From c54d55d661897212c26488d78f1953f414444d0d Mon Sep 17 00:00:00 2001 From: contrudar Date: Wed, 26 Oct 2016 12:03:11 +0300 Subject: [PATCH 1/2] fix the black pixel issue --- PdfView/build.gradle | 6 +- .../main/java/com/sun/pdfview/PDFImage.java | 1317 ++++++++--------- .../main/java/com/sun/pdfview/PDFParser.java | 166 +-- .../pdfview/colorspace/ICCIColorSpace.java | 60 - .../sun/pdfview/colorspace/PDFColorSpace.java | 309 ++-- .../com/sun/pdfview/decode/DCTDecode.java | 95 +- .../andpdf/pdfviewer/PdfViewerFragment.java | 83 -- .../java/net/sf/andpdf/utils/MathUtils.java | 78 - .../java/net/sf/andpdf/utils/VectorF.java | 63 - 9 files changed, 919 insertions(+), 1258 deletions(-) delete mode 100644 PdfView/src/main/java/com/sun/pdfview/colorspace/ICCIColorSpace.java delete mode 100755 PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java delete mode 100644 PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java 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; h 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. + * + * @param maskArrayObject + */ + 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]; + } + + float[] decodeArray = getDecode(); + + 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); + } + + return normComponents; + } + +// /** +// * A wrapper for ComponentColorSpace which normalizes based on the +// * decode array. +// */ +// class DecodeComponentColorModel extends ComponentColorModel { +// +// public DecodeComponentColorModel(ColorSpace cs, int[] bpc) { +// super(cs, bpc, false, false, Transparency.OPAQUE, +// DataBuffer.TYPE_BYTE); +// +// if (bpc != null) { +// pixel_bits = bpc.length * bpc[0]; +// } +// } +// +// @Override +// public SampleModel createCompatibleSampleModel(int width, int height) { +// // workaround -- create a MultiPixelPackedSample models for +// // single-sample, less than 8bpp color models +// if (getNumComponents() == 1 && getPixelSize() < 8) { +// return new MultiPixelPackedSampleModel(getTransferType(), +// width, +// height, +// getPixelSize()); +// } +// +// return super.createCompatibleSampleModel(width, height); +// } +// +// @Override +// public boolean isCompatibleRaster(Raster raster) { +// if (getNumComponents() == 1 && getPixelSize() < 8) { +// SampleModel sm = raster.getSampleModel(); +// +// if (sm instanceof MultiPixelPackedSampleModel) { +// return (sm.getSampleSize(0) == getPixelSize()); +// } else { +// return false; +// } +// } +// +// return super.isCompatibleRaster(raster); +// } +// +// @Override +// public float[] getNormalizedComponents(Object pixel, +// float[] normComponents, int normOffset) { +// if (getDecode() == null) { +// return super.getNormalizedComponents(pixel, normComponents, +// normOffset); +// } +// +// return normalize((byte[]) pixel, normComponents, normOffset); +// } +// } } diff --git a/PdfView/src/main/java/com/sun/pdfview/PDFParser.java b/PdfView/src/main/java/com/sun/pdfview/PDFParser.java index 397e165..93283bf 100644 --- a/PdfView/src/main/java/com/sun/pdfview/PDFParser.java +++ b/PdfView/src/main/java/com/sun/pdfview/PDFParser.java @@ -54,9 +54,7 @@ import com.sun.pdfview.font.PDFFont; */ public class PDFParser extends BaseWatchable { - /** - * emit a file of DCT stream data. - */ + /** emit a file of DCT stream data. */ public final static String DEBUG_DCTDECODE_DATA = "debugdctdecode"; static final boolean RELEASE = true; static final int PDF_CMDS_RANGE1_MIN = 1; @@ -78,13 +76,11 @@ public class PDFParser extends BaseWatchable { private boolean resend = false; private Tok tok; private boolean catchexceptions; // Indicates state of BX...EX - /** - * a weak reference to the page we render into. For the page + /** a weak reference to the page we render into. For the page * to remain available, some other code must retain a strong reference to it. */ private WeakReference pageRef; - /** - * the actual command, for use within a singe iteration. Note that + /** the actual command, for use within a singe iteration. Note that * this must be released at the end of each iteration to assure the * page can be collected if not in use */ @@ -92,7 +88,7 @@ public class PDFParser extends BaseWatchable { // ---- result variables byte[] stream; HashMap resources; - // public static int debuglevel = 4000; +// public static int debuglevel = 4000; // TODO [FHe]: changed for debugging public static int debuglevel = -1; @@ -125,7 +121,7 @@ public class PDFParser extends BaseWatchable { * on to a PDFParser. */ public PDFParser(PDFPage cmds, byte[] stream, - HashMap resources) { + HashMap resources) { super(); this.pageRef = new WeakReference(cmds); @@ -141,76 +137,43 @@ public class PDFParser extends BaseWatchable { ///////////////////////////////////////////////////////////////// // B E G I N R E A D E R S E C T I O N ///////////////////////////////////////////////////////////////// - /** * a token from a PDF Stream */ static class Tok { - /** - * begin bracket < - */ + /** begin bracket < */ public static final int BRKB = 11; - /** - * end bracket > - */ + /** end bracket > */ public static final int BRKE = 10; - /** - * begin array [ - */ + /** begin array [ */ public static final int ARYB = 9; - /** - * end array ] - */ + /** end array ] */ public static final int ARYE = 8; - /** - * String (, readString looks for trailing ) - */ + /** String (, readString looks for trailing ) */ public static final int STR = 7; - /** - * begin brace { - */ + /** begin brace { */ public static final int BRCB = 5; - /** - * end brace } - */ + /** end brace } */ public static final int BRCE = 4; - /** - * number - */ + /** number */ public static final int NUM = 3; - /** - * keyword - */ + /** keyword */ public static final int CMD = 2; - /** - * name (begins with /) - */ + /** name (begins with /) */ public static final int NAME = 1; - /** - * unknown token - */ + /** unknown token */ public static final int UNK = 0; - /** - * end of stream - */ + /** end of stream */ public static final int EOF = -1; - /** - * the string value of a STR, NAME, or CMD token - */ + /** the string value of a STR, NAME, or CMD token */ public String name; - /** - * the value of a NUM token - */ + /** the value of a NUM token */ public double value; - /** - * the type of the token - */ + /** the type of the token */ public int type; - /** - * a printable representation of the token - */ + /** a printable representation of the token */ @Override public String toString() { if (type == NUM) { @@ -409,7 +372,7 @@ public class PDFParser extends BaseWatchable { * character, which has already been read, and end with a balanced ')' * character. A '\' character starts an escape sequence of up * to three octal digits.

- *

+ * *

Parenthesis 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

  • Watchable.RUNNING when there are commands to be processed - *
  • Watchable.COMPLETED when the page is done and all - * the commands have been processed - *
  • Watchable.STOPPED if the page we are rendering into is - * no longer available - *
+ *
  • Watchable.COMPLETED when the page is done and all + * the commands have been processed + *
  • Watchable.STOPPED if the page we are rendering into is + * no longer available + * */ public int iterate() throws Exception { // make sure the page is still available, and create the reference @@ -700,7 +662,7 @@ public class PDFParser extends BaseWatchable { path = new Path(); break; case 'f': - // the fall-through is intended! + // the fall-through is intended! case 'F': // fill the path (close/not close identical) cmds.addPath(path, PDFShapeCmd.FILL | clip); @@ -990,11 +952,11 @@ public class PDFParser extends BaseWatchable { break; case 'Q' + ('q' << 8): processQCmd(); - // 'q'-cmd - // push the parser state - parserStates.push((ParserState) state.clone()); - // push graphics state - cmds.addPush(); + // 'q'-cmd + // push the parser state + parserStates.push((ParserState) state.clone()); + // push graphics state + cmds.addPush(); break; default: if (catchexceptions) { @@ -1063,7 +1025,6 @@ public class PDFParser extends BaseWatchable { path = null; cmds = null; } - boolean errorwritten = false; public void dumpStreamToError() { @@ -1107,12 +1068,10 @@ public class PDFParser extends BaseWatchable { ///////////////////////////////////////////////////////////////// // H E L P E R S ///////////////////////////////////////////////////////////////// - /** * get a property from a named dictionary in the resources of this * content stream. - * - * @param name the name of the property in the dictionary + * @param name the name of the property in the dictionary * @param inDict the name of the dictionary in the resources * @return the value of the property in the dictionary */ @@ -1133,7 +1092,6 @@ public class PDFParser extends BaseWatchable { * Insert a PDF object into the command stream. The object must * either be an Image or a Form, which is a set of PDF commands * in a stream. - * * @param obj the object to insert, an Image or a Form. */ private void doXObject(PDFObject obj) throws IOException { @@ -1153,9 +1111,8 @@ public class PDFParser extends BaseWatchable { /** * Parse image data into a Java BufferedImage and add the image * command to the page. - * * @param obj contains the image data, and a dictionary describing - * the width, height and color space of the image. + * the width, height and color space of the image. */ private void doImage(PDFObject obj) throws IOException { cmds.addImage(PDFImage.createImage(obj, resources)); @@ -1165,9 +1122,8 @@ public class PDFParser extends BaseWatchable { * Inject a stream of PDF commands onto the page. Optimized to cache * a parsed stream of commands, so that each Form object only needs * to be parsed once. - * * @param obj a stream containing the PDF commands, a transformation - * matrix, bounding box, and resources. + * matrix, bounding box, and resources. */ private void doForm(PDFObject obj) throws IOException { // check to see if we've already parsed this sucker @@ -1230,7 +1186,6 @@ public class PDFParser extends BaseWatchable { // // return patternSpace.getPaint(pattern, components, resources); // } - /** * Parse the next object out of the PDF stream. This could be a * Double, a String, a HashMap (dictionary), Object[] array, or @@ -1243,13 +1198,13 @@ public class PDFParser extends BaseWatchable { case Tok.NUM: return new Double(tok.value); case Tok.STR: - // the fall-through is intended! + // the fall-through is intended! case Tok.NAME: return tok.name; case Tok.BRKB: { final HashMap hm = new HashMap(); String name = null; - for (Object obj = null; (obj = parseObject()) != null; ) { + for (Object obj = null; (obj = parseObject()) != null;) { if (name == null) { name = (String) obj; } else { @@ -1265,7 +1220,7 @@ public class PDFParser extends BaseWatchable { case Tok.ARYB: { // build an array final ArrayList ary = new ArrayList(); - for (Object obj = null; (obj = parseObject()) != null; ) { + for (Object obj = null; (obj = parseObject()) != null;) { ary.add(obj); } if (tok.type != Tok.ARYE) { @@ -1396,7 +1351,6 @@ public class PDFParser extends BaseWatchable { /** * add graphics state commands contained within a dictionary. - * * @param name the resource name of the graphics state dictionary */ private void setGSState(String name) throws IOException { @@ -1454,15 +1408,11 @@ public class PDFParser extends BaseWatchable { /** * pop a single float value off the stack. - * * @return the float value of the top of the stack * @throws PDFParseException if the value on the top of the stack - * isn't a number + * isn't a number */ private float popFloat() throws PDFParseException { - if (stack.isEmpty()) { - return 0; - } Object obj = stack.pop(); if (obj instanceof Double) { return ((Double) obj).floatValue(); @@ -1475,11 +1425,10 @@ public class PDFParser extends BaseWatchable { * pop an array of float values off the stack. This is equivalent * to filling an array from end to front by popping values off the * stack. - * * @param count the number of numbers to pop off the stack * @return an array of length count * @throws PDFParseException if any of the values popped off the - * stack are not numbers. + * stack are not numbers. */ private float[] popFloat(int count) throws PDFParseException { float[] ary = new float[count]; @@ -1491,7 +1440,6 @@ public class PDFParser extends BaseWatchable { /** * pop a single integer value off the stack. - * * @return the integer value of the top of the stack * @throws PDFParseException if the top of the stack isn't a number. */ @@ -1508,11 +1456,10 @@ public class PDFParser extends BaseWatchable { * pop an array of integer values off the stack. This is equivalent * to filling an array from end to front by popping values off the * stack. - * * @param count the number of numbers to pop off the stack * @return an array of length count * @throws PDFParseException if any of the values popped off the - * stack are not numbers. + * stack are not numbers. */ private float[] popFloatArray() throws PDFParseException { Object obj = stack.pop(); @@ -1533,10 +1480,9 @@ public class PDFParser extends BaseWatchable { /** * pop a String off the stack. - * * @return the String from the top of the stack * @throws PDFParseException if the top of the stack is not a NAME - * or STR. + * or STR. */ private String popString() throws PDFParseException { Object obj = stack.pop(); @@ -1549,10 +1495,9 @@ public class PDFParser extends BaseWatchable { /** * pop a PDFObject off the stack. - * * @return the PDFObject from the top of the stack * @throws PDFParseException if the top of the stack does not contain - * a PDFObject. + * a PDFObject. */ private PDFObject popObject() throws PDFParseException { Object obj = stack.pop(); @@ -1564,10 +1509,9 @@ public class PDFParser extends BaseWatchable { /** * pop an array off the stack - * * @return the array of objects that is the top element of the stack * @throws PDFParseException if the top element of the stack does not - * contain an array. + * contain an array. */ private Object[] popArray() throws PDFParseException { Object obj = stack.pop(); @@ -1584,17 +1528,11 @@ public class PDFParser extends BaseWatchable { */ class ParserState implements Cloneable { - /** - * the fill color space - */ + /** the fill color space */ PDFColorSpace fillCS; - /** - * the stroke color space - */ + /** the stroke color space */ PDFColorSpace strokeCS; - /** - * the text paramters - */ + /** the text paramters */ PDFTextFormat textFormat; /** diff --git a/PdfView/src/main/java/com/sun/pdfview/colorspace/ICCIColorSpace.java b/PdfView/src/main/java/com/sun/pdfview/colorspace/ICCIColorSpace.java deleted file mode 100644 index b97ce52..0000000 --- a/PdfView/src/main/java/com/sun/pdfview/colorspace/ICCIColorSpace.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * $Id: CalRGBColor.java,v 1.2 2007/12/20 18:33:34 rbair Exp $ - * - * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, - * Santa Clara, California 95054, U.S.A. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package com.sun.pdfview.colorspace; - -import android.graphics.Color; - -public class ICCIColorSpace extends PDFColorSpace { - - public ICCIColorSpace() { - } - - /** - * get the number of components (3) - */ - @Override public int getNumComponents() { - return 3; - } - - @Override public int toColor(float[] fcomp) { - return Color.rgb((int)(fcomp[0]*255),(int)(fcomp[1]*255),(int)(fcomp[2]*255)); - } - - @Override public int toColor(int[] icomp) { - return Color.rgb(icomp[0],icomp[1],icomp[2]); - } - - - /** - * get the type of this color space (TYPE_RGB) - */ - @Override public int getType() { - return COLORSPACE_GRAY; - } - - @Override - public String getName() { - return "RGB"; - } - - -} diff --git a/PdfView/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java b/PdfView/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java index 8a7df61..2151f49 100644 --- a/PdfView/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java +++ b/PdfView/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java @@ -28,186 +28,187 @@ import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.function.PDFFunction; + /** * A color space that can convert a set of color components into * PDFPaint. - * * @author Mike Wessler */ public abstract class PDFColorSpace { + + /** the name of the device-dependent gray color space */ + public static final int COLORSPACE_GRAY = 0; - /** the name of the device-dependent gray color space */ - public static final int COLORSPACE_GRAY = 0; + /** the name of the device-dependent RGB color space */ + public static final int COLORSPACE_RGB = 1; - /** the name of the device-dependent RGB color space */ - public static final int COLORSPACE_RGB = 1; + /** the name of the device-dependent CMYK color space */ + public static final int COLORSPACE_CMYK = 2; - /** the name of the device-dependent CMYK color space */ - public static final int COLORSPACE_CMYK = 2; + /** the name of the pattern color space */ + public static final int COLORSPACE_PATTERN = 3; - /** the name of the pattern color space */ - public static final int COLORSPACE_PATTERN = 3; + public static final int COLORSPACE_INDEXED = 4; - public static final int COLORSPACE_INDEXED = 4; + public static final int COLORSPACE_ALTERNATE = 5; - public static final int COLORSPACE_ALTERNATE = 5; + /** the device-dependent color spaces */ + // private static PDFColorSpace graySpace = + // new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY)); + private static PDFColorSpace rgbSpace = new RGBColorSpace(); + private static PDFColorSpace cmykSpace = new CMYKColorSpace(); - /** the device-dependent color spaces */ - // private static PDFColorSpace graySpace = - // new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY)); - private static PDFColorSpace rgbSpace = new RGBColorSpace(); - private static PDFColorSpace cmykSpace = new CMYKColorSpace(); - private static PDFColorSpace icciSpace = new ICCIColorSpace(); - /** the pattern space */ - private static PDFColorSpace patternSpace = new RGBColorSpace(); // TODO [FHe] + /** the pattern space */ + private static PDFColorSpace patternSpace = new RGBColorSpace(); // TODO [FHe] - /** graySpace and the gamma correction for it. */ - private static PDFColorSpace graySpace = new GrayColorSpace(); + /** graySpace and the gamma correction for it. */ + private static PDFColorSpace graySpace = new GrayColorSpace(); - /** - * create a PDFColorSpace based on a Java ColorSpace - * - * @param cs the Java ColorSpace - */ - protected PDFColorSpace() { - } - /** - * Get a color space by name - * - * @param name the name of one of the device-dependent color spaces - */ - public static PDFColorSpace getColorSpace(int name) { - switch (name) { - case COLORSPACE_GRAY: - return graySpace; - - case COLORSPACE_RGB: - return rgbSpace; - - case COLORSPACE_CMYK: - return cmykSpace; - - case COLORSPACE_PATTERN: - return patternSpace; - - default: - throw new IllegalArgumentException("Unknown Color Space name: " + name); - } - } - - /** - * Get a color space specified in a PDFObject - * - * @param csobj the PDFObject with the colorspace information - */ - public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) throws IOException { - String name; - - PDFObject colorSpaces = null; - - if (resources != null) { - colorSpaces = (PDFObject) resources.get("ColorSpace"); + /** + * create a PDFColorSpace based on a Java ColorSpace + * @param cs the Java ColorSpace + */ + protected PDFColorSpace() { } - if (csobj.getType() == PDFObject.NAME) { - name = csobj.getStringValue(); + /** + * Get a color space by name + * + * @param name the name of one of the device-dependent color spaces + */ + public static PDFColorSpace getColorSpace(int name) { + switch (name) { + case COLORSPACE_GRAY: + return graySpace; - if (name.equals("DeviceGray") || name.equals("G")) { - return getColorSpace(COLORSPACE_GRAY); - } else if (name.equals("DeviceRGB") || name.equals("RGB")) { - return getColorSpace(COLORSPACE_RGB); - } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) { - return getColorSpace(COLORSPACE_CMYK); - } else if (name.equals("Pattern")) { - return getColorSpace(COLORSPACE_PATTERN); - } else if (colorSpaces != null) { - csobj = (PDFObject) colorSpaces.getDictRef(name); - } + case COLORSPACE_RGB: + return rgbSpace; + + case COLORSPACE_CMYK: + return cmykSpace; + + case COLORSPACE_PATTERN: + return patternSpace; + + default: + throw new IllegalArgumentException("Unknown Color Space name: " + + name); + } } - if (csobj == null) { - return null; - } else if (csobj.getCache() != null) { - return (PDFColorSpace) csobj.getCache(); + /** + * Get a color space specified in a PDFObject + * + * @param csobj the PDFObject with the colorspace information + */ + public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) + throws IOException { + String name; + + PDFObject colorSpaces = null; + + if (resources != null) { + colorSpaces = (PDFObject) resources.get("ColorSpace"); + } + + if (csobj.getType() == PDFObject.NAME) { + name = csobj.getStringValue(); + + if (name.equals("DeviceGray") || name.equals("G")) { + return getColorSpace(COLORSPACE_GRAY); + } else if (name.equals("DeviceRGB") || name.equals("RGB")) { + return getColorSpace(COLORSPACE_RGB); + } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) { + return getColorSpace(COLORSPACE_CMYK); + } else if (name.equals("Pattern")) { + return getColorSpace(COLORSPACE_PATTERN); + } else if (colorSpaces != null) { + csobj = (PDFObject) colorSpaces.getDictRef(name); + } + } + + if (csobj == null) { + return null; + } else if (csobj.getCache() != null) { + return (PDFColorSpace) csobj.getCache(); + } + + PDFColorSpace value = null; + + // csobj is [/name <>] + PDFObject[] ary = csobj.getArray(); + name = ary[0].getStringValue(); + + if (name.equals("CalGray")) { + value = graySpace; // TODO [FHe] + } else if (name.equals("CalRGB")) { + value = rgbSpace; // TODO [FHe] + } else if (name.equals("Lab")) { + value = rgbSpace; // TODO [FHe] + } else if (name.equals("ICCBased")) { + value = rgbSpace; // TODO [FHe] + } else if (name.equals("Separation") || name.equals("DeviceN")) { + PDFColorSpace alternate = getColorSpace(ary[2], resources); + PDFFunction function = PDFFunction.getFunction(ary[3]); + value = new AlternateColorSpace(alternate, function); + } else if (name.equals("Indexed") || name.equals("I")) { + /** + * 4.5.5 [/Indexed baseColor hival lookup] + */ + PDFColorSpace refspace = getColorSpace(ary[1], resources); + + // number of indices= ary[2], data is in ary[3]; + int count = ary[2].getIntValue(); + value = new IndexedColor(refspace, count, ary[3]); + } else if (name.equals("Pattern")) { + return rgbSpace; // TODO [FHe] + } else { + throw new PDFParseException("Unknown color space: " + name + + " with " + ary[1]); + } + + csobj.setCache(value); + + return value; } - PDFColorSpace value = null; + /** + * get the number of components expected in the getPaint command + */ + public abstract int getNumComponents(); - // csobj is [/name <>] - PDFObject[] ary = csobj.getArray(); - name = ary[0].getStringValue(); - - if (name.equals("CalGray")) { - value = graySpace; // TODO [FHe] - } else if (name.equals("CalRGB")) { - value = rgbSpace; // TODO [FHe] - } else if (name.equals("Lab")) { - value = rgbSpace; // TODO [FHe] - } else if (name.equals("ICCBased")) { - value = rgbSpace;//icciSpace; // TODO [FHe] - } else if (name.equals("Separation") || name.equals("DeviceN")) { - PDFColorSpace alternate = getColorSpace(ary[2], resources); - PDFFunction function = PDFFunction.getFunction(ary[3]); - value = new AlternateColorSpace(alternate, function); - } else if (name.equals("Indexed") || name.equals("I")) { - /** - * 4.5.5 [/Indexed baseColor hival lookup] - */ - PDFColorSpace refspace = getColorSpace(ary[1], resources); - - // number of indices= ary[2], data is in ary[3]; - int count = ary[2].getIntValue(); - value = new IndexedColor(refspace, count, ary[3]); - } else if (name.equals("Pattern")) { - return rgbSpace; // TODO [FHe] - } else { - throw new PDFParseException("Unknown color space: " + name + - " with " + ary[1]); + /** + * get the PDFPaint representing the color described by the + * given color components + * @param components the color components corresponding to the given + * colorspace + * @return a PDFPaint object representing the closest Color to the + * given components. + */ + public PDFPaint getPaint(float[] components) { + return PDFPaint.getColorPaint(toColor(components)); + } + public PDFPaint getFillPaint(float[] components) { + return PDFPaint.getPaint(toColor(components)); } - csobj.setCache(value); + /** + * get the type of this color space + */ + public abstract int getType(); + /** + * get the name of this color space + */ + public abstract String getName(); - return value; - } + public abstract int toColor(float[] fcomp); + + public abstract int toColor(int[] icomp); + + @Override + public String toString() { + return "ColorSpace["+getName()+"]"; + } - /** - * get the number of components expected in the getPaint command - */ - public abstract int getNumComponents(); - - /** - * get the PDFPaint representing the color described by the - * given color components - * - * @param components the color components corresponding to the given - * colorspace - * @return a PDFPaint object representing the closest Color to the - * given components. - */ - public PDFPaint getPaint(float[] components) { - return PDFPaint.getColorPaint(toColor(components)); - } - - public PDFPaint getFillPaint(float[] components) { - return PDFPaint.getPaint(toColor(components)); - } - - /** - * get the type of this color space - */ - public abstract int getType(); - - /** - * get the name of this color space - */ - public abstract String getName(); - - public abstract int toColor(float[] fcomp); - - public abstract int toColor(int[] icomp); - - @Override public String toString() { - return "ColorSpace[" + getName() + "]"; - } } diff --git a/PdfView/src/main/java/com/sun/pdfview/decode/DCTDecode.java b/PdfView/src/main/java/com/sun/pdfview/decode/DCTDecode.java index 7e13e2c..0ad23b1 100644 --- a/PdfView/src/main/java/com/sun/pdfview/decode/DCTDecode.java +++ b/PdfView/src/main/java/com/sun/pdfview/decode/DCTDecode.java @@ -21,13 +21,19 @@ package com.sun.pdfview.decode; +import java.io.IOException; +import java.nio.IntBuffer; + +import net.sf.andpdf.nio.ByteBuffer; + import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; +import android.graphics.Bitmap.Config; import android.util.Log; + import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; -import net.sf.andpdf.nio.ByteBuffer; +import com.sun.pdfview.colorspace.PDFColorSpace; /** * decode a DCT encoded array into a byte array. This class uses Java's @@ -37,49 +43,52 @@ import net.sf.andpdf.nio.ByteBuffer; */ public class DCTDecode { - /** - * decode an array of bytes in DCT format. - *

    - * DCT is the format used by JPEG images, so this class simply - * loads the DCT-format bytes as an image, then reads the bytes out - * of the image to create the array. Unfortunately, their most - * likely use is to get turned BACK into an image, so this isn't - * terribly efficient... but is is general... don't hit, please. - *

    - * The DCT-encoded stream may have 1, 3 or 4 samples per pixel, depending - * on the colorspace of the image. In decoding, we look for the colorspace - * in the stream object's dictionary to decide how to decode this image. - * If no colorspace is present, we guess 3 samples per pixel. - * - * @param dict the stream dictionary - * @param buf the DCT-encoded buffer - * @param params the parameters to the decoder (ignored) - * @return the decoded buffer - */ - protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException { - // System.out.println("DCTDecode image info: "+params); - buf.rewind(); + /** + * decode an array of bytes in DCT format. + *

    + * DCT is the format used by JPEG images, so this class simply + * loads the DCT-format bytes as an image, then reads the bytes out + * of the image to create the array. Unfortunately, their most + * likely use is to get turned BACK into an image, so this isn't + * terribly efficient... but is is general... don't hit, please. + *

    + * The DCT-encoded stream may have 1, 3 or 4 samples per pixel, depending + * on the colorspace of the image. In decoding, we look for the colorspace + * in the stream object's dictionary to decide how to decode this image. + * If no colorspace is present, we guess 3 samples per pixel. + * + * @param dict the stream dictionary + * @param buf the DCT-encoded buffer + * @param params the parameters to the decoder (ignored) + * @return the decoded buffer + */ + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, + PDFObject params) throws PDFParseException + { + // System.out.println("DCTDecode image info: "+params); + buf.rewind(); + + // copy the data into a byte array required by createimage + byte[] ary = new byte[buf.remaining()]; + buf.get(ary); - // copy the data into a byte array required by createimage - byte[] ary = new byte[buf.remaining()]; - buf.get(ary); - Bitmap img = BitmapFactory.decodeByteArray(ary, 0, ary.length); + Bitmap img = BitmapFactory.decodeByteArray(ary, 0, ary.length); - if (img == null) throw new PDFParseException("could not decode image of compressed size " + ary.length); - Config conf = img.getConfig(); - Log.e("ANDPDF.dctdecode", "decoded image type" + conf); - int size = 4 * img.getWidth() * img.getHeight(); - if (conf == Config.RGB_565) { - size = 2 * img.getWidth() * img.getHeight(); + if (img == null) + throw new PDFParseException("could not decode image of compressed size "+ary.length); + Config conf = img.getConfig(); + Log.e("ANDPDF.dctdecode", "decoded image type"+conf); + int size = 4*img.getWidth()*img.getHeight(); + if (conf == Config.RGB_565) + size = 2*img.getWidth()*img.getHeight(); + // TODO [FHe]: else ... what do we get for gray? Config.ALPHA_8? + + java.nio.ByteBuffer byteBuf = java.nio.ByteBuffer.allocate(size); + img.copyPixelsToBuffer(byteBuf); + + ByteBuffer result = ByteBuffer.fromNIO(byteBuf); + result.rewind(); + return result; } - // TODO [FHe]: else ... what do we get for gray? Config.ALPHA_8? - - java.nio.ByteBuffer byteBuf = java.nio.ByteBuffer.allocate(size); - img.copyPixelsToBuffer(byteBuf); - ByteBuffer result = ByteBuffer.fromNIO(byteBuf); - result.rewind(); - - return result; - } } diff --git a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java index 27f47ca..e05f07e 100644 --- a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java +++ b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java @@ -1,22 +1,17 @@ package net.sf.andpdf.pdfviewer; import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Gravity; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -25,7 +20,6 @@ import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -43,7 +37,6 @@ import net.sf.andpdf.nio.ByteBuffer; import net.sf.andpdf.refs.HardReference; import java.io.IOException; -import java.util.Locale; import uk.co.senab.photoview.PhotoViewAttacher; @@ -64,8 +57,6 @@ public class PdfViewerFragment extends Fragment { public static final boolean DEFAULTANTIALIAS = true; public static final boolean DEFAULTUSEFONTSUBSTITUTION = false; - public static final String DIALOG_FRAGMENT_TAG_MARK = "DIALOG_FRAGMENT"; - private GraphView mGraphView; private PDFFile mPdfFile; public static byte[] byteArray; @@ -221,13 +212,6 @@ public class PdfViewerFragment extends Fragment { } } - private void gotoPage() { - if (mPdfFile != null) { - final Bundle bundle = new Bundle(); - showDialogFragment(new GoToPageDialogFragment(), bundle); - } - } - /** * Hides device keyboard that is showing over {@link Activity}. * Do NOT use it if keyboard is over {@link android.app.Dialog} - it won't work as they have different {@link Activity#getWindow()}. @@ -241,78 +225,11 @@ public class PdfViewerFragment extends Fragment { getActivity().getWindow().getDecorView().requestFocus(); } - public class GoToPageDialogFragment extends DialogFragment { - - @NonNull - @Override - public Dialog onCreateDialog(final Bundle savedInstanceState) { - LayoutInflater factory = LayoutInflater.from(getActivity()); - final View pagenumView = factory.inflate(R.layout.dialog_pagenumber, null); - final EditText edPagenum = (EditText) pagenumView.findViewById(R.id.pagenum_edit); - edPagenum.setText(String.format(Locale.getDefault(), "%d", mPage)); - edPagenum.setOnEditorActionListener(new TextView.OnEditorActionListener() { - - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (event == null || (event.getAction() == 1)) { - // Hide the keyboard - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(edPagenum.getWindowToken(), 0); - } - return true; - } - }); - return new AlertDialog.Builder(getActivity()) - //.setIcon(R.drawable.icon) - .setTitle("Jump to page") - .setView(pagenumView) - .setPositiveButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String strPagenum = edPagenum.getText().toString(); - int pageNum = mPage; - try { - pageNum = Integer.parseInt(strPagenum); - } catch (NumberFormatException ignore) { - } - if ((pageNum != mPage) && (pageNum >= 1) && (pageNum <= mPdfFile.getNumPages())) { - mPage = pageNum; - mGraphView.bZoomOut.setEnabled(true); - mGraphView.bZoomIn.setEnabled(true); - progress = ProgressDialog.show(getActivity(), "Loading", "Loading PDF Page " + mPage, true, true); - startRenderThread(mPage); - } - } - }) - .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }) - .create(); - } - } - - public void showDialogFragment(@NonNull final DialogFragment dialogFragment, @Nullable final Bundle bundle) { - if (getFragmentManager().getFragments() != null) { - for (final Fragment fragment : getFragmentManager().getFragments()) { - // to fix bug with opening fragment several times on fast clicking - if (fragment != null && fragment.getClass() == dialogFragment.getClass()) { - return; - } - } - } - if (bundle != null) { - dialogFragment.setArguments(bundle); - } - dialogFragment.show(getFragmentManager(), dialogFragment.getClass().getName() + ";" + DIALOG_FRAGMENT_TAG_MARK); - } - private class GraphView extends FrameLayout { public Bitmap mBi; public ImageView pdfZoomedImageView; public PhotoViewAttacher photoViewAttacher; - ImageButton bZoomOut; - ImageButton bZoomIn; - public GraphView(Context context) { super(context); diff --git a/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java b/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java deleted file mode 100755 index 9eb9e3c..0000000 --- a/PdfView/src/main/java/net/sf/andpdf/utils/MathUtils.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2012 Jason Polites - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.sf.andpdf.utils; - -import android.graphics.PointF; -import android.util.FloatMath; -import android.view.MotionEvent; - -public class MathUtils { - - public static float distance(MotionEvent event) { - float x = event.getX(0) - event.getX(1); - float y = event.getY(0) - event.getY(1); - return FloatMath.sqrt(x * x + y * y); - } - - public static float distance(PointF p1, PointF p2) { - float x = p1.x - p2.x; - float y = p1.y - p2.y; - return FloatMath.sqrt(x * x + y * y); - } - - public static float distance(float x1, float y1, float x2, float y2) { - float x = x1 - x2; - float y = y1 - y2; - return FloatMath.sqrt(x * x + y * y); - } - - public static void midpoint(MotionEvent event, PointF point) { - float x1 = event.getX(0); - float y1 = event.getY(0); - float x2 = event.getX(1); - float y2 = event.getY(1); - midpoint(x1, y1, x2, y2, point); - } - - public static void midpoint(float x1, float y1, float x2, float y2, PointF point) { - point.x = (x1 + x2) / 2.0f; - point.y = (y1 + y2) / 2.0f; - } - - /** - * Rotates p1 around p2 by angle degrees. - * - * @param p1 - * @param p2 - * @param angle - */ - public void rotate(PointF p1, PointF p2, float angle) { - float px = p1.x; - float py = p1.y; - float ox = p2.x; - float oy = p2.y; - p1.x = (FloatMath.cos(angle) * (px - ox) - FloatMath.sin(angle) * (py - oy) + ox); - p1.y = (FloatMath.sin(angle) * (px - ox) + FloatMath.cos(angle) * (py - oy) + oy); - } - - public static float angle(PointF p1, PointF p2) { - return angle(p1.x, p1.y, p2.x, p2.y); - } - - public static float angle(float x1, float y1, float x2, float y2) { - return (float) Math.atan2(y2 - y1, x2 - x1); - } -} diff --git a/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java b/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java deleted file mode 100644 index b0669af..0000000 --- a/PdfView/src/main/java/net/sf/andpdf/utils/VectorF.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2012 Jason Polites - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.sf.andpdf.utils; - -import android.graphics.PointF; -import android.util.FloatMath; -import android.view.MotionEvent; - -public class VectorF { - - public float angle; - public float length; - - public final PointF start = new PointF(); - public final PointF end = new PointF(); - - public void calculateEndPoint() { - end.x = FloatMath.cos(angle) * length + start.x; - end.y = FloatMath.sin(angle) * length + start.y; - } - - public void setStart(PointF p) { - this.start.x = p.x; - this.start.y = p.y; - } - - public void setEnd(PointF p) { - this.end.x = p.x; - this.end.y = p.y; - } - - public void set(MotionEvent event) { - this.start.x = event.getX(0); - this.start.y = event.getY(0); - this.end.x = event.getX(1); - this.end.y = event.getY(1); - } - - public float calculateLength() { - length = MathUtils.distance(start, end); - return length; - } - - public float calculateAngle() { - angle = MathUtils.angle(start, end); - return angle; - } - - -} From 203c4585aae4f84186439ea7828b7681a3c21d44 Mon Sep 17 00:00:00 2001 From: contrudar Date: Wed, 26 Oct 2016 12:20:16 +0300 Subject: [PATCH 2/2] return loaders during rendering --- .../andpdf/pdfviewer/PdfViewerFragment.java | 100 ++++++++---------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java index e05f07e..a17063d 100644 --- a/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java +++ b/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java @@ -283,70 +283,64 @@ public class PdfViewerFragment extends Fragment { // TODO: refactor private void showPage(final int page) { // on some Android getWidth() and getHeight() returns 0, so we need to wait until UI is ready - mGraphView.post(new Runnable() { - @Override - public void run() { - try { - // free memory from previous page - mGraphView.setPageBitmap(null); - mGraphView.updateImage(); + try { + // free memory from previous page + mGraphView.setPageBitmap(null); + mGraphView.updateImage(); - // Only load the page if it's a different page (i.e. not just changing the zoom level) - if (mPdfPage == null || mPdfPage.getPageNumber() != page) { - mPdfPage = mPdfFile.getPage(page, true); - } + // Only load the page if it's a different page (i.e. not just changing the zoom level) + if (mPdfPage == null || mPdfPage.getPageNumber() != page) { + mPdfPage = mPdfFile.getPage(page, true); + } - final int scale = 3; + final int scale = 3; - double width = mPdfPage.getWidth() * scale; - double height = mPdfPage.getHeight() * scale; + double width = mPdfPage.getWidth() * scale; + double height = mPdfPage.getHeight() * scale; - int maxWidthToPopulate = mGraphView.getWidth(); - int maxHeightToPopulate = mGraphView.getHeight(); + int maxWidthToPopulate = mGraphView.getWidth(); + int maxHeightToPopulate = mGraphView.getHeight(); - int calculatedWidth; - int calculatedHeight; - final double widthRatio = width / maxWidthToPopulate; - final double heightRatio = height / maxHeightToPopulate; - if (width < maxWidthToPopulate && height < maxHeightToPopulate) { - if (widthRatio > heightRatio) { - calculatedWidth = (int) (width / widthRatio); - calculatedHeight = (int) (height / widthRatio); - } else { - calculatedWidth = (int) (width / heightRatio); - calculatedHeight = (int) (height / heightRatio); - } + int calculatedWidth; + int calculatedHeight; + final double widthRatio = width / maxWidthToPopulate; + final double heightRatio = height / maxHeightToPopulate; + if (width < maxWidthToPopulate && height < maxHeightToPopulate) { + if (widthRatio > heightRatio) { + calculatedWidth = (int) (width / widthRatio); + calculatedHeight = (int) (height / widthRatio); + } else { + calculatedWidth = (int) (width / heightRatio); + calculatedHeight = (int) (height / heightRatio); + } + } else { + if (widthRatio > 1 && heightRatio > 1) { + if (widthRatio > heightRatio) { + calculatedHeight = (int) (height / widthRatio); + calculatedWidth = (int) (width / widthRatio); } else { - if (widthRatio > 1 && heightRatio > 1) { - if (widthRatio > heightRatio) { - calculatedHeight = (int) (height / widthRatio); - calculatedWidth = (int) (width / widthRatio); - } else { - calculatedHeight = (int) (height / heightRatio); - calculatedWidth = (int) (width / heightRatio); - } - } else { - if (widthRatio > heightRatio) { - calculatedHeight = (int) (height / widthRatio); - calculatedWidth = (int) (width / widthRatio); - } else { - calculatedHeight = (int) (height / heightRatio); - calculatedWidth = (int) (width / heightRatio); - } - } + calculatedHeight = (int) (height / heightRatio); + calculatedWidth = (int) (width / heightRatio); + } + } else { + if (widthRatio > heightRatio) { + calculatedHeight = (int) (height / widthRatio); + calculatedWidth = (int) (width / widthRatio); + } else { + calculatedHeight = (int) (height / heightRatio); + calculatedWidth = (int) (width / heightRatio); } - - final Bitmap bitmap = mPdfPage.getImage(calculatedWidth, calculatedHeight, null, true, true); - mGraphView.setPageBitmap(bitmap); - mGraphView.updateImage(); - } catch (Throwable e) { - Log.e(TAG, e.getMessage(), e); } } - }); + + final Bitmap bitmap = mPdfPage.getImage(calculatedWidth, calculatedHeight, null, true, true); + mGraphView.setPageBitmap(bitmap); + mGraphView.updateImage(); + } catch (Throwable e) { + Log.e(TAG, e.getMessage(), e); + } hideProgressBar(); - } private void hideProgressBar() {