public static boolean convert( byte[] objectData, ImageData imageData, GenericColorSpace decodeColorData, PdfObject newSMask, PdfObjectReader currentPdfFile) throws PdfException { newSMask.setFloatArray(PdfDictionary.Decode, new float[] {1, 0}); final PdfArrayIterator Filters = newSMask.getMixedArray(PdfDictionary.Filter); boolean isMaskJPX = false; // check not handled elsewhere int firstValue; if (Filters != null && Filters.hasMoreTokens()) { while (Filters.hasMoreTokens()) { firstValue = Filters.getNextValueAsConstant(true); // isDCT=firstValue==PdfFilteredReader.DCTDecode; isMaskJPX = firstValue == PdfFilteredReader.JPXDecode; } } byte[] objData = currentPdfFile.readStream(newSMask, true, true, false, false, false, null); imageData.setObjectData(objData); imageData.setDepth(1); imageData.setWidth(newSMask.getInt(PdfDictionary.Width)); imageData.setHeight(newSMask.getInt(PdfDictionary.Height)); int newDepth = newSMask.getInt(PdfDictionary.BitsPerComponent); // JPEG2000 causes us special difficulties as we not actually decoding objectData because // it is JPEG2000 and we decode as part of image handling because Java does byte[] to image // directly // // This code fixes specific example by getting the actual data and ignoring empty mask but will // probably need developing further if we find other examples if (isMaskJPX) { // see case 17665 for example BufferedImage img = decodeColorData.JPEG2000ToRGBImage( imageData.getObjectData(), imageData.getWidth(), imageData.getHeight(), null, -1, -1, 8); img = ColorSpaceConvertor.convertColorspace(img, 10); objData = ((DataBufferByte) img.getRaster().getDataBuffer()).getData(); imageData.setObjectData(objData); boolean isEmptyMask = true; for (final byte b : objectData) { if (b != 0) { isEmptyMask = false; break; } } if (isEmptyMask) { imageData.setObjectData(null); } // we need to unset this as e have handled the JPX filter newSMask.setMixedArray(PdfDictionary.Filter, null); } if (newDepth != PdfDictionary.Unknown) { imageData.setDepth(newDepth); } return objData == null; }
static GenericColorSpace downSample( ImageData imageData, GenericColorSpace decodeColorData, int sampling, byte[] index) { final boolean hasIndex = decodeColorData.getIndexedMap() != null && (decodeColorData.getID() == ColorSpaces.DeviceRGB || decodeColorData.getID() == ColorSpaces.CalRGB || decodeColorData.getID() == ColorSpaces.DeviceCMYK || decodeColorData.getID() == ColorSpaces.ICC || decodeColorData.getID() == ColorSpaces.DeviceN); int comp; int indexCount = 1; if (hasIndex) { // convert to sRGB comp = 1; imageData.setCompCount(3); indexCount = 3; index = decodeColorData.convertIndexToRGB(index); // actually sRGB now so reset colorspace decodeColorData = new DeviceRGBColorSpace(); } else { comp = decodeColorData.getColorComponentCount(); } int newW = imageData.getWidth() / sampling; int newH = imageData.getHeight() / sampling; byte[] data = imageData.getObjectData(); final int oldSize = data.length; int x, y, xx, yy, jj; int origLineLength; // black and white if (imageData.getWidth() * imageData.getHeight() == oldSize || decodeColorData.getID() == ColorSpaces.DeviceGray) { comp = 1; } final byte[] newData; if (hasIndex) { // hard-coded to 3 values newData = new byte[newW * newH * indexCount]; origLineLength = imageData.getWidth(); } else { newData = new byte[newW * newH * comp]; origLineLength = imageData.getWidth() * comp; } // scan all pixels and down-sample for (y = 0; y < newH; y++) { for (x = 0; x < newW; x++) { // allow for edges in number of pixels left int wCount = sampling, hCount = sampling; final int wGapLeft = imageData.getWidth() - x; final int hGapLeft = imageData.getHeight() - y; if (wCount > wGapLeft) { wCount = wGapLeft; } if (hCount > hGapLeft) { hCount = hGapLeft; } int[] indexAv; for (jj = 0; jj < comp; jj++) { int byteTotal = 0; int count = 0; int ptr; final int newPtr; //noinspection ObjectAllocationInLoop indexAv = new int[indexCount]; // count pixels in sample we will make into a pixel (ie 2x2 is 4 pixels , 4x4 is 16 // pixels) for (yy = 0; yy < hCount; yy++) { for (xx = 0; xx < wCount; xx++) { ptr = ((yy + (y * sampling)) * origLineLength) + (((x * sampling * comp) + (xx * comp) + jj)); if (ptr < oldSize) { if (!hasIndex) { byteTotal += (data[ptr] & 255); } else { for (int aa = 0; aa < indexCount; aa++) { indexAv[aa] += (index[(((data[ptr] & 255) * indexCount) + aa)] & 255); } } count++; } } } // set value as white or average of pixels if (hasIndex) { newPtr = jj + (x * indexCount) + (newW * y * indexCount); for (int aa = 0; aa < indexCount; aa++) { newData[newPtr + aa] = (byte) ((indexAv[aa]) / count); } } else if (count > 0) { newPtr = jj + (x * comp) + (newW * y * comp); newData[newPtr] = (byte) ((byteTotal) / count); } } } } imageData.setObjectData(newData); imageData.setWidth(newW); imageData.setHeight(newH); return decodeColorData; }