diff --git a/PdfView/build.gradle b/PdfView/build.gradle index 5083f1d..dde31a8 100644 --- a/PdfView/build.gradle +++ b/PdfView/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 21 - buildToolsVersion "23.0.2" + compileSdkVersion 25 + buildToolsVersion "25.0.0" defaultConfig { minSdkVersion 14 @@ -17,7 +17,7 @@ android { } dependencies { - provided 'com.android.support:appcompat-v7:24.2.1' + provided 'com.android.support:appcompat-v7:25.0.0' compile('com.github.chrisbanes:PhotoView:1.3.0') { exclude group: 'com.android.support', module: 'support-v4' } diff --git a/PdfView/src/main/java/com/sun/pdfview/PDFImage.java b/PdfView/src/main/java/com/sun/pdfview/PDFImage.java index a7c0db8..007796b 100644 --- a/PdfView/src/main/java/com/sun/pdfview/PDFImage.java +++ b/PdfView/src/main/java/com/sun/pdfview/PDFImage.java @@ -20,694 +20,691 @@ */ package com.sun.pdfview; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.Log; -import com.sun.pdfview.colorspace.PDFColorSpace; -import com.sun.pdfview.function.FunctionType0; +import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import com.sun.pdfview.colorspace.PDFColorSpace; +import com.sun.pdfview.function.FunctionType0; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Bitmap.Config; +import android.util.Log; + + + /** * Encapsulates a PDF Image */ public class PDFImage { - private static final String TAG = "AWTPDF.pdfimage"; + private static final String TAG = "AWTPDF.pdfimage"; - public static boolean sShowImages; + public static boolean sShowImages; - public static void dump(PDFObject obj) throws IOException { - p("dumping PDF object: " + obj); - if (obj == null) { - return; - } - HashMap dict = obj.getDictionary(); - p(" dict = " + dict); - for (Object key : dict.keySet()) { - p("key = " + key + " value = " + dict.get(key)); - } - } - - public static void p(String string) { - System.out.println(string); - } - - /** - * color key mask. Array of start/end pairs of ranges of color components to - * mask out. If a component falls within any of the ranges it is clear. - */ - private int[] colorKeyMask = null; - /** the width of this image in pixels */ - private int width; - /** the height of this image in pixels */ - private int height; - /** the colorspace to interpret the samples in */ - private PDFColorSpace colorSpace; - /** the number of bits per sample component */ - private int bpc; - /** whether this image is a mask or not */ - private boolean imageMask = false; - /** the SMask image, if any */ - private PDFImage sMask; - /** the decode array */ - private float[] decode; - /** the actual image data */ - private PDFObject imageObj; - - /** - * Create an instance of a PDFImage - */ - protected PDFImage(PDFObject imageObj) { - this.imageObj = imageObj; - } - - /** - * Read a PDFImage from an image dictionary and stream - * - * @param obj the PDFObject containing the image's dictionary and stream - * @param resources the current resources - */ - public static PDFImage createImage(PDFObject obj, Map resources) throws IOException { - // create the image - PDFImage image = new PDFImage(obj); - - // get the width (required) - PDFObject widthObj = obj.getDictRef("Width"); - if (widthObj == null) { - throw new PDFParseException("Unable to read image width: " + obj); - } - image.setWidth(widthObj.getIntValue()); - - // get the height (required) - PDFObject heightObj = obj.getDictRef("Height"); - if (heightObj == null) { - throw new PDFParseException("Unable to get image height: " + obj); - } - image.setHeight(heightObj.getIntValue()); - - // figure out if we are an image mask (optional) - PDFObject imageMaskObj = obj.getDictRef("ImageMask"); - if (imageMaskObj != null) { - image.setImageMask(imageMaskObj.getBooleanValue()); - } - - // read the bpc and colorspace (required except for masks) - if (image.isImageMask()) { - image.setBitsPerComponent(1); - - // create the indexed color space for the mask - // [PATCHED by michal.busta@gmail.com] - default value od Decode according to PDF spec. is [0, 1] - // so the color arry should be: - int[] colors = { Color.BLACK, Color.WHITE }; - - PDFObject imageMaskDecode = obj.getDictRef("Decode"); - if (imageMaskDecode != null) { - PDFObject[] array = imageMaskDecode.getArray(); - float decode0 = array[0].getFloatValue(); - if (decode0 == 1.0f) { - colors = new int[] { Color.WHITE, Color.BLACK }; + public static void dump(PDFObject obj) throws IOException { + p("dumping PDF object: " + obj); + if (obj == null) { + return; } - } - // TODO [FHe]: support for indexed colorspace - image.setColorSpace(PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY)); - //image.setColorSpace(new IndexedColor(colors)); - } else { - // get the bits per component (required) - PDFObject bpcObj = obj.getDictRef("BitsPerComponent"); - if (bpcObj == null) { - throw new PDFParseException("Unable to get bits per component: " + obj); - } - image.setBitsPerComponent(bpcObj.getIntValue()); - - // get the color space (required) - PDFObject csObj = obj.getDictRef("ColorSpace"); - if (csObj == null) { - throw new PDFParseException("No ColorSpace for image: " + obj); - } - - PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); - image.setColorSpace(cs); - } - - // read the decode array - PDFObject decodeObj = obj.getDictRef("Decode"); - if (decodeObj != null) { - PDFObject[] decodeArray = decodeObj.getArray(); - - float[] decode = new float[decodeArray.length]; - for (int i = 0; i < decodeArray.length; i++) { - decode[i] = decodeArray[i].getFloatValue(); - } - - image.setDecode(decode); - } - - // read the soft mask. - // If ImageMask is true, this entry must not be present. - // (See implementation note 52 in Appendix H.) - if (imageMaskObj == null) { - PDFObject sMaskObj = obj.getDictRef("SMask"); - if (sMaskObj == null) { - // try the explicit mask, if there is no SoftMask - sMaskObj = obj.getDictRef("Mask"); - } - - if (sMaskObj != null) { - if (sMaskObj.getType() == PDFObject.STREAM) { - try { - PDFImage sMaskImage = PDFImage.createImage(sMaskObj, resources); - image.setSMask(sMaskImage); - } catch (IOException ex) { - p("ERROR: there was a problem parsing the mask for this object"); - dump(obj); - ex.printStackTrace(System.out); - } - } else if (sMaskObj.getType() == PDFObject.ARRAY) { - // retrieve the range of the ColorKeyMask - // colors outside this range will not be painted. - try { - image.setColorKeyMask(sMaskObj); - } catch (IOException ex) { - p("ERROR: there was a problem parsing the color mask for this object"); - dump(obj); - ex.printStackTrace(System.out); - } + HashMap dict = obj.getDictionary(); + p(" dict = " + dict); + for (Object key : dict.keySet()) { + p("key = " + key + " value = " + dict.get(key)); } - } } - return image; - } - - /** - * Get the image that this PDFImage generates. - * - * @return a buffered image containing the decoded image data - */ - public Bitmap getImage() { - try { - Bitmap bi = (Bitmap) imageObj.getCache(); - - if (bi == null) { - if (!sShowImages) throw new UnsupportedOperationException("do not show images"); - byte[] imgBytes = imageObj.getStream(); - bi = parseData(imgBytes); - // TODO [FHe]: is the cache useful on Android? - imageObj.setCache(bi); - } - // if(bi != null) - // ImageIO.write(bi, "png", new File("/tmp/test/" + System.identityHashCode(this) + ".png")); - return bi; - } catch (IOException ioe) { - System.out.println("Error reading image"); - ioe.printStackTrace(); - return null; - } catch (OutOfMemoryError e) { - // fix for too large images - Log.e(TAG, "image too large (OutOfMemoryError)"); - int size = 15; - int max = size - 1; - int half = size / 2 - 1; - Bitmap bi = Bitmap.createBitmap(size, size, Config.RGB_565); - Canvas c = new Canvas(bi); - c.drawColor(Color.RED); - Paint p = new Paint(); - p.setColor(Color.WHITE); - c.drawLine(0, 0, max, max, p); - c.drawLine(0, max, max, 0, p); - c.drawLine(half, 0, half, max, p); - c.drawLine(0, half, max, half, p); - return bi; + public static void p(String string) { + System.out.println(string); } - } + /** color key mask. Array of start/end pairs of ranges of color components to + * mask out. If a component falls within any of the ranges it is clear. */ + private int[] colorKeyMask = null; + /** the width of this image in pixels */ + private int width; + /** the height of this image in pixels */ + private int height; + /** the colorspace to interpret the samples in */ + private PDFColorSpace colorSpace; + /** the number of bits per sample component */ + private int bpc; + /** whether this image is a mask or not */ + private boolean imageMask = false; + /** the SMask image, if any */ + private PDFImage sMask; + /** the decode array */ + private float[] decode; + /** the actual image data */ + private PDFObject imageObj; - private Bitmap parseData(byte[] imgBytes) { - Bitmap bi; - long startTime = System.currentTimeMillis(); - // parse the stream data into an actual image - Log.i(TAG, "Creating Image width=" - + getWidth() - + ", Height=" - + getHeight() - + ", bpc=" - + getBitsPerComponent() - + ",cs=" - + colorSpace); - if (colorSpace == null) { - throw new UnsupportedOperationException("image without colorspace"); - } else if (colorSpace.getType() == PDFColorSpace.COLORSPACE_RGB) { - int maxH = getHeight(); - int maxW = getWidth(); - if (imgBytes.length == 2 * maxW * maxH) { - // decoded JPEG as RGB565 - bi = Bitmap.createBitmap(maxW, maxH, Config.RGB_565); - bi.copyPixelsFromBuffer(ByteBuffer.wrap(imgBytes)); - } else if (imgBytes.length == 4 * maxW * maxH) { - // create RGB image - bi = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); - bi.copyPixelsFromBuffer(ByteBuffer.wrap(imgBytes)); + /** + * Create an instance of a PDFImage + */ + protected PDFImage(PDFObject imageObj) { + this.imageObj = imageObj; + } - } else { - bi = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); - int[] line = new int[maxW]; - int n = 0; - for (int h = 0; h < maxH; h++) { - for (int w = 0; w < getWidth(); w++) { - line[w] = ((0xff & (int) imgBytes[n]) << 8 | (0xff & (int) imgBytes[n + 1])) << 8 - | (0xff & (int) imgBytes[n + 2]) - | 0xFF000000; - // line[w] = Color.rgb(0xff&(int)imgBytes[n], 0xff&(int)imgBytes[n+1],0xff&(int)imgBytes[n+2]); - if (-line[w] == 0xFFFFFF + 1) { - line[w] = 0xFFFFFFFF; + /** + * Read a PDFImage from an image dictionary and stream + * + * @param obj the PDFObject containing the image's dictionary and stream + * @param resources the current resources + */ + public static PDFImage createImage(PDFObject obj, Map resources) + throws IOException { + // create the image + PDFImage image = new PDFImage(obj); + + // get the width (required) + PDFObject widthObj = obj.getDictRef("Width"); + if (widthObj == null) { + throw new PDFParseException("Unable to read image width: " + obj); + } + image.setWidth(widthObj.getIntValue()); + + // get the height (required) + PDFObject heightObj = obj.getDictRef("Height"); + if (heightObj == null) { + throw new PDFParseException("Unable to get image height: " + obj); + } + image.setHeight(heightObj.getIntValue()); + + // figure out if we are an image mask (optional) + PDFObject imageMaskObj = obj.getDictRef("ImageMask"); + if (imageMaskObj != null) { + image.setImageMask(imageMaskObj.getBooleanValue()); + } + + // read the bpc and colorspace (required except for masks) + if (image.isImageMask()) { + image.setBitsPerComponent(1); + + // create the indexed color space for the mask + // [PATCHED by michal.busta@gmail.com] - default value od Decode according to PDF spec. is [0, 1] + // so the color arry should be: + int[] colors = {Color.BLACK, Color.WHITE}; + + PDFObject imageMaskDecode = obj.getDictRef("Decode"); + if (imageMaskDecode != null) { + PDFObject[] array = imageMaskDecode.getArray(); + float decode0 = array[0].getFloatValue(); + if (decode0 == 1.0f) { + colors = new int[]{Color.WHITE, Color.BLACK}; + } } - n += 3; - } - bi.setPixels(line, 0, maxW, 0, h, maxW, 1); + // TODO [FHe]: support for indexed colorspace + image.setColorSpace(PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY)); +// image.setColorSpace(new IndexedColor(colors)); + } else { + // get the bits per component (required) + PDFObject bpcObj = obj.getDictRef("BitsPerComponent"); + if (bpcObj == null) { + throw new PDFParseException("Unable to get bits per component: " + obj); + } + image.setBitsPerComponent(bpcObj.getIntValue()); + + // get the color space (required) + PDFObject csObj = obj.getDictRef("ColorSpace"); + if (csObj == null) { + throw new PDFParseException("No ColorSpace for image: " + obj); + } + + PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); + image.setColorSpace(cs); } - } - } else if (colorSpace.getType() == PDFColorSpace.COLORSPACE_GRAY) { - // create gray image - bi = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); - int maxH = getHeight(); - int maxW = getWidth(); - int[] line = new int[maxW]; - int n = 0; - for (int h = 0; h < maxH; h++) { - for (int w = 0; w < getWidth(); w++) { - int gray = 0xff & (int) imgBytes[n]; - line[w] = (gray << 8 | gray) << 8 | gray | 0xFF000000; - n += 1; + + // read the decode array + PDFObject decodeObj = obj.getDictRef("Decode"); + if (decodeObj != null) { + PDFObject[] decodeArray = decodeObj.getArray(); + + float[] decode = new float[decodeArray.length]; + for (int i = 0; i < decodeArray.length; i++) { + decode[i] = decodeArray[i].getFloatValue(); + } + + image.setDecode(decode); } - bi.setPixels(line, 0, maxW, 0, h, maxW, 1); - } - } else if (colorSpace.getType() == PDFColorSpace.COLORSPACE_INDEXED) { - // create indexed image - bi = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); - int maxH = getHeight(); - int maxW = getWidth(); - int[] line = new int[maxW]; - int[] comps = new int[1]; - int n = 0; - for (int h = 0; h < maxH; h++) { - for (int w = 0; w < getWidth(); w++) { - comps[0] = imgBytes[n] & 0xff; - line[w] = colorSpace.toColor(comps); - n += 1; + + // read the soft mask. + // If ImageMask is true, this entry must not be present. + // (See implementation note 52 in Appendix H.) + if (imageMaskObj == null) { + PDFObject sMaskObj = obj.getDictRef("SMask"); + if (sMaskObj == null) { + // try the explicit mask, if there is no SoftMask + sMaskObj = obj.getDictRef("Mask"); + } + + if (sMaskObj != null) { + if (sMaskObj.getType() == PDFObject.STREAM) { + try { + PDFImage sMaskImage = PDFImage.createImage(sMaskObj, resources); + image.setSMask(sMaskImage); + } catch (IOException ex) { + p("ERROR: there was a problem parsing the mask for this object"); + dump(obj); + ex.printStackTrace(System.out); + } + } else if (sMaskObj.getType() == PDFObject.ARRAY) { + // retrieve the range of the ColorKeyMask + // colors outside this range will not be painted. + try { + image.setColorKeyMask(sMaskObj); + } catch (IOException ex) { + p("ERROR: there was a problem parsing the color mask for this object"); + dump(obj); + ex.printStackTrace(System.out); + } + } + } } - bi.setPixels(line, 0, maxW, 0, h, maxW, 1); - } - } else { - throw new UnsupportedOperationException("image with unsupported colorspace " + colorSpace); - } - long stopTime = System.currentTimeMillis(); - Log.i(TAG, "millis for converting image=" + (stopTime - startTime)); - return bi; - } - // /** - // *
Parse the image stream into a buffered image. Note that this is - // * guaranteed to be called after all the other setXXX methods have been - // * called.
- // * - // *NOTE: the color convolving is extremely slow on large images. - // * It would be good to see if it could be moved out into the rendering - // * phases, where we might be able to scale the image down first.
data.length) { - // byte[] tempLargerData = new byte[tempExpectedSize]; - // System.arraycopy (data, 0, tempLargerData, 0, data.length); - // db = new DataBufferByte (tempLargerData, tempExpectedSize); - // raster = - // Raster.createWritableRaster (sm, db, new Point (0, 0)); - // } else { - // throw e; - // } - // } - // - // /* - // * Workaround for a bug on the Mac -- a class cast exception in - // * drawImage() due to the wrong data buffer type (?) - // */ - // BufferedImage bi = null; - // if (cm instanceof IndexColorModel) { - // IndexColorModel icm = (IndexColorModel) cm; - // - // // choose the image type based on the size - // int type = BufferedImage.TYPE_BYTE_BINARY; - // if (getBitsPerComponent() == 8) { - // type = BufferedImage.TYPE_BYTE_INDEXED; - // } - // - // // create the image with an explicit indexed color model. - // bi = new BufferedImage(getWidth(), getHeight(), type, icm); - // - // // set the data explicitly as well - // bi.setData(raster); - // } else { - // bi = new BufferedImage(cm, raster, true, null); - // } - // - // // hack to avoid *very* slow conversion - // ColorSpace cs = cm.getColorSpace(); - // ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); - // - // // add in the alpha data supplied by the SMask, if any - // PDFImage sMaskImage = getSMask(); - // if (sMaskImage != null) { - // BufferedImage si = sMaskImage.getImage(); - // - // BufferedImage outImage = new BufferedImage(getWidth(), - // getHeight(), BufferedImage.TYPE_INT_ARGB); - // - // int[] srcArray = new int[width]; - // int[] maskArray = new int[width]; - // - // for (int i = 0; i < height; i++) { - // bi.getRGB(0, i, width, 1, srcArray, 0, width); - // si.getRGB(0, i, width, 1, maskArray, 0, width); - // - // for (int j = 0; j < width; j++) { - // int ac = 0xff000000; - // - // maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); - // } - // - // outImage.setRGB(0, i, width, 1, maskArray, 0, width); - // } - // - // bi = outImage; - // } - // - // return (bi); - // } - - /** - * Get the image's width - */ - public int getWidth() { - return width; - } - - /** - * Set the image's width - */ - protected void setWidth(int width) { - this.width = width; - } - - /** - * Get the image's height - */ - public int getHeight() { - return height; - } - - /** - * Set the image's height - */ - protected void setHeight(int height) { - this.height = height; - } - - /** - * set the color key mask. It is an array of start/end entries - * to indicate ranges of color indicies that should be masked out. - */ - private void setColorKeyMask(PDFObject maskArrayObject) throws IOException { - PDFObject[] maskObjects = maskArrayObject.getArray(); - colorKeyMask = null; - int[] masks = new int[maskObjects.length]; - for (int i = 0; i < masks.length; i++) { - masks[i] = maskObjects[i].getIntValue(); - } - colorKeyMask = masks; - } - - /** - * Get the colorspace associated with this image, or null if there - * isn't one - */ - protected PDFColorSpace getColorSpace() { - return colorSpace; - } - - /** - * Set the colorspace associated with this image - */ - protected void setColorSpace(PDFColorSpace colorSpace) { - this.colorSpace = colorSpace; - } - - /** - * Get the number of bits per component sample - */ - protected int getBitsPerComponent() { - return bpc; - } - - /** - * Set the number of bits per component sample - */ - protected void setBitsPerComponent(int bpc) { - this.bpc = bpc; - } - - /** - * Return whether or not this is an image mask - */ - public boolean isImageMask() { - return imageMask; - } - - /** - * Set whether or not this is an image mask - */ - public void setImageMask(boolean imageMask) { - this.imageMask = imageMask; - } - - /** - * Return the soft mask associated with this image - */ - public PDFImage getSMask() { - return sMask; - } - - /** - * Set the soft mask image - */ - protected void setSMask(PDFImage sMask) { - this.sMask = sMask; - } - - /** - * Get the decode array - */ - protected float[] getDecode() { - return decode; - } - - /** - * Set the decode array - */ - protected void setDecode(float[] decode) { - this.decode = decode; - } - - // /** - // * get a Java ColorModel consistent with the current color space, - // * number of bits per component and decode array - // * - // * @param bpc the number of bits per component - // */ - // private ColorModel getColorModel() { - // PDFColorSpace cs = getColorSpace(); - // - // if (cs instanceof IndexedColor) { - // IndexedColor ics = (IndexedColor) cs; - // - // byte[] components = ics.getColorComponents(); - // int num = ics.getCount(); - // - // // process the decode array - // if (decode != null) { - // byte[] normComps = new byte[components.length]; - // - // // move the components array around - // for (int i = 0; i < num; i++) { - // byte[] orig = new byte[1]; - // orig[0] = (byte) i; - // - // float[] res = normalize(orig, null, 0); - // int idx = (int) res[0]; - // - // normComps[i * 3] = components[idx * 3]; - // normComps[(i * 3) + 1] = components[(idx * 3) + 1]; - // normComps[(i * 3) + 2] = components[(idx * 3) + 2]; - // } - // - // components = normComps; - // } - // - // // make sure the size of the components array is 2 ^ numBits - // // since if it's not, Java will complain - // int correctCount = 1 << getBitsPerComponent(); - // if (correctCount < num) { - // byte[] fewerComps = new byte[correctCount * 3]; - // - // System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); - // - // components = fewerComps; - // num = correctCount; - // } - // if (colorKeyMask == null || colorKeyMask.length == 0) { - // return new IndexColorModel(getBitsPerComponent(), num, components, - // 0, false); - // } else { - // byte[] aComps = new byte[num * 4]; - // int idx = 0; - // for (int i = 0; i < num; i++) { - // aComps[idx++] = components[(i * 3)]; - // aComps[idx++] = components[(i * 3) + 1]; - // aComps[idx++] = components[(i * 3) + 2]; - // aComps[idx++] = (byte) 0xFF; - // } - // for (int i = 0; i < colorKeyMask.length; i += 2) { - // for (int j = colorKeyMask[i]; j <= colorKeyMask[i + 1]; j++) { - // aComps[(j * 4) + 3] = 0; // make transparent - // } - // } - // return new IndexColorModel(getBitsPerComponent(), num, aComps, - // 0, true); - // } - // } else { - // int[] bits = new int[cs.getNumComponents()]; - // for (int i = 0; i < bits.length; i++) { - // bits[i] = getBitsPerComponent(); - // } - // - // return new DecodeComponentColorModel(cs.getColorSpace(), bits); - // } - // } - - /** - * Normalize an array of values to match the decode array - */ - private float[] normalize(byte[] pixels, float[] normComponents, int normOffset) { - if (normComponents == null) { - normComponents = new float[normOffset + pixels.length]; + return image; } - float[] decodeArray = getDecode(); + /** + * Get the image that this PDFImage generates. + * + * @return a buffered image containing the decoded image data + */ + public Bitmap getImage() { + try { + Bitmap bi = (Bitmap) imageObj.getCache(); - for (int i = 0; i < pixels.length; i++) { - int val = pixels[i] & 0xff; - int pow = ((int) Math.pow(2, getBitsPerComponent())) - 1; - float ymin = decodeArray[i * 2]; - float ymax = decodeArray[(i * 2) + 1]; - - normComponents[normOffset + i] = FunctionType0.interpolate(val, 0, pow, ymin, ymax); + if (bi == null) { + if (!sShowImages) + throw new UnsupportedOperationException("do not show images"); + byte[] imgBytes = imageObj.getStream(); + bi = parseData(imgBytes); + // TODO [FHe]: is the cache useful on Android? + imageObj.setCache(bi); + } +// if(bi != null) +// ImageIO.write(bi, "png", new File("/tmp/test/" + System.identityHashCode(this) + ".png")); + return bi; + } catch (IOException ioe) { + System.out.println("Error reading image"); + ioe.printStackTrace(); + return null; + } catch (OutOfMemoryError e) { + // fix for too large images + Log.e(TAG, "image too large (OutOfMemoryError)"); + int size = 15; + int max = size-1; + int half = size/2-1; + Bitmap bi = Bitmap.createBitmap(size, size, Config.RGB_565); + Canvas c = new Canvas(bi); + c.drawColor(Color.RED); + Paint p = new Paint(); + p.setColor(Color.WHITE); + c.drawLine(0, 0, max, max, p); + c.drawLine(0, max, max, 0, p); + c.drawLine(half, 0, half, max, p); + c.drawLine(0, half, max, half, p); + return bi; + } } - return normComponents; - } + private Bitmap parseData(byte[] imgBytes) { + Bitmap bi; + long startTime = System.currentTimeMillis(); + // parse the stream data into an actual image + Log.i(TAG, "Creating Image width="+getWidth() + ", Height="+getHeight()+", bpc="+getBitsPerComponent()+",cs="+colorSpace); + if (colorSpace == null) { + throw new UnsupportedOperationException("image without colorspace"); + } else if (colorSpace.getType() == PDFColorSpace.COLORSPACE_RGB) { + int maxH = getHeight(); + int maxW = getWidth(); + if (imgBytes.length == 2*maxW*maxH) { + // decoded JPEG as RGB565 + bi = Bitmap.createBitmap(maxW, maxH, Config.RGB_565); + bi.copyPixelsFromBuffer(ByteBuffer.wrap(imgBytes)); + } + else { + // create RGB image + bi = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); + int[] line = new int[maxW]; + int n=0; + for (int h = 0; hParenthesis must be enclosed by a balanced set of parenthesis, * so a string may enclose balanced parenthesis.
* @@ -421,7 +384,7 @@ public class PDFParser extends BaseWatchable { int parenLevel = 0; final StringBuffer sb = new StringBuffer(); - for (int to = stream_.length; loc < to; ) { + for (int to = stream_.length; loc < to;) { int c = stream_[loc++]; if (c == ')') { if (parenLevel-- == 0) { @@ -462,7 +425,7 @@ public class PDFParser extends BaseWatchable { * character, which has already been read, and end with a '>' * character. Each byte in the array is made up of two hex characters, * the first being the high-order bit. - * + * * We translate the byte arrays into char arrays by combining two bytes * into a character, and then translate the character array into a string. * [JK FIXME this is probably a really bad idea!] @@ -477,7 +440,7 @@ public class PDFParser extends BaseWatchable { char w = (char) 0; // read individual bytes and format into a character array - for (int to = stream_.length; (loc < to) && (stream_[loc] != '>'); ) { + for (int to = stream_.length; (loc < to) && (stream_[loc] != '>');) { final char c = (char) stream_[loc]; byte b = (byte) 0; @@ -515,7 +478,6 @@ public class PDFParser extends BaseWatchable { ///////////////////////////////////////////////////////////////// // B E G I N P A R S E R S E C T I O N ///////////////////////////////////////////////////////////////// - /** * Called to prepare for some iterations */ @@ -543,16 +505,16 @@ public class PDFParser extends BaseWatchable { /** * parse the stream. commands are added to the PDFPage initialized * in the constructor as they are encountered. - * + *
* Page numbers in comments refer to the Adobe PDF specification.
* commands are listed in PDF spec 32000-1:2008 in Table A.1
*
* @return