diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/BaseWatchable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/BaseWatchable.java index c2f3cf7b2..a7cd2c1fd 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/BaseWatchable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/BaseWatchable.java @@ -79,7 +79,7 @@ protected void cleanup() { } @Override - public void run() { + public void run() { try { Thread.sleep(1); // call setup once we started @@ -151,7 +151,7 @@ public void run() { * @return one of the well-known statuses */ @Override - public int getStatus() { + public int getStatus() { return this.status; } @@ -175,12 +175,12 @@ public boolean isExecutable() { /** * Stop this watchable if it is not already finished. - * Stop will cause all processing to cease, + * Stop will cause all processing to cease, * and the watchable to be destroyed. */ @Override - public void stop() { - if (!isFinished()) setStatus(Watchable.STOPPED); + public void stop() { + if (!isFinished()) setStatus(Watchable.STOPPED); } /** @@ -190,7 +190,7 @@ public void stop() { * different time is called during execution. */ @Override - public synchronized void go() { + public synchronized void go() { this.gate = null; execute(false); @@ -216,7 +216,7 @@ public synchronized void go(boolean synchronous) { * @param steps the number of steps to run for */ @Override - public synchronized void go(int steps) { + public synchronized void go(int steps) { this.gate = new Gate(); this.gate.setStopIterations(steps); @@ -230,7 +230,7 @@ public synchronized void go(int steps) { * @param millis the number of milliseconds to run for */ @Override - public synchronized void go(long millis) { + public synchronized void go(long millis) { this.gate = new Gate(); this.gate.setStopTime(millis); @@ -277,11 +277,11 @@ protected synchronized void execute(boolean synchronous) { this.thread = Thread.currentThread(); run(); } else { - this.thread = new Thread(this); - this.thread.setName(getClass().getName()); - //Fix for NPE: Taken from http://java.net/jira/browse/PDF_RENDERER-46 - synchronized (statusLock) { - Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() { + this.thread = new Thread(this); + this.thread.setName(getClass().getName()); + //Fix for NPE: Taken from http://java.net/jira/browse/PDF_RENDERER-46 + synchronized (statusLock) { + Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException( Thread th, Throwable ex ) { @@ -289,7 +289,7 @@ public void uncaughtException( Thread th, Throwable ex ) } }; thread.setUncaughtExceptionHandler( h ); - thread.start(); + thread.start(); try { this.statusLock.wait(5000); } catch (InterruptedException ex) { @@ -297,7 +297,7 @@ public void uncaughtException( Thread th, Throwable ex ) PDFDebugger.debug("Thread interrupted while waiting for status change."); } - } + } } } @@ -334,7 +334,7 @@ public static void setSuppressSetErrorStackTrace(boolean suppressTrace) { * Set an error on this watchable */ protected void setError(Exception error) { - exception = error; + exception = error; if (!SuppressSetErrorStackTrace) { errorHandler.publishException(error); } @@ -342,9 +342,9 @@ protected void setError(Exception error) { setStatus(Watchable.ERROR); } - public Exception getException() { - return exception; - } + public Exception getException() { + return exception; + } /** A class that lets us give it a target time or number of steps, * and will tell us to stop after that much time or that many steps diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/Configuration.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/Configuration.java index 7f58b9736..6f01a3d5a 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/Configuration.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/Configuration.java @@ -9,7 +9,7 @@ * PDFRenderer API. */ public class Configuration { - private static Configuration INSTANCE; + private static Configuration INSTANCE; /** whether grey scale images will be converted to ARGB */ private boolean convertGreyscaleImagesToArgb = true; @@ -31,60 +31,60 @@ public class Configuration { /** Print link annotations on pdf **/ private boolean printLinkAnnotations = true; - public static synchronized Configuration getInstance() { - if (INSTANCE == null) { - INSTANCE = new Configuration(); - } - return INSTANCE; - } + public static synchronized Configuration getInstance() { + if (INSTANCE == null) { + INSTANCE = new Configuration(); + } + return INSTANCE; + } /** - * Enables or disables the conversion of greyscale images to ARGB. - * Disabling this may have a lower memory overhead with high resolution - * (e.g. scanned) images. Note that this has to be called before - * {@link #getImage()} is called to have an effect. - * - * Enabled by default. - * @param aFlag whether greyscale images shall be converted to ARGB. - */ - public void setConvertGreyscaleImagesToArgb(boolean aFlag) { - convertGreyscaleImagesToArgb = aFlag; - } + * Enables or disables the conversion of greyscale images to ARGB. + * Disabling this may have a lower memory overhead with high resolution + * (e.g. scanned) images. Note that this has to be called before + * {@link #getImage()} is called to have an effect. + * + * Enabled by default. + * @param aFlag whether greyscale images shall be converted to ARGB. + */ + public void setConvertGreyscaleImagesToArgb(boolean aFlag) { + convertGreyscaleImagesToArgb = aFlag; + } - /** - * Returns true if greyscale images will be converted to ARGB - */ - public boolean isConvertGreyscaleImagesToArgb() { - return convertGreyscaleImagesToArgb; - } + /** + * Returns true if greyscale images will be converted to ARGB + */ + public boolean isConvertGreyscaleImagesToArgb() { + return convertGreyscaleImagesToArgb; + } - /** - * If an image is higher than the given size (in pixels) then - * the image will be rendered in chunks, rather than as one big image. - * This may lead to lower memory consumption for e.g. scanned PDFs with - * large images. - * - * Set to a value <= 0 to disable banded image rendering. - * Defaults to 0 (off) - * - * @param aSize the height threshold at which to enable banded image rendering - */ - public void setThresholdForBandedImageRendering(int aSize) { - thresholdForBandedImageRendering = aSize; - } + /** + * If an image is higher than the given size (in pixels) then + * the image will be rendered in chunks, rather than as one big image. + * This may lead to lower memory consumption for e.g. scanned PDFs with + * large images. + * + * Set to a value <= 0 to disable banded image rendering. + * Defaults to 0 (off) + * + * @param aSize the height threshold at which to enable banded image rendering + */ + public void setThresholdForBandedImageRendering(int aSize) { + thresholdForBandedImageRendering = aSize; + } - /** - * Returns the image height threshold at which to enable banded image rendering. - * @return the threshold value, or a value <= 0 if banded rendering is disabled - */ - public int getThresholdForBandedImageRendering() { - return thresholdForBandedImageRendering; - } + /** + * Returns the image height threshold at which to enable banded image rendering. + * @return the threshold value, or a value <= 0 if banded rendering is disabled + */ + public int getThresholdForBandedImageRendering() { + return thresholdForBandedImageRendering; + } - /** - * Is the color converting op switched on or off? - * @return - the usage of this color convert op - */ + /** + * Is the color converting op switched on or off? + * @return - the usage of this color convert op + */ public boolean isAvoidColorConvertOp() { return avoidColorConvertOp; } @@ -131,14 +131,14 @@ public void setUseBlurResizingForImages(boolean useBlurResizingForImages) { * @param printSignatureField */ public void setPrintSignatureFields(boolean printSignatureFields) { - this.printSigantureFields = printSignatureFields; + this.printSigantureFields = printSignatureFields; } /** * @return true if signature fields will be printed on pdf */ public boolean isPrintSignatureFields() { - return this.printSigantureFields; + return this.printSigantureFields; } /** @@ -147,14 +147,14 @@ public boolean isPrintSignatureFields() { * @param printStampAnnotation */ public void setPrintStampAnnotations(boolean printStampAnnotations) { - this.printStampAnnotations = printStampAnnotations; + this.printStampAnnotations = printStampAnnotations; } /** * @return true if stamp annotations will be printed on pdf */ public boolean isPrintStampAnnotations() { - return this.printStampAnnotations; + return this.printStampAnnotations; } /** @@ -163,15 +163,15 @@ public boolean isPrintStampAnnotations() { * @param printWidgetAnnotations */ public void setPrintWidgetAnnotations(boolean printWidgetAnnotations) { - this.printWidgetAnnotations = printWidgetAnnotations; + this.printWidgetAnnotations = printWidgetAnnotations; } /** * @return true if widget annotations will be printed on pdf */ public boolean isPrintWidgetAnnotations() { - return this.printWidgetAnnotations; - } + return this.printWidgetAnnotations; + } /** * Print freetext annotations on pdf @@ -179,14 +179,14 @@ public boolean isPrintWidgetAnnotations() { * @param printFreetextAnnotations */ public void setPrintFreetextAnnotations(boolean printFreetextAnnotations) { - this.printFreetextAnnotations = printFreetextAnnotations; + this.printFreetextAnnotations = printFreetextAnnotations; } /** * @return true if freetext annotations will be printed on pdf */ public boolean isPrintFreetextAnnotations() { - return this.printFreetextAnnotations; + return this.printFreetextAnnotations; } /** @@ -195,13 +195,13 @@ public boolean isPrintFreetextAnnotations() { * @param printLinkAnnotations */ public void setPrintLinkAnnotations(boolean printLinkAnnotations) { - this.printLinkAnnotations = printLinkAnnotations; + this.printLinkAnnotations = printLinkAnnotations; } /** * @return true if link annotations will be printed on pdf */ public boolean isPrintLinkAnnotations() { - return this.printLinkAnnotations; + return this.printLinkAnnotations; } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/Identity8BitCharsetEncoder.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/Identity8BitCharsetEncoder.java index e934c49c2..0eee52c1a 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/Identity8BitCharsetEncoder.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/Identity8BitCharsetEncoder.java @@ -38,7 +38,7 @@ public Identity8BitCharsetEncoder() { } @Override - protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.remaining() > 0) { if (out.remaining() < 1) { return CoderResult.OVERFLOW; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/NameTree.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/NameTree.java index 6f18fbcbc..d3e29bb5a 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/NameTree.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/NameTree.java @@ -110,12 +110,12 @@ private PDFObject findInArray(PDFObject[] array, String key) int comp = key.compareTo(posKey); if (comp == 0) { // they match. Return the value - int tmp = (pos * 2) + 1; - if(array.length>tmp){ + int tmp = (pos * 2) + 1; + if(array.length>tmp){ return array[tmp]; - }else { - return null; - } + }else { + return null; + } } else if (comp > 0) { // too big, search the top half of the tree start = pos + 1; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDestination.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDestination.java index beb2875a2..7756b8dce 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDestination.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDestination.java @@ -35,265 +35,265 @@ */ public class PDFDestination { - /** The known types of destination */ - public static final int XYZ = 0; - public static final int FIT = 1; - public static final int FITH = 2; - public static final int FITV = 3; - public static final int FITR = 4; - public static final int FITB = 5; - public static final int FITBH = 6; - public static final int FITBV = 7; - /** the type of this destination (from the list above) */ - private int type; - /** the page we refer to */ - private PDFObject pageObj; - /** the left coordinate of the fit area, if applicable */ - private float left; - /** the right coordinate of the fit area, if applicable */ - private float right; - /** the top coordinate of the fit area, if applicable */ - private float top; - /** the bottom coordinate of the fit area, if applicable */ - private float bottom; - /** the zoom, if applicable */ - private float zoom; + /** The known types of destination */ + public static final int XYZ = 0; + public static final int FIT = 1; + public static final int FITH = 2; + public static final int FITV = 3; + public static final int FITR = 4; + public static final int FITB = 5; + public static final int FITBH = 6; + public static final int FITBV = 7; + /** the type of this destination (from the list above) */ + private int type; + /** the page we refer to */ + private PDFObject pageObj; + /** the left coordinate of the fit area, if applicable */ + private float left; + /** the right coordinate of the fit area, if applicable */ + private float right; + /** the top coordinate of the fit area, if applicable */ + private float top; + /** the bottom coordinate of the fit area, if applicable */ + private float bottom; + /** the zoom, if applicable */ + private float zoom; - /** - * Creates a new instance of PDFDestination - * - * @param pageObj - * the page object this destination refers to - * @param type - * the type of page this object refers to - */ - protected PDFDestination(PDFObject pageObj, int type) { - this.pageObj = pageObj; - this.type = type; - } + /** + * Creates a new instance of PDFDestination + * + * @param pageObj + * the page object this destination refers to + * @param type + * the type of page this object refers to + */ + protected PDFDestination(PDFObject pageObj, int type) { + this.pageObj = pageObj; + this.type = type; + } - /** - * Get a destination from either an array (explicit destination), a name - * (named destination) or a string (name tree destination). - * - * @param obj - * the PDFObject representing this destination - * @param root - * the root of the PDF object tree - */ - public static PDFDestination getDestination(PDFObject obj, PDFObject root) throws IOException { - // resolve string and name issues - if (obj.getType() == PDFObject.NAME) { - obj = getDestFromName(obj, root); - } else if (obj.getType() == PDFObject.STRING) { - obj = getDestFromString(obj, root); - } + /** + * Get a destination from either an array (explicit destination), a name + * (named destination) or a string (name tree destination). + * + * @param obj + * the PDFObject representing this destination + * @param root + * the root of the PDF object tree + */ + public static PDFDestination getDestination(PDFObject obj, PDFObject root) throws IOException { + // resolve string and name issues + if (obj.getType() == PDFObject.NAME) { + obj = getDestFromName(obj, root); + } else if (obj.getType() == PDFObject.STRING) { + obj = getDestFromString(obj, root); + } - // make sure we have the right kind of object - if (obj == null || obj.getType() != PDFObject.ARRAY) { - throw new PDFParseException("Can't create destination from: " + obj); - } + // make sure we have the right kind of object + if (obj == null || obj.getType() != PDFObject.ARRAY) { + throw new PDFParseException("Can't create destination from: " + obj); + } - // the array is in the form [page type args ... ] - PDFObject[] destArray = obj.getArray(); + // the array is in the form [page type args ... ] + PDFObject[] destArray = obj.getArray(); - // create the destination based on the type - PDFDestination dest = null; - String type = destArray[1].getStringValue(); - if (type.equals("XYZ")) { - dest = new PDFDestination(destArray[0], XYZ); - } else if (type.equals("Fit")) { - dest = new PDFDestination(destArray[0], FIT); - } else if (type.equals("FitH")) { - dest = new PDFDestination(destArray[0], FITH); - } else if (type.equals("FitV")) { - dest = new PDFDestination(destArray[0], FITV); - } else if (type.equals("FitR")) { - dest = new PDFDestination(destArray[0], FITR); - } else if (type.equals("FitB")) { - dest = new PDFDestination(destArray[0], FITB); - } else if (type.equals("FitBH")) { - dest = new PDFDestination(destArray[0], FITBH); - } else if (type.equals("FitBV")) { - dest = new PDFDestination(destArray[0], FITBV); - } else { - throw new PDFParseException("Unknown destination type: " + type); - } + // create the destination based on the type + PDFDestination dest = null; + String type = destArray[1].getStringValue(); + if (type.equals("XYZ")) { + dest = new PDFDestination(destArray[0], XYZ); + } else if (type.equals("Fit")) { + dest = new PDFDestination(destArray[0], FIT); + } else if (type.equals("FitH")) { + dest = new PDFDestination(destArray[0], FITH); + } else if (type.equals("FitV")) { + dest = new PDFDestination(destArray[0], FITV); + } else if (type.equals("FitR")) { + dest = new PDFDestination(destArray[0], FITR); + } else if (type.equals("FitB")) { + dest = new PDFDestination(destArray[0], FITB); + } else if (type.equals("FitBH")) { + dest = new PDFDestination(destArray[0], FITBH); + } else if (type.equals("FitBV")) { + dest = new PDFDestination(destArray[0], FITBV); + } else { + throw new PDFParseException("Unknown destination type: " + type); + } - // now fill in the arguments based on the type - switch (dest.getType()) { - case XYZ: - dest.setLeft(destArray[2].getFloatValue()); - dest.setTop(destArray[3].getFloatValue()); - dest.setZoom(destArray[4].getFloatValue()); - break; - case FITH: - if (destArray.length > 2) { - dest.setTop(destArray[2].getFloatValue()); - } else { - dest.setTop(0.0F); - } - break; - case FITV: - if (destArray.length > 2) { - dest.setTop(destArray[2].getFloatValue()); - } else { - dest.setTop(0.0F); - } - break; - case FITR: - dest.setLeft(destArray[2].getFloatValue()); - dest.setBottom(destArray[3].getFloatValue()); - dest.setRight(destArray[4].getFloatValue()); - dest.setTop(destArray[5].getFloatValue()); - break; - case FITBH: - if (destArray.length > 2) { - dest.setTop(destArray[2].getFloatValue()); - } else { - dest.setTop(0.0F); - } - break; - case FITBV: - if (destArray.length > 2) { - dest.setTop(destArray[2].getFloatValue()); - } else { - dest.setTop(0.0F); - } - break; - } + // now fill in the arguments based on the type + switch (dest.getType()) { + case XYZ: + dest.setLeft(destArray[2].getFloatValue()); + dest.setTop(destArray[3].getFloatValue()); + dest.setZoom(destArray[4].getFloatValue()); + break; + case FITH: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITV: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITR: + dest.setLeft(destArray[2].getFloatValue()); + dest.setBottom(destArray[3].getFloatValue()); + dest.setRight(destArray[4].getFloatValue()); + dest.setTop(destArray[5].getFloatValue()); + break; + case FITBH: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITBV: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + } - return dest; - } + return dest; + } - /** - * Get the type of this destination - */ - public int getType() { - return this.type; - } + /** + * Get the type of this destination + */ + public int getType() { + return this.type; + } - /** - * Get the PDF Page object associated with this destination - */ - public PDFObject getPage() { - return this.pageObj; - } + /** + * Get the PDF Page object associated with this destination + */ + public PDFObject getPage() { + return this.pageObj; + } - /** - * Get the left coordinate value - */ - public float getLeft() { - return this.left; - } + /** + * Get the left coordinate value + */ + public float getLeft() { + return this.left; + } - /** - * Set the left coordinate value - */ - public void setLeft(float left) { - this.left = left; - } + /** + * Set the left coordinate value + */ + public void setLeft(float left) { + this.left = left; + } - /** - * Get the right coordinate value - */ - public float getRight() { - return this.right; - } + /** + * Get the right coordinate value + */ + public float getRight() { + return this.right; + } - /** - * Set the right coordinate value - */ - public void setRight(float right) { - this.right = right; - } + /** + * Set the right coordinate value + */ + public void setRight(float right) { + this.right = right; + } - /** - * Get the top coordinate value - */ - public float getTop() { - return this.top; - } + /** + * Get the top coordinate value + */ + public float getTop() { + return this.top; + } - /** - * Set the top coordinate value - */ - public void setTop(float top) { - this.top = top; - } + /** + * Set the top coordinate value + */ + public void setTop(float top) { + this.top = top; + } - /** - * Get the bottom coordinate value - */ - public float getBottom() { - return this.bottom; - } + /** + * Get the bottom coordinate value + */ + public float getBottom() { + return this.bottom; + } - /** - * Set the bottom coordinate value - */ - public void setBottom(float bottom) { - this.bottom = bottom; - } + /** + * Set the bottom coordinate value + */ + public void setBottom(float bottom) { + this.bottom = bottom; + } - /** - * Get the zoom value - */ - public float getZoom() { - return this.zoom; - } + /** + * Get the zoom value + */ + public float getZoom() { + return this.zoom; + } - /** - * Set the zoom value - */ - public void setZoom(float zoom) { - this.zoom = zoom; - } + /** + * Set the zoom value + */ + public void setZoom(float zoom) { + this.zoom = zoom; + } - /** - * Get a destination, given a name. This means the destination is in the - * root node's dests dictionary. - */ - private static PDFObject getDestFromName(PDFObject name, PDFObject root) throws IOException { - // find the dests object in the root node - PDFObject dests = root.getDictRef("Dests"); - if (dests != null) { - // find this name in the dests dictionary - return dests.getDictRef(name.getStringValue()); - } + /** + * Get a destination, given a name. This means the destination is in the + * root node's dests dictionary. + */ + private static PDFObject getDestFromName(PDFObject name, PDFObject root) throws IOException { + // find the dests object in the root node + PDFObject dests = root.getDictRef("Dests"); + if (dests != null) { + // find this name in the dests dictionary + return dests.getDictRef(name.getStringValue()); + } - // not found - return null; - } + // not found + return null; + } - /** - * Get a destination, given a string. This means the destination is in the - * root node's names dictionary. - */ - private static PDFObject getDestFromString(PDFObject str, PDFObject root) throws IOException { - // find the names object in the root node - PDFObject names = root.getDictRef("Names"); - if (names != null) { - // find the dests entry in the names dictionary - PDFObject dests = names.getDictRef("Dests"); - if (dests != null) { - // create a name tree object - NameTree tree = new NameTree(dests); + /** + * Get a destination, given a string. This means the destination is in the + * root node's names dictionary. + */ + private static PDFObject getDestFromString(PDFObject str, PDFObject root) throws IOException { + // find the names object in the root node + PDFObject names = root.getDictRef("Names"); + if (names != null) { + // find the dests entry in the names dictionary + PDFObject dests = names.getDictRef("Dests"); + if (dests != null) { + // create a name tree object + NameTree tree = new NameTree(dests); - // find the value we're looking for - PDFObject obj = tree.find(str.getStringValue()); + // find the value we're looking for + PDFObject obj = tree.find(str.getStringValue()); - // if we get back a dictionary, look for the /D value - if (obj != null && obj.getType() == PDFObject.DICTIONARY) { - obj = obj.getDictRef("D"); - } + // if we get back a dictionary, look for the /D value + if (obj != null && obj.getType() == PDFObject.DICTIONARY) { + obj = obj.getDictRef("D"); + } - // found it - return obj; - } - } + // found it + return obj; + } + } - // not found - return null; - } + // not found + return null; + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDocCharsetEncoder.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDocCharsetEncoder.java index 12cae51bc..f60f83d48 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDocCharsetEncoder.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFDocCharsetEncoder.java @@ -78,7 +78,7 @@ public PDFDocCharsetEncoder() { } @Override - protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.remaining() > 0) { if (out.remaining() < 1) { return CoderResult.OVERFLOW; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFFile.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFFile.java index 517def048..72ae46e4e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFFile.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFFile.java @@ -111,11 +111,11 @@ public class PDFFile { * protected and requires a password */ public PDFFile(ByteBuffer buf) throws IOException { - this(buf, null); + this(buf, null); } public PDFFile(ByteBuffer buf, boolean doNotParse) throws IOException { - this.buf = buf; + this.buf = buf; } /** @@ -247,48 +247,48 @@ public synchronized PDFObject dereference(PDFXref ref, PDFDecrypter decrypter) boolean compressed = this.objIdx[id].getCompressed(); if (!compressed) { - int loc = this.objIdx[id].getFilePos(); - if (loc < 0) { - return PDFObject.nullObj; - } - - // move to where this object is - this.buf.position(loc); - - // read the object and cache the reference - obj= readObject(ref.getID(), ref.getGeneration(), decrypter); + int loc = this.objIdx[id].getFilePos(); + if (loc < 0) { + return PDFObject.nullObj; + } + + // move to where this object is + this.buf.position(loc); + + // read the object and cache the reference + obj= readObject(ref.getID(), ref.getGeneration(), decrypter); } else { // compressed - int compId = this.objIdx[id].getID(); - int idx = this.objIdx[id].getIndex(); - if (idx < 0) - return PDFObject.nullObj; - PDFXref compRef = new PDFXref(compId, 0); - PDFObject compObj = dereference(compRef, decrypter); - int first = compObj.getDictionary().get("First").getIntValue(); - int length = compObj.getDictionary().get("Length").getIntValue(); - int n = compObj.getDictionary().get("N").getIntValue(); - if (idx >= n) - return PDFObject.nullObj; - ByteBuffer strm = compObj.getStreamBuffer(); - - ByteBuffer oldBuf = this.buf; - this.buf = strm; - // skip other nums - for (int i=0; i= n) + return PDFObject.nullObj; + ByteBuffer strm = compObj.getStreamBuffer(); + + ByteBuffer oldBuf = this.buf; + this.buf = strm; + // skip other nums + for (int i=0; i hm = new HashMap(); // we've already read the <<. Now get /Name obj pairs until >> PDFObject name; - while ((name= readObject(objNum, objGen, decrypter))!=null) { + while ((name= readObject(objNum, objGen, decrypter))!=null) { // make sure first item is a NAME if (name.getType() != PDFObject.NAME) { throw new PDFParseException("First item in dictionary must be a /Name. (Was " + name + ")"); } - PDFObject value= readObject(objNum, objGen, decrypter); + PDFObject value= readObject(objNum, objGen, decrypter); if (value != null) { hm.put(name.getStringValue(), value); } @@ -844,7 +844,7 @@ private PDFObject readArray( // we've already read the [. Now read objects until ] ArrayList ary = new ArrayList(); PDFObject obj; - while((obj= readObject(objNum, objGen, decrypter))!=null) { + while((obj= readObject(objNum, objGen, decrypter))!=null) { ary.add(obj); } if (this.buf.hasRemaining() && this.buf.get() != ']') { @@ -1038,16 +1038,16 @@ private void readTrailer(PDFPassword password) while (true) { // make sure we are looking at an xref table if (!nextItemIs("xref")) { - this.buf.position(pos); - readTrailer15(password); - return; + this.buf.position(pos); + readTrailer15(password); + return; // throw new PDFParseException("Expected 'xref' at start of table"); } // read a bunch of linked tabled while (true) { // read until the word "trailer" - PDFObject obj=readObject(-1, -1, IdentityDecrypter.getInstance()); + PDFObject obj=readObject(-1, -1, IdentityDecrypter.getInstance()); if (obj.getType() == PDFObject.KEYWORD && obj.getStringValue().equals("trailer")) { break; @@ -1113,7 +1113,7 @@ private void readTrailer(PDFPassword password) } // at this point, the "trailer" word (not EOL) has been read. - PDFObject trailerdict = readObject(-1, -1, IdentityDecrypter.getInstance()); + PDFObject trailerdict = readObject(-1, -1, IdentityDecrypter.getInstance()); if (trailerdict.getType() != PDFObject.DICTIONARY) { throw new IOException("Expected dictionary after \"trailer\""); } @@ -1160,7 +1160,7 @@ private void readTrailer(PDFPassword password) if (xrefstmPos != null) { int pos14 = this.buf.position(); this.buf.position(xrefstmPos.getIntValue()); - readTrailer15(password); + readTrailer15(password); this.buf.position(pos14); } @@ -1216,90 +1216,90 @@ private void readTrailer15(PDFPassword password) PDFAuthenticationFailureException, EncryptionUnsupportedByProductException, EncryptionUnsupportedByPlatformException { - + // the table of xrefs // objIdx is initialized from readTrailer(), do not overwrite here data from hybrid PDFs // objIdx = new PDFXref[50]; PDFDecrypter newDefaultDecrypter = null; while (true) { - PDFObject xrefObj = readObject(-1, -1, IdentityDecrypter.getInstance()); - if (xrefObj == null) { - break; - } - HashMap trailerdict = xrefObj.getDictionary(); - if (trailerdict == null) { - break; - } - PDFObject pdfObject = trailerdict.get("W"); - if (pdfObject == null) { - break; - } - PDFObject[] wNums = pdfObject.getArray(); - int l1 = wNums[0].getIntValue(); - int l2 = wNums[1].getIntValue(); - int l3 = wNums[2].getIntValue(); - - int size = trailerdict.get("Size").getIntValue(); - - byte[] strmbuf = xrefObj.getStream(); - int strmPos = 0; - - PDFObject idxNums = trailerdict.get("Index"); - int[] idxArray; - if (idxNums == null) { - idxArray = new int[]{0, size}; - } - else { - PDFObject[] idxNumArr = idxNums.getArray(); - idxArray = new int[idxNumArr.length]; - for (int i = 0; i < idxNumArr.length; i++) { - idxArray[i] = idxNumArr[i].getIntValue(); - } - } - int idxLen = idxArray.length; - int idxPos = 0; - - - while (idxPos= this.objIdx.length) { - PDFXref nobjIdx[] = new PDFXref[refstart + reflen]; - System.arraycopy(this.objIdx, 0, nobjIdx, 0, this.objIdx.length); - this.objIdx = nobjIdx; - } - - // read reference lines - for (int refID = refstart; refID < refstart + reflen; refID++) { - - int type = readNum(strmbuf, strmPos, l1); - strmPos += l1; - int id = readNum(strmbuf, strmPos, l2); - strmPos += l2; - int gen = readNum(strmbuf, strmPos, l3); - strmPos += l3; - - // ignore this line if the object ID is already defined - if (this.objIdx[refID] != null) { - continue; - } - - // see if it's an active object - if (type == 0) { // inactive - this.objIdx[refID] = new PDFXref(null); - } else if (type == 1) { // active uncompressed - this.objIdx[refID] = new PDFXref(id, gen); - } else { // active compressed - this.objIdx[refID] = new PDFXref(id, gen, true); - } - - } - } - - // read the root object location + PDFObject xrefObj = readObject(-1, -1, IdentityDecrypter.getInstance()); + if (xrefObj == null) { + break; + } + HashMap trailerdict = xrefObj.getDictionary(); + if (trailerdict == null) { + break; + } + PDFObject pdfObject = trailerdict.get("W"); + if (pdfObject == null) { + break; + } + PDFObject[] wNums = pdfObject.getArray(); + int l1 = wNums[0].getIntValue(); + int l2 = wNums[1].getIntValue(); + int l3 = wNums[2].getIntValue(); + + int size = trailerdict.get("Size").getIntValue(); + + byte[] strmbuf = xrefObj.getStream(); + int strmPos = 0; + + PDFObject idxNums = trailerdict.get("Index"); + int[] idxArray; + if (idxNums == null) { + idxArray = new int[]{0, size}; + } + else { + PDFObject[] idxNumArr = idxNums.getArray(); + idxArray = new int[idxNumArr.length]; + for (int i = 0; i < idxNumArr.length; i++) { + idxArray[i] = idxNumArr[i].getIntValue(); + } + } + int idxLen = idxArray.length; + int idxPos = 0; + + + while (idxPos= this.objIdx.length) { + PDFXref nobjIdx[] = new PDFXref[refstart + reflen]; + System.arraycopy(this.objIdx, 0, nobjIdx, 0, this.objIdx.length); + this.objIdx = nobjIdx; + } + + // read reference lines + for (int refID = refstart; refID < refstart + reflen; refID++) { + + int type = readNum(strmbuf, strmPos, l1); + strmPos += l1; + int id = readNum(strmbuf, strmPos, l2); + strmPos += l2; + int gen = readNum(strmbuf, strmPos, l3); + strmPos += l3; + + // ignore this line if the object ID is already defined + if (this.objIdx[refID] != null) { + continue; + } + + // see if it's an active object + if (type == 0) { // inactive + this.objIdx[refID] = new PDFXref(null); + } else if (type == 1) { // active uncompressed + this.objIdx[refID] = new PDFXref(id, gen); + } else { // active compressed + this.objIdx[refID] = new PDFXref(id, gen, true); + } + + } + } + + // read the root object location if (this.root == null) { this.root = trailerdict.get("Root"); if (this.root != null) { @@ -1375,13 +1375,13 @@ private void readTrailer15(PDFPassword password) } private int readNum(byte[] sbuf, int pos, int numBytes) { - int result = 0; - for (int i=0; i resources, boolean useAsSMask) - 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: - // [PATCHED by XOND] - switched colors in case the image is used as - // SMask for another image, otherwise transparency isn't - // handled correctly. - Color[] colors = useAsSMask ? new Color[] { Color.WHITE, Color.BLACK } - : new Color[] { Color.BLACK, Color.WHITE }; - PDFObject imageMaskDecode = obj.getDictRef("Decode"); - if (imageMaskDecode != null) { - PDFObject[] decodeArray = imageMaskDecode.getArray(); - float decode0 = decodeArray[0].getFloatValue(); - if (decode0 == 1.0f) { - colors = useAsSMask ? new Color[] { Color.BLACK, Color.WHITE } - : new Color[] { Color.WHITE, Color.BLACK }; - } - - /* - * float[] decode = new float[decodeArray.length]; for (int i = - * 0; i < decodeArray.length; i++) { decode[i] = - * decodeArray[i].getFloatValue(); } image.setDecode(decode); - */ - } - - 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.) - 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, true); - image.setSMask(sMaskImage); - } catch (IOException ex) { - PDFDebugger.debug("ERROR: there was a problem parsing the mask for this object"); - PDFDebugger.dump(obj); - BaseWatchable.getErrorHandler().publishException(ex); - } - } 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) { - PDFDebugger.debug("ERROR: there was a problem parsing the color mask for this object"); - PDFDebugger.dump(obj); - BaseWatchable.getErrorHandler().publishException(ex); - } - } - } - } - - return image; - } - - /** - * Get the image that this PDFImage generates. - * - * @return a buffered image containing the decoded image data - * @throws PDFImageParseException - */ - public BufferedImage getImage() throws PDFImageParseException { - try { - BufferedImage bi = (BufferedImage) this.imageObj.getCache(); - - if (bi == null) { - byte[] data = imageObj.getStream(); - ByteBuffer jpegBytes = null; - if (this.jpegDecode) { - // if we're lucky, the stream will have just the DCT - // filter applied to it, and we'll have a reference to - // an underlying mapped file, so we'll manage to avoid - // a copy of the encoded JPEG bytes - jpegBytes = imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS); - } - // parse the stream data into an actual image - bi = parseData(data, jpegBytes); - this.imageObj.setCache(bi); - } - return bi; - } catch (IOException ioe) { - // let the caller know that there was a problem parsing the image - throw new PDFImageParseException("Error reading image: "+ioe.getMessage(), ioe); - } - } - - /** - *

- * 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.

RGB - // transformation when reading JPEGs does not adhere to the spec. - // We're just going to let java read this in - as it is, the - // standard - // jpeg reader looks for the specific Adobe marker header so that - // it may apply the transform, so that's good. If that marker - // isn't present, then it also applies a number of other heuristics - // to determine whether the transform should be applied. - // (http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html) - // In practice, it probably almost always does the right thing here, - // though note that the present or default value of the - // ColorTransform - // dictionary entry is not being observed, so there is scope for - // error. Hopefully the JAI reader does the same. - - // We might need to attempt this with multiple readers, so let's - // remember where the jpeg data starts - jpegData.mark(); - - JpegDecoder decoder = new JpegDecoder(jpegData, cm); - - IOException decodeEx = null; - try { - bi = decoder.decode(); - } catch (IOException e) { - decodeEx = e; - // The native readers weren't able to process the image. - // One common situation is that the image is YCCK/CMYK encoded, - // which isn't supported by the default jpeg readers. - // We've got a work-around we can attempt, though: - decoder.ycckcmykDecodeMode(true); - try { - bi = decoder.decode(); - } catch (IOException e2) { - // It probably wasn't the YCCK/CMYK issue! - // try the "old" implementation - bi = parseData(data, null); - return bi; - } - } - - // the decoder may have requested installation of a new color model - cm = decoder.getColorModel(); - - // make these immediately unreachable, as the referenced - // jpeg data might be quite large - jpegData = null; - decoder = null; - - if (bi == null) { - // This isn't pretty, but it's what's been happening - // previously, so we'll preserve it for the time - // being. At least we'll offer a hint now! - assert decodeEx != null; - throw new IOException(decodeEx.getMessage() + ". Maybe installing JAI for expanded image format " - + "support would help?", decodeEx); - } - } else { - // create the data buffer - DataBuffer db = new DataBufferByte(data, data.length); - - // pick a color model, based on the number of components and - // bits per component - cm = getColorModel(); - - // create a compatible raster - SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); - WritableRaster raster; - try { - raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); - } catch (RasterFormatException e) { - int tempExpectedSize = getWidth() * getHeight() * getColorSpace().getNumComponents() - * Math.max(8, getBitsPerComponent()) / 8; - - if (tempExpectedSize < 3) { - tempExpectedSize = 3; - } - if (tempExpectedSize > 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 (?) - */ - 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 if (cm.getPixelSize() == 1 && cm.getNumComponents() == 1) { - // If the image is black and white only, convert it into - // BYTE_GRAY - // format - // This is a lot faster compared to just drawing the original - // image - - // Are pixels decoded? - int[] cc = new int[] { 0, 1 }; - PDFObject o = imageObj.getDictRef("Decode"); - if (o != null && o.getAt(0) != null) { - cc[0] = o.getAt(0).getIntValue(); - cc[1] = o.getAt(1).getIntValue(); - } - - final byte[] ncc = new byte[] { (byte) -cc[0], (byte) -cc[1] }; - - bi = biColorToGrayscale(raster, ncc); - // Return when there is no SMask - if (getSMask() == null) - return bi; - } else { - // Raster is already in a format which is supported by Java2D, - // such as RGB or Gray. - bi = new BufferedImage(cm, raster, true, null); - } - } - - // hack to avoid *very* slow conversion - ColorSpace cs = cm.getColorSpace(); - ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); - if (isGreyscale(cs) && bpc <= 8 && getDecode() == null && jpegData == null - && Configuration.getInstance().isConvertGreyscaleImagesToArgb()) { - bi = convertGreyscaleToArgb(data, bi); - } else if (!isImageMask() && cs instanceof ICC_ColorSpace && !cs.equals(rgbCS) - && !Configuration.getInstance().isAvoidColorConvertOp()) { - ColorConvertOp op = new ColorConvertOp(cs, rgbCS, null); - - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - - bi = op.filter(bi, converted); - } - else if (cs.getType() == ColorSpace.TYPE_CMYK) { - // convert to ARGB for faster drawing without ColorConvertOp - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D graphics = converted.createGraphics(); - graphics.drawImage(bi,0,0,null); - graphics.dispose(); - bi = converted; - } - - // add in the alpha data supplied by the SMask, if any - PDFImage sMaskImage = getSMask(); - if (sMaskImage != null) { - BufferedImage si = null; - try { - int w = bi.getWidth(); - int h = bi.getHeight(); - // if the bitmap is only a few pixels it just defines the color - boolean maskOnly = (w <= 2); - if (maskOnly) { - // use size of mask - si = sMaskImage.getImage(); - w = si.getWidth(); - h = si.getHeight(); - } - else if (sMaskImage.getHeight() != h && sMaskImage.getWidth() != w) { - // in case the two images do not have the same size, scale - if (sMaskImage.getHeight()*sMaskImage.getWidth() > w*h) { - // upscale image - si = sMaskImage.getImage(); - w = si.getWidth(); - h = si.getHeight(); - int hints = Image.SCALE_FAST; - Image scaledInstance = bi.getScaledInstance(w, h, hints ); - bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics graphics = bi.createGraphics(); - graphics.drawImage(scaledInstance, 0, 0, null); - graphics.dispose(); - } - else { - // upscale mask - si = scaleSMaskImage(sMaskImage); - } - } - else { - si = sMaskImage.getImage(); - } - PDFDebugger.debugImage(si, "smask" + this.imageObj.getObjNum()); - - BufferedImage outImage = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB); - PDFDebugger.debugImage(si, "outImage" + this.imageObj.getObjNum()); - int[] srcArray = new int[w]; - int[] maskArray = new int[w]; + private static int[][] GREY_TO_ARGB = new int[8][]; + + /** + * 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 final PDFObject imageObj; + /** true if the image is in encoded in JPEG*/ + private final boolean jpegDecode; - for (int i = 0; i < h; i++) { - if (maskOnly) { - // use first pixel color from image - Arrays.fill(srcArray, bi.getRGB(0,0)); - } - else { - // pixel row from image - bi.getRGB(0, i, w, 1, srcArray, 0, w); - } - // pixel row from mask - si.getRGB(0, i, w, 1, maskArray, 0, w); + /** + * Create an instance of a PDFImage + * @throws IOException if {@link PDFDecoder} throws one while evaluating if the image is a Jpeg + */ + protected PDFImage(PDFObject imageObj) throws IOException { + this.imageObj = imageObj; + this.jpegDecode = PDFDecoder.isLastFilter(imageObj, PDFDecoder.DCT_FILTERS); + } + + /** + * 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 + * @param useAsSMask + * - flag for switching colors in case image is used as sMask + * internally this is needed for handling transparency in smask + * images. + */ + public static PDFImage createImage(PDFObject obj, Map resources, boolean useAsSMask) + 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: + // [PATCHED by XOND] - switched colors in case the image is used as + // SMask for another image, otherwise transparency isn't + // handled correctly. + Color[] colors = useAsSMask ? new Color[] { Color.WHITE, Color.BLACK } + : new Color[] { Color.BLACK, Color.WHITE }; + PDFObject imageMaskDecode = obj.getDictRef("Decode"); + if (imageMaskDecode != null) { + PDFObject[] decodeArray = imageMaskDecode.getArray(); + float decode0 = decodeArray[0].getFloatValue(); + if (decode0 == 1.0f) { + colors = useAsSMask ? new Color[] { Color.BLACK, Color.WHITE } + : new Color[] { Color.WHITE, Color.BLACK }; + } + + /* + * float[] decode = new float[decodeArray.length]; for (int i = + * 0; i < decodeArray.length; i++) { decode[i] = + * decodeArray[i].getFloatValue(); } image.setDecode(decode); + */ + } + + 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.) + 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, true); + image.setSMask(sMaskImage); + } catch (IOException ex) { + PDFDebugger.debug("ERROR: there was a problem parsing the mask for this object"); + PDFDebugger.dump(obj); + BaseWatchable.getErrorHandler().publishException(ex); + } + } 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) { + PDFDebugger.debug("ERROR: there was a problem parsing the color mask for this object"); + PDFDebugger.dump(obj); + BaseWatchable.getErrorHandler().publishException(ex); + } + } + } + } + + return image; + } + + /** + * Get the image that this PDFImage generates. + * + * @return a buffered image containing the decoded image data + * @throws PDFImageParseException + */ + public BufferedImage getImage() throws PDFImageParseException { + try { + BufferedImage bi = (BufferedImage) this.imageObj.getCache(); + + if (bi == null) { + byte[] data = imageObj.getStream(); + ByteBuffer jpegBytes = null; + if (this.jpegDecode) { + // if we're lucky, the stream will have just the DCT + // filter applied to it, and we'll have a reference to + // an underlying mapped file, so we'll manage to avoid + // a copy of the encoded JPEG bytes + jpegBytes = imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS); + } + // parse the stream data into an actual image + bi = parseData(data, jpegBytes); + this.imageObj.setCache(bi); + } + return bi; + } catch (IOException ioe) { + // let the caller know that there was a problem parsing the image + throw new PDFImageParseException("Error reading image: "+ioe.getMessage(), ioe); + } + } + + /** + *

+ * 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.

RGB + // transformation when reading JPEGs does not adhere to the spec. + // We're just going to let java read this in - as it is, the + // standard + // jpeg reader looks for the specific Adobe marker header so that + // it may apply the transform, so that's good. If that marker + // isn't present, then it also applies a number of other heuristics + // to determine whether the transform should be applied. + // (http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html) + // In practice, it probably almost always does the right thing here, + // though note that the present or default value of the + // ColorTransform + // dictionary entry is not being observed, so there is scope for + // error. Hopefully the JAI reader does the same. + + // We might need to attempt this with multiple readers, so let's + // remember where the jpeg data starts + jpegData.mark(); + + JpegDecoder decoder = new JpegDecoder(jpegData, cm); + + IOException decodeEx = null; + try { + bi = decoder.decode(); + } catch (IOException e) { + decodeEx = e; + // The native readers weren't able to process the image. + // One common situation is that the image is YCCK/CMYK encoded, + // which isn't supported by the default jpeg readers. + // We've got a work-around we can attempt, though: + decoder.ycckcmykDecodeMode(true); + try { + bi = decoder.decode(); + } catch (IOException e2) { + // It probably wasn't the YCCK/CMYK issue! + // try the "old" implementation + bi = parseData(data, null); + return bi; + } + } + + // the decoder may have requested installation of a new color model + cm = decoder.getColorModel(); + + // make these immediately unreachable, as the referenced + // jpeg data might be quite large + jpegData = null; + decoder = null; + + if (bi == null) { + // This isn't pretty, but it's what's been happening + // previously, so we'll preserve it for the time + // being. At least we'll offer a hint now! + assert decodeEx != null; + throw new IOException(decodeEx.getMessage() + ". Maybe installing JAI for expanded image format " + + "support would help?", decodeEx); + } + } else { + // create the data buffer + DataBuffer db = new DataBufferByte(data, data.length); + + // pick a color model, based on the number of components and + // bits per component + cm = getColorModel(); + + // create a compatible raster + SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); + WritableRaster raster; + try { + raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); + } catch (RasterFormatException e) { + int tempExpectedSize = getWidth() * getHeight() * getColorSpace().getNumComponents() + * Math.max(8, getBitsPerComponent()) / 8; + + if (tempExpectedSize < 3) { + tempExpectedSize = 3; + } + if (tempExpectedSize > 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 (?) + */ + 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 if (cm.getPixelSize() == 1 && cm.getNumComponents() == 1) { + // If the image is black and white only, convert it into + // BYTE_GRAY + // format + // This is a lot faster compared to just drawing the original + // image + + // Are pixels decoded? + int[] cc = new int[] { 0, 1 }; + PDFObject o = imageObj.getDictRef("Decode"); + if (o != null && o.getAt(0) != null) { + cc[0] = o.getAt(0).getIntValue(); + cc[1] = o.getAt(1).getIntValue(); + } + + final byte[] ncc = new byte[] { (byte) -cc[0], (byte) -cc[1] }; + + bi = biColorToGrayscale(raster, ncc); + // Return when there is no SMask + if (getSMask() == null) + return bi; + } else { + // Raster is already in a format which is supported by Java2D, + // such as RGB or Gray. + bi = new BufferedImage(cm, raster, true, null); + } + } + + // hack to avoid *very* slow conversion + ColorSpace cs = cm.getColorSpace(); + ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + if (isGreyscale(cs) && bpc <= 8 && getDecode() == null && jpegData == null + && Configuration.getInstance().isConvertGreyscaleImagesToArgb()) { + bi = convertGreyscaleToArgb(data, bi); + } else if (!isImageMask() && cs instanceof ICC_ColorSpace && !cs.equals(rgbCS) + && !Configuration.getInstance().isAvoidColorConvertOp()) { + ColorConvertOp op = new ColorConvertOp(cs, rgbCS, null); + + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); + + bi = op.filter(bi, converted); + } + else if (cs.getType() == ColorSpace.TYPE_CMYK) { + // convert to ARGB for faster drawing without ColorConvertOp + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = converted.createGraphics(); + graphics.drawImage(bi,0,0,null); + graphics.dispose(); + bi = converted; + } + + // add in the alpha data supplied by the SMask, if any + PDFImage sMaskImage = getSMask(); + if (sMaskImage != null) { + BufferedImage si = null; + try { + int w = bi.getWidth(); + int h = bi.getHeight(); + // if the bitmap is only a few pixels it just defines the color + boolean maskOnly = (w <= 2); + if (maskOnly) { + // use size of mask + si = sMaskImage.getImage(); + w = si.getWidth(); + h = si.getHeight(); + } + else if (sMaskImage.getHeight() != h && sMaskImage.getWidth() != w) { + // in case the two images do not have the same size, scale + if (sMaskImage.getHeight()*sMaskImage.getWidth() > w*h) { + // upscale image + si = sMaskImage.getImage(); + w = si.getWidth(); + h = si.getHeight(); + int hints = Image.SCALE_FAST; + Image scaledInstance = bi.getScaledInstance(w, h, hints ); + bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics graphics = bi.createGraphics(); + graphics.drawImage(scaledInstance, 0, 0, null); + graphics.dispose(); + } + else { + // upscale mask + si = scaleSMaskImage(sMaskImage); + } + } + else { + si = sMaskImage.getImage(); + } + PDFDebugger.debugImage(si, "smask" + this.imageObj.getObjNum()); + + BufferedImage outImage = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB); + PDFDebugger.debugImage(si, "outImage" + this.imageObj.getObjNum()); + int[] srcArray = new int[w]; + int[] maskArray = new int[w]; - for (int j = 0; j < w; j++) { - int ac = 0xff000000; - // alpha from mask with color from image - maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); - } - // write pixel row - outImage.setRGB(0, i, w, 1, maskArray, 0, w); - } + for (int i = 0; i < h; i++) { + if (maskOnly) { + // use first pixel color from image + Arrays.fill(srcArray, bi.getRGB(0,0)); + } + else { + // pixel row from image + bi.getRGB(0, i, w, 1, srcArray, 0, w); + } + // pixel row from mask + si.getRGB(0, i, w, 1, maskArray, 0, w); - bi = outImage; + for (int j = 0; j < w; j++) { + int ac = 0xff000000; + // alpha from mask with color from image + maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); + } + // write pixel row + outImage.setRGB(0, i, w, 1, maskArray, 0, w); + } + + bi = outImage; } catch (PDFImageParseException e) { PDFDebugger.debug("Error parsing sMask image caused by:" + e.getMessage(), 100); } - } - - PDFDebugger.debugImage(bi, "result" + this.imageObj.getObjNum()); - return bi; - } - - /** - * Scale the softmask image to the size of the actual image - * - * @param sMaskImage - * @return - * @throws PDFImageParseException - */ - private BufferedImage scaleSMaskImage(PDFImage sMaskImage) throws PDFImageParseException { - BufferedImage before = sMaskImage.getImage(); - int w = before.getWidth(); - int h = before.getHeight(); - - if (PDFDebugger.DEBUG_IMAGES) { - PDFDebugger.debug("Scaling image from " + w + "/" + h + " to " + this.width + "/" + this.height); - } - BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - AffineTransform at = new AffineTransform(); - - at.scale(((double) this.width / w), ((double) this.height / h)); - - AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); - return scaleOp.filter(before, after); - } - - private boolean isGreyscale(ColorSpace aCs) { - return aCs == PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); - } - - private BufferedImage convertGreyscaleToArgb(byte[] data, BufferedImage bi) { - // we use an optimised greyscale colour conversion, as with scanned - // greyscale/mono documents consisting of nothing but page-size - // images, using the ICC converter is perhaps 15 times slower than this - // method. Using an example scanned, mainly monochrome document, on this - // developer's machine pages took an average of 3s to render using the - // ICC converter filter, and around 115ms using this method. We use - // pre-calculated tables generated using the ICC converter to map - // between - // each possible greyscale value and its desired value in sRGB. - // We also try to avoid going through SampleModels, WritableRasters or - // BufferedImages as that takes about 3 times as long. - final int[] convertedPixels = new int[getWidth() * getHeight()]; - final WritableRaster r = bi.getRaster(); - int i = 0; - final int[] greyToArgbMap = getGreyToArgbMap(bpc); - if (bpc == 1) { - int calculatedLineBytes = (getWidth() + 7) / 8; - int rowStartByteIndex; - // avoid hitting the WritableRaster for the common 1 bpc case - if (greyToArgbMap[0] == 0 && greyToArgbMap[1] == 0xFFFFFFFF) { - // optimisation for common case of a direct map to full white - // and black, using bit twiddling instead of consulting the - // greyToArgb map - for (int y = 0; y < getHeight(); ++y) { - // each row is byte-aligned - rowStartByteIndex = y * calculatedLineBytes; - for (int x = 0; x < getWidth(); ++x) { - final byte b = data[rowStartByteIndex + x / 8]; - final int white = b >> (7 - (x & 7)) & 1; - // if white == 0, white - 1 will be 0xFFFFFFFF, - // which when xored with 0xFFFFFF will produce 0 - // if white == 1, white - 1 will be 0, - // which when xored with 0xFFFFFF will produce 0xFFFFFF - // (ignoring the top two bytes, which are always set - // high anyway) - convertedPixels[i] = 0xFF000000 | ((white - 1) ^ 0xFFFFFF); - ++i; - } - } - } else { - // 1 bpc case where we can't bit-twiddle and need to consult - // the map - for (int y = 0; y < getHeight(); ++y) { - rowStartByteIndex = y * calculatedLineBytes; - for (int x = 0; x < getWidth(); ++x) { - final byte b = data[rowStartByteIndex + x / 8]; - final int val = b >> (7 - (x & 7)) & 1; - convertedPixels[i] = greyToArgbMap[val]; - ++i; - } - } - } - } else { - for (int y = 0; y < getHeight(); ++y) { - for (int x = 0; x < getWidth(); ++x) { - final int greyscale = r.getSample(x, y, 0); - convertedPixels[i] = greyToArgbMap[greyscale]; - ++i; - } - } - } - - final ColorModel ccm = ColorModel.getRGBdefault(); - return new BufferedImage(ccm, - Raster.createPackedRaster(new DataBufferInt(convertedPixels, convertedPixels.length), getWidth(), - getHeight(), getWidth(), ((PackedColorModel) ccm).getMasks(), null), - false, null); - } - - private static int[] getGreyToArgbMap(int numBits) { - assert numBits <= 8; - int[] argbVals = GREY_TO_ARGB[numBits - 1]; - if (argbVals == null) { - argbVals = createGreyToArgbMap(numBits); - } - return argbVals; - } - - /** - * Create a map from all bit-patterns of a certain depth greyscale to the - * corresponding sRGB values via the ICC colorr converter. - * - * @param numBits - * the number of greyscale bits - * @return a 2^bits array of standard 32-bit ARGB fits for each greyscale - * value at that bitdepth - */ - private static int[] createGreyToArgbMap(int numBits) { - final ColorSpace greyCs = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); - - byte[] greyVals = new byte[1 << numBits]; - for (int i = 0; i < greyVals.length; ++i) { - greyVals[i] = (byte) (i & 0xFF); - } - - final int[] argbVals = new int[greyVals.length]; - final int mask = (1 << numBits) - 1; - final WritableRaster inRaster = Raster.createPackedRaster(new DataBufferByte(greyVals, greyVals.length), - greyVals.length, 1, greyVals.length, new int[] { mask }, null); - - final BufferedImage greyImage = new BufferedImage(new PdfComponentColorModel(greyCs, new int[] { numBits }), - inRaster, false, null); - - final ColorModel ccm = ColorModel.getRGBdefault(); - final WritableRaster outRaster = Raster.createPackedRaster(new DataBufferInt(argbVals, argbVals.length), - argbVals.length, 1, argbVals.length, ((PackedColorModel) ccm).getMasks(), null); - final BufferedImage srgbImage = new BufferedImage(ccm, outRaster, false, null); - - final ColorConvertOp op = new ColorConvertOp(greyCs, ColorSpace.getInstance(ColorSpace.CS_sRGB), null); - - op.filter(greyImage, srgbImage); - - GREY_TO_ARGB[numBits - 1] = argbVals; - return argbVals; - } - - /** - * Creates a new image of type {@link TYPE_BYTE_GRAY} which represents the - * given raster - * - * @param raster - * Raster of an image with just two colors, bitwise encoded - * @param ncc - * Array with two entries that describe the corresponding gray - * values - */ - private BufferedImage biColorToGrayscale(final WritableRaster raster, final byte[] ncc) { - - final byte[] bufferO = ((DataBufferByte) raster.getDataBuffer()).getData(); - - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY); - - byte[] buffer = ((DataBufferByte) converted.getRaster().getDataBuffer()).getData(); - int i = 0; - final int height = converted.getHeight(); - final int width = converted.getWidth(); - for (int y = 0; y < height; y++) { - int base = y * width + 7; - if ((y + 1) * width < buffer.length) { - for (int x = 0; x < width; x += 8) { - final byte bits = bufferO[i]; - i++; - for (byte j = 7; j >= 0; j--) { - if (buffer.length <= (base - j)) { - break; - } - final int c = ((bits >>> j) & 1); - buffer[base - j] = ncc[c]; - } - base += 8; - } - } else { - for (int x = 0; x < width; x += 8) { - final byte bits = bufferO[i]; - i++; - for (byte j = 7; j >= 0; j--) { - if (base - j >= buffer.length) - break; - buffer[base - j] = ncc[((bits >>> j) & 1)]; - } - base += 8; - } - } - } - return converted; - } - - /** - * Get the image's width - */ - public int getWidth() { - return this.width; - } - - /** - * Set the image's width - */ - protected void setWidth(int width) { - this.width = width; - } - - /** - * Get the image's height - */ - public int getHeight() { - return this.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(); - this.colorKeyMask = null; - int[] masks = new int[maskObjects.length]; - for (int i = 0; i < masks.length; i++) { - masks[i] = maskObjects[i].getIntValue(); - } - this.colorKeyMask = masks; - } - - /** - * Get the colorspace associated with this image, or null if there isn't one - */ - protected PDFColorSpace getColorSpace() { - return this.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 this.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 this.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 this.sMask; - } - - /** - * Set the soft mask image - */ - protected void setSMask(PDFImage sMask) { - this.sMask = sMask; - } - - /** - * Get the decode array - */ - protected float[] getDecode() { - return this.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 (this.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 (this.colorKeyMask == null || this.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 < this.colorKeyMask.length; i += 2) { - for (int j = this.colorKeyMask[i]; j <= this.colorKeyMask[i + 1]; j++) { - aComps[(j * 4) + 3] = 0; // make transparent - } - } - return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); - } - } else if (cs instanceof AlternateColorSpace) { - // ColorSpace altCS = new AltColorSpace(((AlternateColorSpace) - // cs).getFunktion(), cs.getColorSpace()); - ColorSpace altCS = cs.getColorSpace(); - int[] bits = new int[altCS.getNumComponents()]; - for (int i = 0; i < bits.length; i++) { - bits[i] = getBitsPerComponent(); - } - return new DecodeComponentColorModel(altCS, bits); - } else { - // If the image is a JPEG, then CMYK color space has been converted to RGB in DCTDecode - if (this.jpegDecode && cs.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { - ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] bits = new int[rgbCS.getNumComponents()]; - for (int i = 0; i < bits.length; i++) { - bits[i] = getBitsPerComponent(); - } - return new DecodeComponentColorModel(rgbCS, bits); - } - ColorSpace colorSpace = cs.getColorSpace(); - int[] bits = new int[colorSpace.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) { - this.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); - } - } - - /** - * 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 createColorModel() { - 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 decode != null ? new DecodeComponentColorModel(cs.getColorSpace(), bits) - : new PdfComponentColorModel(cs.getColorSpace(), bits); - } - } - - /** - * Decodes jpeg data, possibly attempting a manual YCCK decode if requested. - * Users should use {@link #getColorModel()} to see which color model should - * now be used after a successful decode. - */ - private class JpegDecoder { - /** The jpeg bytes */ - private final ByteBuffer jpegData; - /** The color model employed */ - private ColorModel cm; - /** Whether the YCCK/CMYK decode work-around should be used */ - private boolean ycckcmykDecodeMode = false; - - /** - * Class constructor - * - * @param jpegData - * the JPEG data - * @param cm - * the color model as presented in the PDF - */ - private JpegDecoder(ByteBuffer jpegData, ColorModel cm) { - this.jpegData = jpegData; - this.cm = cm; - } - - /** - * Identify whether the decoder should operate in YCCK/CMYK decode mode, - * whereby the YCCK Chroma is specifically looked for and the color - * model is changed to support converting raw YCCK color values, working - * around a lack of YCCK/CMYK report in the standard Java jpeg readers. - * Non-YCCK images will not be decoded while in this mode. - * - * @param ycckcmykDecodeMode - */ - public void ycckcmykDecodeMode(boolean ycckcmykDecodeMode) { - this.ycckcmykDecodeMode = ycckcmykDecodeMode; - } - - /** - * Get the color model that should be used now - * - * @return - */ - public ColorModel getColorModel() { - return cm; - } - - /** - * Attempt to decode the jpeg data - * - * @return the successfully decoded image - * @throws IOException - * if the image couldn't be decoded due to a lack of support - * or some IO problem - */ + } + + PDFDebugger.debugImage(bi, "result" + this.imageObj.getObjNum()); + return bi; + } + + /** + * Scale the softmask image to the size of the actual image + * + * @param sMaskImage + * @return + * @throws PDFImageParseException + */ + private BufferedImage scaleSMaskImage(PDFImage sMaskImage) throws PDFImageParseException { + BufferedImage before = sMaskImage.getImage(); + int w = before.getWidth(); + int h = before.getHeight(); + + if (PDFDebugger.DEBUG_IMAGES) { + PDFDebugger.debug("Scaling image from " + w + "/" + h + " to " + this.width + "/" + this.height); + } + BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + AffineTransform at = new AffineTransform(); + + at.scale(((double) this.width / w), ((double) this.height / h)); + + AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); + return scaleOp.filter(before, after); + } + + private boolean isGreyscale(ColorSpace aCs) { + return aCs == PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + } + + private BufferedImage convertGreyscaleToArgb(byte[] data, BufferedImage bi) { + // we use an optimised greyscale colour conversion, as with scanned + // greyscale/mono documents consisting of nothing but page-size + // images, using the ICC converter is perhaps 15 times slower than this + // method. Using an example scanned, mainly monochrome document, on this + // developer's machine pages took an average of 3s to render using the + // ICC converter filter, and around 115ms using this method. We use + // pre-calculated tables generated using the ICC converter to map + // between + // each possible greyscale value and its desired value in sRGB. + // We also try to avoid going through SampleModels, WritableRasters or + // BufferedImages as that takes about 3 times as long. + final int[] convertedPixels = new int[getWidth() * getHeight()]; + final WritableRaster r = bi.getRaster(); + int i = 0; + final int[] greyToArgbMap = getGreyToArgbMap(bpc); + if (bpc == 1) { + int calculatedLineBytes = (getWidth() + 7) / 8; + int rowStartByteIndex; + // avoid hitting the WritableRaster for the common 1 bpc case + if (greyToArgbMap[0] == 0 && greyToArgbMap[1] == 0xFFFFFFFF) { + // optimisation for common case of a direct map to full white + // and black, using bit twiddling instead of consulting the + // greyToArgb map + for (int y = 0; y < getHeight(); ++y) { + // each row is byte-aligned + rowStartByteIndex = y * calculatedLineBytes; + for (int x = 0; x < getWidth(); ++x) { + final byte b = data[rowStartByteIndex + x / 8]; + final int white = b >> (7 - (x & 7)) & 1; + // if white == 0, white - 1 will be 0xFFFFFFFF, + // which when xored with 0xFFFFFF will produce 0 + // if white == 1, white - 1 will be 0, + // which when xored with 0xFFFFFF will produce 0xFFFFFF + // (ignoring the top two bytes, which are always set + // high anyway) + convertedPixels[i] = 0xFF000000 | ((white - 1) ^ 0xFFFFFF); + ++i; + } + } + } else { + // 1 bpc case where we can't bit-twiddle and need to consult + // the map + for (int y = 0; y < getHeight(); ++y) { + rowStartByteIndex = y * calculatedLineBytes; + for (int x = 0; x < getWidth(); ++x) { + final byte b = data[rowStartByteIndex + x / 8]; + final int val = b >> (7 - (x & 7)) & 1; + convertedPixels[i] = greyToArgbMap[val]; + ++i; + } + } + } + } else { + for (int y = 0; y < getHeight(); ++y) { + for (int x = 0; x < getWidth(); ++x) { + final int greyscale = r.getSample(x, y, 0); + convertedPixels[i] = greyToArgbMap[greyscale]; + ++i; + } + } + } + + final ColorModel ccm = ColorModel.getRGBdefault(); + return new BufferedImage(ccm, + Raster.createPackedRaster(new DataBufferInt(convertedPixels, convertedPixels.length), getWidth(), + getHeight(), getWidth(), ((PackedColorModel) ccm).getMasks(), null), + false, null); + } + + private static int[] getGreyToArgbMap(int numBits) { + assert numBits <= 8; + int[] argbVals = GREY_TO_ARGB[numBits - 1]; + if (argbVals == null) { + argbVals = createGreyToArgbMap(numBits); + } + return argbVals; + } + + /** + * Create a map from all bit-patterns of a certain depth greyscale to the + * corresponding sRGB values via the ICC colorr converter. + * + * @param numBits + * the number of greyscale bits + * @return a 2^bits array of standard 32-bit ARGB fits for each greyscale + * value at that bitdepth + */ + private static int[] createGreyToArgbMap(int numBits) { + final ColorSpace greyCs = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + + byte[] greyVals = new byte[1 << numBits]; + for (int i = 0; i < greyVals.length; ++i) { + greyVals[i] = (byte) (i & 0xFF); + } + + final int[] argbVals = new int[greyVals.length]; + final int mask = (1 << numBits) - 1; + final WritableRaster inRaster = Raster.createPackedRaster(new DataBufferByte(greyVals, greyVals.length), + greyVals.length, 1, greyVals.length, new int[] { mask }, null); + + final BufferedImage greyImage = new BufferedImage(new PdfComponentColorModel(greyCs, new int[] { numBits }), + inRaster, false, null); + + final ColorModel ccm = ColorModel.getRGBdefault(); + final WritableRaster outRaster = Raster.createPackedRaster(new DataBufferInt(argbVals, argbVals.length), + argbVals.length, 1, argbVals.length, ((PackedColorModel) ccm).getMasks(), null); + final BufferedImage srgbImage = new BufferedImage(ccm, outRaster, false, null); + + final ColorConvertOp op = new ColorConvertOp(greyCs, ColorSpace.getInstance(ColorSpace.CS_sRGB), null); + + op.filter(greyImage, srgbImage); + + GREY_TO_ARGB[numBits - 1] = argbVals; + return argbVals; + } + + /** + * Creates a new image of type {@link TYPE_BYTE_GRAY} which represents the + * given raster + * + * @param raster + * Raster of an image with just two colors, bitwise encoded + * @param ncc + * Array with two entries that describe the corresponding gray + * values + */ + private BufferedImage biColorToGrayscale(final WritableRaster raster, final byte[] ncc) { + + final byte[] bufferO = ((DataBufferByte) raster.getDataBuffer()).getData(); + + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY); + + byte[] buffer = ((DataBufferByte) converted.getRaster().getDataBuffer()).getData(); + int i = 0; + final int height = converted.getHeight(); + final int width = converted.getWidth(); + for (int y = 0; y < height; y++) { + int base = y * width + 7; + if ((y + 1) * width < buffer.length) { + for (int x = 0; x < width; x += 8) { + final byte bits = bufferO[i]; + i++; + for (byte j = 7; j >= 0; j--) { + if (buffer.length <= (base - j)) { + break; + } + final int c = ((bits >>> j) & 1); + buffer[base - j] = ncc[c]; + } + base += 8; + } + } else { + for (int x = 0; x < width; x += 8) { + final byte bits = bufferO[i]; + i++; + for (byte j = 7; j >= 0; j--) { + if (base - j >= buffer.length) + break; + buffer[base - j] = ncc[((bits >>> j) & 1)]; + } + base += 8; + } + } + } + return converted; + } + + /** + * Get the image's width + */ + public int getWidth() { + return this.width; + } + + /** + * Set the image's width + */ + protected void setWidth(int width) { + this.width = width; + } + + /** + * Get the image's height + */ + public int getHeight() { + return this.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(); + this.colorKeyMask = null; + int[] masks = new int[maskObjects.length]; + for (int i = 0; i < masks.length; i++) { + masks[i] = maskObjects[i].getIntValue(); + } + this.colorKeyMask = masks; + } + + /** + * Get the colorspace associated with this image, or null if there isn't one + */ + protected PDFColorSpace getColorSpace() { + return this.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 this.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 this.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 this.sMask; + } + + /** + * Set the soft mask image + */ + protected void setSMask(PDFImage sMask) { + this.sMask = sMask; + } + + /** + * Get the decode array + */ + protected float[] getDecode() { + return this.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 (this.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 (this.colorKeyMask == null || this.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 < this.colorKeyMask.length; i += 2) { + for (int j = this.colorKeyMask[i]; j <= this.colorKeyMask[i + 1]; j++) { + aComps[(j * 4) + 3] = 0; // make transparent + } + } + return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); + } + } else if (cs instanceof AlternateColorSpace) { + // ColorSpace altCS = new AltColorSpace(((AlternateColorSpace) + // cs).getFunktion(), cs.getColorSpace()); + ColorSpace altCS = cs.getColorSpace(); + int[] bits = new int[altCS.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = getBitsPerComponent(); + } + return new DecodeComponentColorModel(altCS, bits); + } else { + // If the image is a JPEG, then CMYK color space has been converted to RGB in DCTDecode + if (this.jpegDecode && cs.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { + ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] bits = new int[rgbCS.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = getBitsPerComponent(); + } + return new DecodeComponentColorModel(rgbCS, bits); + } + ColorSpace colorSpace = cs.getColorSpace(); + int[] bits = new int[colorSpace.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) { + this.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); + } + } + + /** + * 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 createColorModel() { + 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 decode != null ? new DecodeComponentColorModel(cs.getColorSpace(), bits) + : new PdfComponentColorModel(cs.getColorSpace(), bits); + } + } + + /** + * Decodes jpeg data, possibly attempting a manual YCCK decode if requested. + * Users should use {@link #getColorModel()} to see which color model should + * now be used after a successful decode. + */ + private class JpegDecoder { + /** The jpeg bytes */ + private final ByteBuffer jpegData; + /** The color model employed */ + private ColorModel cm; + /** Whether the YCCK/CMYK decode work-around should be used */ + private boolean ycckcmykDecodeMode = false; + + /** + * Class constructor + * + * @param jpegData + * the JPEG data + * @param cm + * the color model as presented in the PDF + */ + private JpegDecoder(ByteBuffer jpegData, ColorModel cm) { + this.jpegData = jpegData; + this.cm = cm; + } + + /** + * Identify whether the decoder should operate in YCCK/CMYK decode mode, + * whereby the YCCK Chroma is specifically looked for and the color + * model is changed to support converting raw YCCK color values, working + * around a lack of YCCK/CMYK report in the standard Java jpeg readers. + * Non-YCCK images will not be decoded while in this mode. + * + * @param ycckcmykDecodeMode + */ + public void ycckcmykDecodeMode(boolean ycckcmykDecodeMode) { + this.ycckcmykDecodeMode = ycckcmykDecodeMode; + } + + /** + * Get the color model that should be used now + * + * @return + */ + public ColorModel getColorModel() { + return cm; + } + + /** + * Attempt to decode the jpeg data + * + * @return the successfully decoded image + * @throws IOException + * if the image couldn't be decoded due to a lack of support + * or some IO problem + */ private BufferedImage decode() throws IOException { byte[] jpegBytes = jpegData.hasArray() ? Arrays.copyOfRange(jpegData.array(), jpegData.position(), jpegData.limit()) @@ -1175,165 +1175,165 @@ private BufferedImage decode() throws IOException { } private BufferedImage readImage(ImageReader jpegReader, ImageReadParam param) throws IOException { - if (ycckcmykDecodeMode) { - // The standard Oracle Java JPEG readers can't deal with CMYK - // YCCK encoded images - // without a little help from us. We'll try and pick up such - // instances and work around it. - final IIOMetadata imageMeta = jpegReader.getImageMetadata(0); - if (imageMeta != null) { - final Node standardMeta = imageMeta.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); - if (standardMeta != null) { - final Node chroma = getChild(standardMeta, "Chroma"); - if (chroma != null) { - final Node csType = getChild(chroma, "ColorSpaceType"); - if (csType != null) { - final Attr csTypeNameNode = (Attr) csType.getAttributes().getNamedItem("name"); - if (csTypeNameNode != null) { - final String typeName = csTypeNameNode.getValue(); - final boolean YCCK; - if ((YCCK = "YCCK".equals(typeName)) || "CMYK".equals(typeName)) { - // If it's a YCCK image, then we can - // coax a workable image out of it - // by grabbing the raw raster and - // installing a YCCK converting - // color space wrapper around the - // existing (CMYK) color space; this - // will - // do the YCCK conversion for us - // - // If it's a CMYK image - just raster it - // in existing CMYK color space - - // first make sure we can get the - // unadjusted raster - final Raster raster = jpegReader.readRaster(0, param); - - if (YCCK) { - // and now use it with a YCCK - // converting color space. - PDFImage.this.colorSpace = new PDFColorSpace( - new YCCKColorSpace(colorSpace.getColorSpace())); - // re-calculate the color model - // since the color space has changed - cm = PDFImage.this.createColorModel(); - } - - return new BufferedImage(cm, Raster.createWritableRaster( - raster.getSampleModel(), raster.getDataBuffer(), null), true, null); - - } - } - } - } - } - } - - throw new IIOException("Neither YCCK nor CMYK image"); - - } else { - - if (param != null && param.getDestination() != null) { - // if we've already set up a destination image then we'll - // use it - return jpegReader.read(0, param); - } else { - // otherwise we'll create a new buffered image with the - // desired color model - //return new BufferedImage(cm, jpegReader.read(0, param).getRaster(), true, null); - BufferedImage bi = jpegReader.read(0, param); - try { - return new BufferedImage(cm, bi.getRaster(), true, null); - } catch (IllegalArgumentException raster_ByteInterleavedRaster) { - BufferedImage bi2 = new BufferedImage(bi.getWidth(), bi.getHeight(), - BufferedImage.TYPE_BYTE_INDEXED, - new IndexColorModel(8, 1, new byte[] { 0 }, new byte[] { 0 }, new byte[] { 0 }, 0)); - cm = bi2.getColorModel(); - return bi2; - } - } - } - - } - - /** - * Get a named child node - * - * @param aNode - * the node - * @param aChildName - * the name of the child node - * @return the first direct child node with that name or null if it - * doesn't exist - */ - private Node getChild(Node aNode, String aChildName) { - for (int i = 0; i < aNode.getChildNodes().getLength(); ++i) { - final Node child = aNode.getChildNodes().item(i); - if (child.getNodeName().equals(aChildName)) { - return child; - } - } - return null; - } - } - - /** - * A wrapper for ComponentColorSpace which normalizes based on the decode - * array. - */ - static class PdfComponentColorModel extends ComponentColorModel { - - int bitsPerComponent; - - public PdfComponentColorModel(ColorSpace cs, int[] bpc) { - super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - - pixel_bits = bpc.length * bpc[0]; - this.bitsPerComponent = bpc[0]; - } - - @Override - public SampleModel createCompatibleSampleModel(int width, int height) { - - if (bitsPerComponent >= 8) { - assert bitsPerComponent == 8 || bitsPerComponent == 16; - final int numComponents = getNumComponents(); - int[] bandOffsets = new int[numComponents]; - for (int i = 0; i < numComponents; i++) { - bandOffsets[i] = i; - } - return new PixelInterleavedSampleModel(getTransferType(), width, height, numComponents, - width * numComponents, bandOffsets); - } else { - switch (getPixelSize()) { - case 1: - case 2: - case 4: - // pixels don't span byte boundaries, so we can use the - // standard multi pixel - // packing, which offers a slight performance advantage over - // the other sample - // model, which must consider such cases. Given that sample - // model interactions - // can dominate processing, this small distinction is - // worthwhile - return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); - default: - // pixels will cross byte boundaries - assert getTransferType() == DataBuffer.TYPE_BYTE; - return new PdfSubByteSampleModel(width, height, getNumComponents(), bitsPerComponent); - } - } - } - - @Override - public boolean isCompatibleRaster(Raster raster) { - if (bitsPerComponent < 8 || getNumComponents() == 1) { - SampleModel sm = raster.getSampleModel(); - return sm.getSampleSize(0) == bitsPerComponent; - } - return super.isCompatibleRaster(raster); - } - - } + if (ycckcmykDecodeMode) { + // The standard Oracle Java JPEG readers can't deal with CMYK + // YCCK encoded images + // without a little help from us. We'll try and pick up such + // instances and work around it. + final IIOMetadata imageMeta = jpegReader.getImageMetadata(0); + if (imageMeta != null) { + final Node standardMeta = imageMeta.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); + if (standardMeta != null) { + final Node chroma = getChild(standardMeta, "Chroma"); + if (chroma != null) { + final Node csType = getChild(chroma, "ColorSpaceType"); + if (csType != null) { + final Attr csTypeNameNode = (Attr) csType.getAttributes().getNamedItem("name"); + if (csTypeNameNode != null) { + final String typeName = csTypeNameNode.getValue(); + final boolean YCCK; + if ((YCCK = "YCCK".equals(typeName)) || "CMYK".equals(typeName)) { + // If it's a YCCK image, then we can + // coax a workable image out of it + // by grabbing the raw raster and + // installing a YCCK converting + // color space wrapper around the + // existing (CMYK) color space; this + // will + // do the YCCK conversion for us + // + // If it's a CMYK image - just raster it + // in existing CMYK color space + + // first make sure we can get the + // unadjusted raster + final Raster raster = jpegReader.readRaster(0, param); + + if (YCCK) { + // and now use it with a YCCK + // converting color space. + PDFImage.this.colorSpace = new PDFColorSpace( + new YCCKColorSpace(colorSpace.getColorSpace())); + // re-calculate the color model + // since the color space has changed + cm = PDFImage.this.createColorModel(); + } + + return new BufferedImage(cm, Raster.createWritableRaster( + raster.getSampleModel(), raster.getDataBuffer(), null), true, null); + + } + } + } + } + } + } + + throw new IIOException("Neither YCCK nor CMYK image"); + + } else { + + if (param != null && param.getDestination() != null) { + // if we've already set up a destination image then we'll + // use it + return jpegReader.read(0, param); + } else { + // otherwise we'll create a new buffered image with the + // desired color model + //return new BufferedImage(cm, jpegReader.read(0, param).getRaster(), true, null); + BufferedImage bi = jpegReader.read(0, param); + try { + return new BufferedImage(cm, bi.getRaster(), true, null); + } catch (IllegalArgumentException raster_ByteInterleavedRaster) { + BufferedImage bi2 = new BufferedImage(bi.getWidth(), bi.getHeight(), + BufferedImage.TYPE_BYTE_INDEXED, + new IndexColorModel(8, 1, new byte[] { 0 }, new byte[] { 0 }, new byte[] { 0 }, 0)); + cm = bi2.getColorModel(); + return bi2; + } + } + } + + } + + /** + * Get a named child node + * + * @param aNode + * the node + * @param aChildName + * the name of the child node + * @return the first direct child node with that name or null if it + * doesn't exist + */ + private Node getChild(Node aNode, String aChildName) { + for (int i = 0; i < aNode.getChildNodes().getLength(); ++i) { + final Node child = aNode.getChildNodes().item(i); + if (child.getNodeName().equals(aChildName)) { + return child; + } + } + return null; + } + } + + /** + * A wrapper for ComponentColorSpace which normalizes based on the decode + * array. + */ + static class PdfComponentColorModel extends ComponentColorModel { + + int bitsPerComponent; + + public PdfComponentColorModel(ColorSpace cs, int[] bpc) { + super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + pixel_bits = bpc.length * bpc[0]; + this.bitsPerComponent = bpc[0]; + } + + @Override + public SampleModel createCompatibleSampleModel(int width, int height) { + + if (bitsPerComponent >= 8) { + assert bitsPerComponent == 8 || bitsPerComponent == 16; + final int numComponents = getNumComponents(); + int[] bandOffsets = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bandOffsets[i] = i; + } + return new PixelInterleavedSampleModel(getTransferType(), width, height, numComponents, + width * numComponents, bandOffsets); + } else { + switch (getPixelSize()) { + case 1: + case 2: + case 4: + // pixels don't span byte boundaries, so we can use the + // standard multi pixel + // packing, which offers a slight performance advantage over + // the other sample + // model, which must consider such cases. Given that sample + // model interactions + // can dominate processing, this small distinction is + // worthwhile + return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); + default: + // pixels will cross byte boundaries + assert getTransferType() == DataBuffer.TYPE_BYTE; + return new PdfSubByteSampleModel(width, height, getNumComponents(), bitsPerComponent); + } + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + if (bitsPerComponent < 8 || getNumComponents() == 1) { + SampleModel sm = raster.getSampleModel(); + return sm.getSampleSize(0) == bitsPerComponent; + } + return super.isCompatibleRaster(raster); + } + + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFObject.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFObject.java index ca76c8fff..1a3725abf 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFObject.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFObject.java @@ -206,8 +206,8 @@ public PDFObject(PDFFile owner, PDFXref xref) { * @throws IOException */ public String getDictRefAsString(String name) throws IOException { - PDFObject ref = getDictRef(name); - return ref == null ? null : ref.getStringValue(); + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getStringValue(); } /** @@ -217,8 +217,8 @@ public String getDictRefAsString(String name) throws IOException { * @throws IOException */ public Boolean getDictRefAsBoolean(String name) throws IOException { - PDFObject ref = getDictRef(name); - return ref == null ? null : ref.getBooleanValue(); + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getBooleanValue(); } /** @@ -228,8 +228,8 @@ public Boolean getDictRefAsBoolean(String name) throws IOException { * @throws IOException */ public Integer getDictRefAsInt(String name) throws IOException { - PDFObject ref = getDictRef(name); - return ref == null ? null : ref.getIntValue(); + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getIntValue(); } /** @@ -239,16 +239,16 @@ public Integer getDictRefAsInt(String name) throws IOException { * @throws IOException */ public int[] getDictRefAsIntArray(String name) throws IOException { - PDFObject ref = getDictRef(name); - if (ref == null) { - return null; - } - PDFObject[] values = ref.getArray(); + PDFObject ref = getDictRef(name); + if (ref == null) { + return null; + } + PDFObject[] values = ref.getArray(); int[] result = new int[values.length]; for (int i = 0; i < values.length; i++) { - result[i] = values[i].getIntValue(); + result[i] = values[i].getIntValue(); } - return result; + return result; } /** @@ -258,16 +258,16 @@ public int[] getDictRefAsIntArray(String name) throws IOException { * @throws IOException */ public float[] getDictRefAsFloatArray(String name) throws IOException { - PDFObject ref = getDictRef(name); - if (ref == null) { - return null; - } - PDFObject[] values = ref.getArray(); - float[] result = new float[values.length]; + PDFObject ref = getDictRef(name); + if (ref == null) { + return null; + } + PDFObject[] values = ref.getArray(); + float[] result = new float[values.length]; for (int i = 0; i < values.length; i++) { - result[i] = values[i].getFloatValue(); + result[i] = values[i].getFloatValue(); } - return result; + return result; } @@ -278,8 +278,8 @@ public float[] getDictRefAsFloatArray(String name) throws IOException { * @throws IOException */ public Float getDictRefAsFloat(String name) throws IOException { - PDFObject ref = getDictRef(name); - return ref == null ? null : ref.getFloatValue(); + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getFloatValue(); } /** @@ -289,8 +289,8 @@ public Float getDictRefAsFloat(String name) throws IOException { * @throws IOException */ public Double getDictRefAsDouble(String name) throws IOException { - PDFObject ref = getDictRef(name); - return ref == null ? null : ref.getDoubleValue(); + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getDoubleValue(); } /** @@ -522,7 +522,7 @@ public String getStringValue() throws IOException { * @throws IOException */ public String getTextStringValue() throws IOException { - return PDFStringUtil.asTextString(getStringValue()); + return PDFStringUtil.asTextString(getStringValue()); } /** @@ -822,12 +822,12 @@ public boolean equals(Object o) { return false; } - - /** + + /** * Returns the root of this object. */ public PDFObject getRoot() { - return owner.getRoot(); + return owner.getRoot(); } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFPage.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFPage.java index 7483444b5..e9f86c397 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFPage.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFPage.java @@ -225,12 +225,12 @@ public Image getImage(int width, int height, Rectangle2D clip, ImageObserver obs renderer.addObserver(observer); } - if (!renderer.isFinished()) { - renderer.go(wait); - if (renderer.getStatus() == Watchable.ERROR) { - PDFDebugger.debug("Error during reading image!"); - } - } + if (!renderer.isFinished()) { + renderer.go(wait); + if (renderer.getStatus() == Watchable.ERROR) { + PDFDebugger.debug("Error during reading image!"); + } + } } // return the image return image; @@ -695,12 +695,12 @@ public void setAnnots(List annots) { } public void addAnnotations() { - if(this.annots != null) { + if(this.annots != null) { for (PDFAnnotation pdfAnnotation : this.annots) { // add command to the page if needed this.commands.addAll(pdfAnnotation.getPageCommandsForAnnotation()); } - } + } } public static PDFImageCmd createImageCmd(PDFImage image) { diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParseException.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParseException.java index c6ca4ef3d..adca624ae 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParseException.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParseException.java @@ -31,7 +31,7 @@ public PDFParseException(String msg) { } public PDFParseException(String msg, Throwable cause) { - this(msg); + this(msg); initCause(cause); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParser.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParser.java index 883fc5c7d..aea40a394 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParser.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFParser.java @@ -84,7 +84,7 @@ public class PDFParser extends BaseWatchable { private int strokeOverprintMode; private boolean fillOverprint; private int fillOverprintMode; - private boolean addAnnotation; + private boolean addAnnotation; /** * Don't call this constructor directly. Instead, use @@ -211,7 +211,7 @@ private Tok nextToken() { } // skip whitespace while (this.loc < this.stream.length && PDFFile.isWhiteSpace(c)) { - c = this.stream[this.loc++]; + c = this.stream[this.loc++]; } } PDFDebugger.debug("Read comment: " + comment.toString(), -1); @@ -1222,7 +1222,7 @@ private void parseInlineImage() throws IOException, DebugStopException { private void doShader(PDFObject shaderObj) throws IOException { PDFShader shader = PDFShader.getShader(shaderObj, this.resources); if(shader == null) { - return; + return; } this.cmds.addPush(); Rectangle2D bbox = shader.getBBox(); @@ -1508,14 +1508,14 @@ public Object clone() { @Override protected void setStatus(int status) { - if(status == COMPLETED) { - if(!addAnnotation){ - // corresponding push in constructor PDFPage - this.cmds.addPop(); - this.cmds.addAnnotations(); - addAnnotation = true; - } - } - super.setStatus(status); + if(status == COMPLETED) { + if(!addAnnotation){ + // corresponding push in constructor PDFPage + this.cmds.addPop(); + this.cmds.addAnnotations(); + addAnnotation = true; + } + } + super.setStatus(status); } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFRenderer.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFRenderer.java index 18e14ae5a..5e433284c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFRenderer.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFRenderer.java @@ -195,9 +195,9 @@ public void push() { * push() was called. */ public void pop() { - if(this.stack.isEmpty() == false) { + if(this.stack.isEmpty() == false) { this.state = this.stack.pop(); - } + } setTransform(this.state.xform); setClip(this.state.cliprgn); @@ -265,9 +265,9 @@ public void draw(GeneralPath p, BasicStroke bs) { public Rectangle2D fill(GeneralPath s) { this.g.setComposite(this.state.fillAlpha); if (s == null) { - GraphicsState gs = stack.peek(); + GraphicsState gs = stack.peek(); if (gs.cliprgn != null) { - s = new GeneralPath(gs.cliprgn); + s = new GeneralPath(gs.cliprgn); } } return this.state.fillPaint.fill(this, this.g, s); @@ -287,35 +287,35 @@ public Rectangle2D drawImage(PDFImage image) { // Nothing to draw, anyway! return new Rectangle2D.Double(); } - - // transform must use bitmap size + + // transform must use bitmap size AffineTransform at = new AffineTransform(1f / bi.getWidth(), 0, 0, -1f / bi.getHeight(), 0, 1); if (image.isImageMask()) { - bi = getMaskedImage(bi); + bi = getMaskedImage(bi); } Rectangle r = g.getTransform().createTransformedShape(new Rectangle(0,0,1,1)).getBounds(); boolean isBlured = false; if (Configuration.getInstance().isUseBlurResizingForImages() && - bi.getType() != BufferedImage.TYPE_CUSTOM && - bi.getWidth() >= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ - try { - return smartDrawImage(image, bi, r, at); - }catch (Exception e) { - // do nothing, just go on with the "default" processing - } + bi.getType() != BufferedImage.TYPE_CUSTOM && + bi.getWidth() >= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ + try { + return smartDrawImage(image, bi, r, at); + }catch (Exception e) { + // do nothing, just go on with the "default" processing + } } this.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //Image quality is better when using texturepaint instead of drawimage //but it is also slower :( - this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); + this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); // banded rendering may lead to lower memory consumption for e.g. scanned PDFs with large images int bandSize = Configuration.getInstance().getThresholdForBandedImageRendering(); if (bandSize > 0 && bi.getHeight() > bandSize) { @@ -335,7 +335,7 @@ public Rectangle2D drawImage(PDFImage image) { PDFDebugger.debug("Image not completed!", 10); } } - + if (isBlured) bi.flush(); // get the total transform that was executed @@ -360,75 +360,75 @@ private Rectangle2D smartDrawImage(PDFImage image, BufferedImage bi, Rectangle r boolean isBlured = false; if (Configuration.getInstance().isUseBlurResizingForImages() && - bi.getType() != BufferedImage.TYPE_CUSTOM && - bi.getWidth() >= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ - - BufferedImageOp op; - // indexed colored images need to be converted for the convolveOp - boolean colorConversion = (bi.getColorModel() instanceof IndexColorModel); - final float maxFactor = 3.5f; - final boolean RESIZE = true; - if (bi.getWidth() > maxFactor*r.getWidth() && bi.getHeight() > maxFactor*r.getHeight()){ - //First resize, otherwise we risk that we get out of heapspace - int newHeight = (int)Math.round(maxFactor*r.getHeight()); - int newWidth = (int)Math.round(maxFactor*r.getWidth()); - if (!RESIZE) { - newHeight = bi.getHeight(); - newWidth = bi.getWidth(); - } - BufferedImage resized = new BufferedImage(newWidth, - newHeight, colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); - Graphics2D bg = (Graphics2D) resized.getGraphics(); - bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - bg.drawImage(bi, 0, 0, newWidth, newHeight, null); - bi = resized; + bi.getType() != BufferedImage.TYPE_CUSTOM && + bi.getWidth() >= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ + + BufferedImageOp op; + // indexed colored images need to be converted for the convolveOp + boolean colorConversion = (bi.getColorModel() instanceof IndexColorModel); + final float maxFactor = 3.5f; + final boolean RESIZE = true; + if (bi.getWidth() > maxFactor*r.getWidth() && bi.getHeight() > maxFactor*r.getHeight()){ + //First resize, otherwise we risk that we get out of heapspace + int newHeight = (int)Math.round(maxFactor*r.getHeight()); + int newWidth = (int)Math.round(maxFactor*r.getWidth()); + if (!RESIZE) { + newHeight = bi.getHeight(); + newWidth = bi.getWidth(); + } + BufferedImage resized = new BufferedImage(newWidth, + newHeight, colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); + Graphics2D bg = (Graphics2D) resized.getGraphics(); + bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + bg.drawImage(bi, 0, 0, newWidth, newHeight, null); + bi = resized; at = new AffineTransform(1f / bi.getWidth(), 0, 0, -1f / bi.getHeight(), 0, 1); final float weight = 1.0f/16.0f; - final float[] blurKernel = { - weight, weight, weight, weight, - weight, weight, weight, weight, - weight, weight, weight, weight, - weight, weight, weight, weight, - }; - op = new ConvolveOp(new Kernel(4, 4, blurKernel), ConvolveOp.EDGE_NO_OP, null); - } - else { - final float weight = 1.0f/18.0f; - final float[] blurKernel = { - 1*weight, 2*weight, 1*weight, - 2*weight, 6*weight, 2*weight, - 1*weight, 2*weight, 1*weight - }; - if (colorConversion) { - BufferedImage colored = new BufferedImage(bi.getWidth(), - bi.getHeight(), colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); - Graphics2D bg = (Graphics2D) colored.getGraphics(); - bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - bg.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null); - bi = colored; - } - op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, null); - } - - BufferedImage blured = op.createCompatibleDestImage(bi, - colorConversion?ColorModel.getRGBdefault():bi.getColorModel()); - - op.filter(bi, blured); - bi = blured; - isBlured = true; + final float[] blurKernel = { + weight, weight, weight, weight, + weight, weight, weight, weight, + weight, weight, weight, weight, + weight, weight, weight, weight, + }; + op = new ConvolveOp(new Kernel(4, 4, blurKernel), ConvolveOp.EDGE_NO_OP, null); + } + else { + final float weight = 1.0f/18.0f; + final float[] blurKernel = { + 1*weight, 2*weight, 1*weight, + 2*weight, 6*weight, 2*weight, + 1*weight, 2*weight, 1*weight + }; + if (colorConversion) { + BufferedImage colored = new BufferedImage(bi.getWidth(), + bi.getHeight(), colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); + Graphics2D bg = (Graphics2D) colored.getGraphics(); + bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + bg.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null); + bi = colored; + } + op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, null); + } + + BufferedImage blured = op.createCompatibleDestImage(bi, + colorConversion?ColorModel.getRGBdefault():bi.getColorModel()); + + op.filter(bi, blured); + bi = blured; + isBlured = true; } this.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //Image quality is better when using texturepaint instead of drawimage //but it is also slower :( - this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); + this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); // banded rendering may lead to lower memory consumption for e.g. scanned PDFs with large images int bandSize = Configuration.getInstance().getThresholdForBandedImageRendering(); if (bandSize > 0 && bi.getHeight() > bandSize) { @@ -661,8 +661,8 @@ public GeneralPath getLastShape() { * @return a BufferedImage or null */ public BufferedImage getImage() { - if (this.imageRef == null) return null; - return this.imageRef.get(); + if (this.imageRef == null) return null; + return this.imageRef.get(); } /** @@ -702,7 +702,7 @@ public void setup() { * */ @Override - public int iterate() throws Exception { + public int iterate() throws Exception { // make sure we have a page to render if (this.page == null) { return COMPLETED; @@ -879,60 +879,60 @@ private void notifyObservers(BufferedImage bi, Rectangle2D region) { */ private BufferedImage getMaskedImage(BufferedImage bi) { - // get the color of the current paint - final Paint paint = state.fillPaint.getPaint(); - if (!(paint instanceof Color)) { - // TODO - support other types of Paint - return bi; - } - - Color col = (Color) paint; - ColorModel colorModel = bi.getColorModel(); - if (colorModel instanceof IndexColorModel) { - int mapSize = ((IndexColorModel) colorModel).getMapSize(); - int pixelSize = colorModel.getPixelSize(); - if (mapSize == 2 && pixelSize == 1) { - // we have a monochrome image mask with 1 bit per pixel - // swap out the standard color with the current paint color - int[] rgbValues = new int[2]; - ((IndexColorModel) colorModel).getRGBs(rgbValues); - byte[] colorComponents = null; - if (rgbValues[0] == 0xff000000) { - // normal case color at 0 - colorComponents = new byte[]{ - (byte) col.getRed(), - (byte) col.getGreen(), - (byte) col.getBlue(), - (byte) col.getAlpha(), - 0, 0, 0, 0 // the background is transparent - }; - } - else if (rgbValues[1] == 0xff000000){ - // alternate case color at 1 - colorComponents = new byte[]{ - 0, 0, 0, 0, // the background is transparent - (byte) col.getRed(), - (byte) col.getGreen(), - (byte) col.getBlue(), - (byte) col.getAlpha() - }; - } - - if (colorComponents != null) { - // replace mapped colors - int startIndex = 0; - boolean hasAlpha = true; - ColorModel replacementColorModel = new IndexColorModel(pixelSize, mapSize, colorComponents, startIndex, hasAlpha); - WritableRaster raster = bi.getRaster(); - BufferedImage adaptedImage = new BufferedImage(replacementColorModel, raster, false, null); - return adaptedImage; - } - else { - return bi; // no color replacement - } - } - } - + // get the color of the current paint + final Paint paint = state.fillPaint.getPaint(); + if (!(paint instanceof Color)) { + // TODO - support other types of Paint + return bi; + } + + Color col = (Color) paint; + ColorModel colorModel = bi.getColorModel(); + if (colorModel instanceof IndexColorModel) { + int mapSize = ((IndexColorModel) colorModel).getMapSize(); + int pixelSize = colorModel.getPixelSize(); + if (mapSize == 2 && pixelSize == 1) { + // we have a monochrome image mask with 1 bit per pixel + // swap out the standard color with the current paint color + int[] rgbValues = new int[2]; + ((IndexColorModel) colorModel).getRGBs(rgbValues); + byte[] colorComponents = null; + if (rgbValues[0] == 0xff000000) { + // normal case color at 0 + colorComponents = new byte[]{ + (byte) col.getRed(), + (byte) col.getGreen(), + (byte) col.getBlue(), + (byte) col.getAlpha(), + 0, 0, 0, 0 // the background is transparent + }; + } + else if (rgbValues[1] == 0xff000000){ + // alternate case color at 1 + colorComponents = new byte[]{ + 0, 0, 0, 0, // the background is transparent + (byte) col.getRed(), + (byte) col.getGreen(), + (byte) col.getBlue(), + (byte) col.getAlpha() + }; + } + + if (colorComponents != null) { + // replace mapped colors + int startIndex = 0; + boolean hasAlpha = true; + ColorModel replacementColorModel = new IndexColorModel(pixelSize, mapSize, colorComponents, startIndex, hasAlpha); + WritableRaster raster = bi.getRaster(); + BufferedImage adaptedImage = new BufferedImage(replacementColorModel, raster, false, null); + return adaptedImage; + } + else { + return bi; // no color replacement + } + } + } + // format as 8 bits each of ARGB int paintColor = col.getAlpha() << 24; paintColor |= col.getRed() << 16; @@ -1022,17 +1022,17 @@ public Object clone() { } } - /************************************************************************* - * @return Returns the lastTransform. - ************************************************************************/ - public AffineTransform getLastTransform() { - return this.lastTransform; - } - - /************************************************************************* - * Remember the current transformation - ************************************************************************/ - public void rememberTransformation() { - this.lastTransform = this.state.xform; - } + /************************************************************************* + * @return Returns the lastTransform. + ************************************************************************/ + public AffineTransform getLastTransform() { + return this.lastTransform; + } + + /************************************************************************* + * Remember the current transformation + ************************************************************************/ + public void rememberTransformation() { + this.lastTransform = this.state.xform; + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFXref.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFXref.java index 145ff9757..0f6204d93 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFXref.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/PDFXref.java @@ -140,7 +140,7 @@ public void setObject(PDFObject obj) { } @Override - public boolean equals(Object obj) { + public boolean equals(Object obj) { return (obj instanceof PDFXref) && ((PDFXref)obj).id == id && ((PDFXref)obj).generation == generation; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/RefImage.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/RefImage.java index 9ad834d4b..55547ab03 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/RefImage.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/RefImage.java @@ -43,7 +43,7 @@ public RefImage(int width, int height, int type) { * return the existing graphics object. */ @Override - public Graphics2D createGraphics() { + public Graphics2D createGraphics() { if (this.g == null) { this.g = super.createGraphics(); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToEAction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToEAction.java index 3af32a378..25d3e6ece 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToEAction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToEAction.java @@ -15,255 +15,255 @@ ****************************************************************************/ public class GoToEAction extends PDFAction { - /** the destination within the remote PDF file */ - private PDFDestination destination; - /** the remote file this action refers to (optional)*/ - private String file = null; - /** Should the remote file be opened in a new window? (optional)*/ - private boolean newWindow = false; - /** The target dictionary*/ - private GoToETarget target; + /** the destination within the remote PDF file */ + private PDFDestination destination; + /** the remote file this action refers to (optional)*/ + private String file = null; + /** Should the remote file be opened in a new window? (optional)*/ + private boolean newWindow = false; + /** The target dictionary*/ + private GoToETarget target; - /** - * Creates a new instance of GoToEAction from an object - * @param obj the PDFObject with the action information - * @throws IOException - in case the action can not be parsed - */ - public GoToEAction(PDFObject obj, PDFObject root) throws IOException { - super("GoToE"); - // find the destination and parse it - this.destination = PdfObjectParseUtil.parseDestination("D", obj, root, true); - - // find the remote file and parse it - this.file = PdfObjectParseUtil.parseStringFromDict("F", obj, false); + /** + * Creates a new instance of GoToEAction from an object + * @param obj the PDFObject with the action information + * @throws IOException - in case the action can not be parsed + */ + public GoToEAction(PDFObject obj, PDFObject root) throws IOException { + super("GoToE"); + // find the destination and parse it + this.destination = PdfObjectParseUtil.parseDestination("D", obj, root, true); + + // find the remote file and parse it + this.file = PdfObjectParseUtil.parseStringFromDict("F", obj, false); - // find the new window attribute and parse it if available - this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); + // find the new window attribute and parse it if available + this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); - // parse the target dictionary - PDFObject targetObj = obj.getDictRef("T"); - ArrayList list = new ArrayList(); - this.target = parseTargetDistionary(targetObj, list); - } + // parse the target dictionary + PDFObject targetObj = obj.getDictRef("T"); + ArrayList list = new ArrayList(); + this.target = parseTargetDistionary(targetObj, list); + } - /************************************************************************* - * Parse a target dictionary if available - * @param targetObj - * @param list - a list of all already parsed targets, for not getting in an endless loop - * (if a target is found which is already contained, the recursive calling - * of this method will stop). - * @throws IOException - in case a value can not be parsed - ************************************************************************/ - private GoToETarget parseTargetDistionary(PDFObject targetObj, ArrayList list) throws IOException { - GoToETarget target = null; - if (targetObj != null) { - target = new GoToETarget(); - - // find the relation and parse it - target.setRelation(PdfObjectParseUtil.parseStringFromDict("R", targetObj, true)); - - // find the name of the embedded file and parse it - target.setNameInTree(PdfObjectParseUtil.parseStringFromDict("N", targetObj, false)); - - // find the page number and parse it - String page = PdfObjectParseUtil.parseStringFromDict("P", targetObj, false); - if(page == null){ - page = ""+PdfObjectParseUtil.parseIntegerFromDict("P", targetObj, false); - } - target.setPageNo(page); - - // find the annotation index and parse it - String annot = PdfObjectParseUtil.parseStringFromDict("A", targetObj, false); - if(annot == null){ - annot = ""+PdfObjectParseUtil.parseIntegerFromDict("A", targetObj, false); - } - target.setAnnotNo(annot); - - //find target dictionary and parse it - PDFObject subTargetObj = targetObj.getDictRef("T"); - if(subTargetObj != null){ - // call this method recursive, in case the target was not already contained in the - // list (this is checked for not getting into an infinite loop) - if(list.contains(target) == false){ - list.add(target); - GoToETarget subTargetDictionary = parseTargetDistionary(subTargetObj, list); - target.setTargetDictionary(subTargetDictionary); - } - } - } else { - if (this.file == null) { - throw new PDFParseException("No target dictionary in GoToE action " + targetObj); - } - } - return target; - } + /************************************************************************* + * Parse a target dictionary if available + * @param targetObj + * @param list - a list of all already parsed targets, for not getting in an endless loop + * (if a target is found which is already contained, the recursive calling + * of this method will stop). + * @throws IOException - in case a value can not be parsed + ************************************************************************/ + private GoToETarget parseTargetDistionary(PDFObject targetObj, ArrayList list) throws IOException { + GoToETarget target = null; + if (targetObj != null) { + target = new GoToETarget(); + + // find the relation and parse it + target.setRelation(PdfObjectParseUtil.parseStringFromDict("R", targetObj, true)); + + // find the name of the embedded file and parse it + target.setNameInTree(PdfObjectParseUtil.parseStringFromDict("N", targetObj, false)); + + // find the page number and parse it + String page = PdfObjectParseUtil.parseStringFromDict("P", targetObj, false); + if(page == null){ + page = ""+PdfObjectParseUtil.parseIntegerFromDict("P", targetObj, false); + } + target.setPageNo(page); + + // find the annotation index and parse it + String annot = PdfObjectParseUtil.parseStringFromDict("A", targetObj, false); + if(annot == null){ + annot = ""+PdfObjectParseUtil.parseIntegerFromDict("A", targetObj, false); + } + target.setAnnotNo(annot); + + //find target dictionary and parse it + PDFObject subTargetObj = targetObj.getDictRef("T"); + if(subTargetObj != null){ + // call this method recursive, in case the target was not already contained in the + // list (this is checked for not getting into an infinite loop) + if(list.contains(target) == false){ + list.add(target); + GoToETarget subTargetDictionary = parseTargetDistionary(subTargetObj, list); + target.setTargetDictionary(subTargetDictionary); + } + } + } else { + if (this.file == null) { + throw new PDFParseException("No target dictionary in GoToE action " + targetObj); + } + } + return target; + } - /************************************************************************* - * Create a new GoToEAction from the given attributes - * @param dest - * @param file - * @param newWindow - ************************************************************************/ - public GoToEAction(PDFDestination dest, String file, boolean newWindow) { - super("GoToR"); - this.file = file; - this.destination = dest; - this.newWindow = newWindow; - } + /************************************************************************* + * Create a new GoToEAction from the given attributes + * @param dest + * @param file + * @param newWindow + ************************************************************************/ + public GoToEAction(PDFDestination dest, String file, boolean newWindow) { + super("GoToR"); + this.file = file; + this.destination = dest; + this.newWindow = newWindow; + } - /************************************************************************* - * Get the destination this action refers to - * @return PDFDestination - ************************************************************************/ - public PDFDestination getDestination() { - return this.destination; - } + /************************************************************************* + * Get the destination this action refers to + * @return PDFDestination + ************************************************************************/ + public PDFDestination getDestination() { + return this.destination; + } - /************************************************************************* - * Get the file this action refers to - * @return PDFDestination - ************************************************************************/ - public String getFile() { - return this.file; - } + /************************************************************************* + * Get the file this action refers to + * @return PDFDestination + ************************************************************************/ + public String getFile() { + return this.file; + } - /************************************************************************* - * Should the remote file be opened in a new window? - * @return boolean - ************************************************************************/ - public boolean isNewWindow() { - return this.newWindow; - } - - /************************************************************************* - * Get the target dictionary - * @return GoToETarget - ************************************************************************/ - public GoToETarget getTarget() { - return this.target; - } + /************************************************************************* + * Should the remote file be opened in a new window? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } + + /************************************************************************* + * Get the target dictionary + * @return GoToETarget + ************************************************************************/ + public GoToETarget getTarget() { + return this.target; + } - - /***************************************************************************** - * Inner class for holding the target dictionary's information - * - * @version $Id: GoToEAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ - * @author xond - * @since 07.07.2009 - ****************************************************************************/ - public static class GoToETarget { - private String relation; - private String nameInTree; - private String pageNo; - private String annotNo; - private GoToETarget targetDictionary; + + /***************************************************************************** + * Inner class for holding the target dictionary's information + * + * @version $Id: GoToEAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 07.07.2009 + ****************************************************************************/ + public static class GoToETarget { + private String relation; + private String nameInTree; + private String pageNo; + private String annotNo; + private GoToETarget targetDictionary; - /************************************************************************* - * Relation between current document and the target. Can either be "P" or "C" - * @return String - ************************************************************************/ - public String getRelation() { - return this.relation; - } + /************************************************************************* + * Relation between current document and the target. Can either be "P" or "C" + * @return String + ************************************************************************/ + public String getRelation() { + return this.relation; + } - /************************************************************************* - * Relation between current document and the target. Can either be "P" or "C" - * @param relation - ************************************************************************/ - public void setRelation(String relation) { - this.relation = relation; - } + /************************************************************************* + * Relation between current document and the target. Can either be "P" or "C" + * @param relation + ************************************************************************/ + public void setRelation(String relation) { + this.relation = relation; + } - /************************************************************************* - * The file name in the embedded files tree - * @return String - ************************************************************************/ - public String getNameInTree() { - return this.nameInTree; - } + /************************************************************************* + * The file name in the embedded files tree + * @return String + ************************************************************************/ + public String getNameInTree() { + return this.nameInTree; + } - /************************************************************************* - * The file name in the embedded files tree - * @param nameInTree - ************************************************************************/ - public void setNameInTree(String nameInTree) { - this.nameInTree = nameInTree; - } + /************************************************************************* + * The file name in the embedded files tree + * @param nameInTree + ************************************************************************/ + public void setNameInTree(String nameInTree) { + this.nameInTree = nameInTree; + } - /************************************************************************* - * Page Number: - * If the value can be parsed as Integer, it specifies the page number in - * the current document containing the file attachment annotation. If the - * value is a string, it defines a named destination in the current document - * that provides the page number of the file attachment annotation. - * - * @return String - ************************************************************************/ - public String getPageNo() { - return this.pageNo; - } + /************************************************************************* + * Page Number: + * If the value can be parsed as Integer, it specifies the page number in + * the current document containing the file attachment annotation. If the + * value is a string, it defines a named destination in the current document + * that provides the page number of the file attachment annotation. + * + * @return String + ************************************************************************/ + public String getPageNo() { + return this.pageNo; + } - /************************************************************************* - * Page Number: - * If the value can be parsed as Integer, it specifies the page number in - * the current document containing the file attachment annotation. If the - * value is a string, it defines a named destination in the current document - * that provides the page number of the file attachment annotation. - * - * @param pageNo - ************************************************************************/ - public void setPageNo(String pageNo) { - this.pageNo = pageNo; - } + /************************************************************************* + * Page Number: + * If the value can be parsed as Integer, it specifies the page number in + * the current document containing the file attachment annotation. If the + * value is a string, it defines a named destination in the current document + * that provides the page number of the file attachment annotation. + * + * @param pageNo + ************************************************************************/ + public void setPageNo(String pageNo) { + this.pageNo = pageNo; + } - /************************************************************************* - * The index of the according annotation in the annotations array - * @return String - ************************************************************************/ - public String getAnnotNo() { - return this.annotNo; - } + /************************************************************************* + * The index of the according annotation in the annotations array + * @return String + ************************************************************************/ + public String getAnnotNo() { + return this.annotNo; + } - /************************************************************************* - * The index of the according annotation in the annotations array - * @param annotNo - ************************************************************************/ - public void setAnnotNo(String annotNo) { - this.annotNo = annotNo; - } + /************************************************************************* + * The index of the according annotation in the annotations array + * @param annotNo + ************************************************************************/ + public void setAnnotNo(String annotNo) { + this.annotNo = annotNo; + } - /************************************************************************* - * A target dictionary specifying additional target information. If missing, - * the current document is the target file containing the destination. - * @return GoToETarget - ************************************************************************/ - public GoToETarget getTargetDictionary() { - return this.targetDictionary; - } + /************************************************************************* + * A target dictionary specifying additional target information. If missing, + * the current document is the target file containing the destination. + * @return GoToETarget + ************************************************************************/ + public GoToETarget getTargetDictionary() { + return this.targetDictionary; + } - /************************************************************************* - * A target dictionary specifying additional target information. If missing, - * the current document is the target file containing the destination. - * @param targetDictionary - ************************************************************************/ - public void setTargetDictionary(GoToETarget targetDictionary) { - this.targetDictionary = targetDictionary; - } + /************************************************************************* + * A target dictionary specifying additional target information. If missing, + * the current document is the target file containing the destination. + * @param targetDictionary + ************************************************************************/ + public void setTargetDictionary(GoToETarget targetDictionary) { + this.targetDictionary = targetDictionary; + } - @Override - public boolean equals(Object obj) { - if((obj instanceof GoToETarget) == false){ - return false; - } - if(super.equals(obj)){ - return true; - } - GoToETarget that = (GoToETarget)obj; - // compare the strng values, as the attributes may also be null - return String.valueOf(this.annotNo).equals(String.valueOf(that.annotNo)) - && String.valueOf(this.nameInTree).equals(String.valueOf(that.nameInTree)) - && String.valueOf(this.pageNo).equals(String.valueOf(that.pageNo)) - && String.valueOf(this.relation).equals(String.valueOf(that.relation)); - } - } + @Override + public boolean equals(Object obj) { + if((obj instanceof GoToETarget) == false){ + return false; + } + if(super.equals(obj)){ + return true; + } + GoToETarget that = (GoToETarget)obj; + // compare the strng values, as the attributes may also be null + return String.valueOf(this.annotNo).equals(String.valueOf(that.annotNo)) + && String.valueOf(this.nameInTree).equals(String.valueOf(that.nameInTree)) + && String.valueOf(this.pageNo).equals(String.valueOf(that.pageNo)) + && String.valueOf(this.relation).equals(String.valueOf(that.relation)); + } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToRAction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToRAction.java index f27c10e62..0da428839 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToRAction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/GoToRAction.java @@ -13,13 +13,13 @@ ****************************************************************************/ public class GoToRAction extends PDFAction { - /** the destination within the remote PDF file */ + /** the destination within the remote PDF file */ private PDFDestination destination; /** the remote file this action refers to*/ private String file; /** Should the remote file be opened in a new window? (optional)*/ private boolean newWindow=false; - /** + /** * Creates a new instance of GoToRAction from an object * @param obj the PDFObject with the action information * @throws IOException - in case the action can not be parsed @@ -33,7 +33,7 @@ public GoToRAction(PDFObject obj, PDFObject root) throws IOException { this.file = PdfObjectParseUtil.parseStringFromDict("F", obj, true); // find the new window attribute and parse it if available - this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); + this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); } /************************************************************************* @@ -43,33 +43,33 @@ public GoToRAction(PDFObject obj, PDFObject root) throws IOException { * @param newWindow ************************************************************************/ public GoToRAction(PDFDestination dest, String file, boolean newWindow){ - super("GoToR"); - this.file = file; - this.destination = dest; - this.newWindow = newWindow; + super("GoToR"); + this.file = file; + this.destination = dest; + this.newWindow = newWindow; } /************************************************************************* * Get the destination this action refers to * @return PDFDestination ************************************************************************/ - public PDFDestination getDestination() { - return this.destination; - } + public PDFDestination getDestination() { + return this.destination; + } /************************************************************************* * Get the file this action refers to * @return PDFDestination ************************************************************************/ - public String getFile() { - return this.file; - } + public String getFile() { + return this.file; + } - /************************************************************************* - * Should the remote file be opened in a new window? - * @return boolean - ************************************************************************/ - public boolean isNewWindow() { - return this.newWindow; - } + /************************************************************************* + * Should the remote file be opened in a new window? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/LaunchAction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/LaunchAction.java index 00dba6ed8..6e9d91ac8 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/LaunchAction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/LaunchAction.java @@ -12,481 +12,481 @@ * @since 08.07.2009 ****************************************************************************/ public class LaunchAction extends PDFAction { - // file separator according to PDF spec - public final static String SOLIDUS = "/"; - - /** the file/application to be opened (optional)*/ - private FileSpec file; - /** should a new window be opened (optional)*/ - private boolean newWindow = false; - private PDFObject unixParam; - private PDFObject macParam; - private WinLaunchParam winParam; - - /** - * Creates a new instance of LaunchAction from an object - * - * @param obj - the PDFObject with the action information - * @param root - the root object - */ - public LaunchAction(PDFObject obj, PDFObject root) throws IOException { - super("Launch"); - // find the file/application and parse it - PDFObject fileObj = obj.getDictRef("F"); - this.file = parseFileSpecification(fileObj); - - // find the new window flag and parse it - PDFObject newWinObj = obj.getDictRef("NewWindow"); - if (newWinObj != null) { - this.newWindow = newWinObj.getBooleanValue(); - } - // parse the OS specific launch parameters: - this.winParam = parseWinDict(obj.getDictRef("Win")); - // unix and mac dictionaries are not further specified, so can not be parsed yet. - this.unixParam = obj.getDictRef("Unix"); - this.macParam = obj.getDictRef("Mac"); - - // check if at least the file or one of the OS specific launch parameters is set: - if ((this.file == null) - && (this.winParam == null) - && (this.unixParam == null) - && (this.macParam == null)) { - throw new PDFParseException("Could not parse launch action (file or OS " + - "specific launch parameters are missing): " + obj.toString()); - } - } - - /************************************************************************* - * Is the file name absolute (if not, it is relative to the path of the - * currently opened PDF file). - * If the file name starts with a "/", it is considered to be absolute. - * - * @return boolean - ************************************************************************/ - public static boolean isAbsolute(String fileName) { - return fileName.startsWith(SOLIDUS); - } - - /************************************************************************* - * Parse the file specification object - * @param fileObj - * @return FileSpec - might be null in case the passed object is null - * @throws IOException - * @throws PDFParseException - ************************************************************************/ - private FileSpec parseFileSpecification(PDFObject fileObj) throws PDFParseException, IOException { - FileSpec file = null; - if (fileObj != null) { - file = new FileSpec(); - if(fileObj.getType() == PDFObject.DICTIONARY){ - file.setFileSystem(PdfObjectParseUtil.parseStringFromDict("FS", fileObj, false)); - file.setFileName(PdfObjectParseUtil.parseStringFromDict("F", fileObj, false)); - file.setUnicode(PdfObjectParseUtil.parseStringFromDict("UF", fileObj, false)); - file.setDosFileName(PdfObjectParseUtil.parseStringFromDict("DOS", fileObj, false)); - file.setMacFileName(PdfObjectParseUtil.parseStringFromDict("Mac", fileObj, false)); - file.setUnixFileName(PdfObjectParseUtil.parseStringFromDict("Unix", fileObj, false)); - file.setVolatileFile(PdfObjectParseUtil.parseBooleanFromDict("V", fileObj, false)); - file.setDescription(PdfObjectParseUtil.parseStringFromDict("Desc", fileObj, false)); - file.setId(fileObj.getDictRef("ID")); - file.setEmbeddedFile(fileObj.getDictRef("EF")); - file.setRelatedFile(fileObj.getDictRef("RF")); - file.setCollectionItem(fileObj.getDictRef("CI")); - }else if(fileObj.getType() == PDFObject.STRING){ - file.setFileName(fileObj.getStringValue()); - }else{ - throw new PDFParseException("File specification could not be parsed " + - "(should be of type 'Dictionary' or 'String'): " + fileObj.toString()); - } - } - return file; - } - - - /************************************************************************* - * Parse the windows specific launch parameters - * @param winDict - * @throws IOException - in case of a problem during parsing content - ************************************************************************/ - private WinLaunchParam parseWinDict(PDFObject winDict) throws IOException { - if (winDict == null) { - return null; - } - WinLaunchParam param = new WinLaunchParam(); - - // find and parse the file/application name - param.setFileName(PdfObjectParseUtil.parseStringFromDict("F", winDict, true)); - - // find and parse the directory - param.setDirectory(PdfObjectParseUtil.parseStringFromDict("D", winDict, false)); - - // find and parse the operation to be performed - param.setOperation(PdfObjectParseUtil.parseStringFromDict("O", winDict, false)); - - // find and parse the parameter to be passed to the application - param.setParameter(PdfObjectParseUtil.parseStringFromDict("P", winDict, false)); - - return param; - } - - /************************************************************************* - * The file / application to be opened - * @return FileSpec - ************************************************************************/ - public FileSpec getFileSpecification() { - return this.file; - } - - /************************************************************************* - * Should a new window be opened for the file/application? - * @return boolean - ************************************************************************/ - public boolean isNewWindow() { - return this.newWindow; - } - - /************************************************************************* - * Get the unix specific launch parameters. - * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject - * which is returned here is not parsed. - * @return PDFObject - ************************************************************************/ - public PDFObject getUnixParam() { - return this.unixParam; - } - - /************************************************************************* - * Get the mac specific launch parameters. - * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject - * which is returned here is not parsed. - * @return PDFObject - ************************************************************************/ - public PDFObject getMacParam() { - return this.macParam; - } - - /************************************************************************* - * Get the windows specific launch parameters. - * @return WinLaunchParam - ************************************************************************/ - public WinLaunchParam getWinParam() { - return this.winParam; - } - - /***************************************************************************** - * Internal class for the windows specific launch parameters - * - * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ - * @author xond - * @since 08.07.2009 - ****************************************************************************/ - public class WinLaunchParam { - private String fileName; - private String directory; - private String operation = "open"; - private String parameter; - - /************************************************************************* - * The file/application name to be opened - * @return String - ************************************************************************/ - public String getFileName() { - return this.fileName; - } - - /************************************************************************* - * The file/application name to be opened - * @param fileName - ************************************************************************/ - public void setFileName(String fileName) { - this.fileName = fileName; - } - - /************************************************************************* - * The directory in standard DOS syntax - * @return String - ************************************************************************/ - public String getDirectory() { - return this.directory; - } - - /************************************************************************* - * The directory in standard DOS syntax - * @param directory - ************************************************************************/ - public void setDirectory(String directory) { - this.directory = directory; - } - - /************************************************************************* - * The operation to be performed (open or print). Ignored - * in case the "F" parameter describes a file to be opened. - * Default is "open". - * @return String - ************************************************************************/ - public String getOperation() { - return this.operation; - } - - /************************************************************************* - * The operation to be performed ("open" or "print").Ignored - * in case the "F" parameter describes a file to be opened. - * Default is "open". - * @param operation - ************************************************************************/ - public void setOperation(String operation) { - this.operation = operation; - } - - /************************************************************************* - * A parameter which shall be passed to the application. Ignored - * in case the "F" parameter describes a file to be opened. - * @return String - ************************************************************************/ - public String getParameter() { - return this.parameter; - } - - /************************************************************************* - * A parameter which shall be passed to the application. Ignored - * in case the "F" parameter describes a file to be opened. - * @param parameter - ************************************************************************/ - public void setParameter(String parameter) { - this.parameter = parameter; - } - } - - /***************************************************************************** - * Inner class for storing a file specification - * - * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ - * @author xond - * @since 08.07.2009 - ****************************************************************************/ - public static class FileSpec{ - private String fileSystem; - private String fileName; - private String dosFileName; - private String unixFileName; - private String macFileName; - private String unicode; - private PDFObject id; - private boolean volatileFile; - private PDFObject embeddedFile; - private PDFObject relatedFile; - private String description; - private PDFObject collectionItem; - - /************************************************************************* - * The name of the file system that should be used to interpret this entry. - * @return String - ************************************************************************/ - public String getFileSystem() { - return this.fileSystem; - } - - /************************************************************************* - * The name of the file system that should be used to interpret this entry. - * @param fileSystem - ************************************************************************/ - public void setFileSystem(String fileSystem) { - this.fileSystem = fileSystem; - } - - /************************************************************************* - * Get the filename: - * first try to get the file name for the used OS, if it's not available - * return the common file name. - * @return String - ************************************************************************/ - public String getFileName() { - String system = System.getProperty("os.name"); - if(system.startsWith("Windows")){ - if(this.dosFileName != null){ - return this.dosFileName; - } - }else if(system.startsWith("mac os x")){ - if(this.macFileName != null){ - return this.macFileName; - } - }else { - if(this.unixFileName != null){ - return this.unixFileName; - } - } - return this.fileName; - } - - /************************************************************************* - * The file name. - * @param fileName - ************************************************************************/ - public void setFileName(String fileName) { - this.fileName = fileName; - } - - /************************************************************************* - * A file specification string representing a DOS file name. - * @return String - ************************************************************************/ - public String getDosFileName() { - return this.dosFileName; - } - - /************************************************************************* - * A file specification string representing a DOS file name. - * @param dosFileName - ************************************************************************/ - public void setDosFileName(String dosFileName) { - this.dosFileName = dosFileName; - } - - /************************************************************************* - * A file specification string representing a unix file name. - * @return String - ************************************************************************/ - public String getUnixFileName() { - return this.unixFileName; - } - - /************************************************************************* - * A file specification string representing a unix file name. - * @param unixFileName - ************************************************************************/ - public void setUnixFileName(String unixFileName) { - this.unixFileName = unixFileName; - } - - /************************************************************************* - * A file specification string representing a mac file name. - * @return String - ************************************************************************/ - public String getMacFileName() { - return this.macFileName; - } - - /************************************************************************* - * A file specification string representing a mac file name. - * @param macFileName - ************************************************************************/ - public void setMacFileName(String macFileName) { - this.macFileName = macFileName; - } - - /************************************************************************* - * Unicode file name - * @return String - ************************************************************************/ - public String getUnicode() { - return this.unicode; - } - - /************************************************************************* - * Unicode file name - * @param unicode - ************************************************************************/ - public void setUnicode(String unicode) { - this.unicode = unicode; - } - - /************************************************************************* - * ID - array of two byte strings constituting a file identifier, which - * should be included in the referenced file. - * - * @return PDFObject - ************************************************************************/ - public PDFObject getId() { - return this.id; - } - - /************************************************************************* - * ID - array of two byte strings constituting a file identifier, which - * should be included in the referenced file. - * - * @param id - ************************************************************************/ - public void setId(PDFObject id) { - this.id = id; - } - - /************************************************************************* - * Is the file volatile? - * @return boolean - ************************************************************************/ - public boolean isVolatileFile() { - return this.volatileFile; - } - - /************************************************************************* - * Is the file volatile? - * @param volatileFile - ************************************************************************/ - public void setVolatileFile(boolean volatileFile) { - this.volatileFile = volatileFile; - } - - /************************************************************************* - * Dictionary of embedded file streams - * @return PDFObject - ************************************************************************/ - public PDFObject getEmbeddedFile() { - return this.embeddedFile; - } - - /************************************************************************* - * Dictionary of embedded file streams - * @param embeddedFile - ************************************************************************/ - public void setEmbeddedFile(PDFObject embeddedFile) { - this.embeddedFile = embeddedFile; - } - - /************************************************************************* - * Dictionary of related files. - * @return PDFObject - ************************************************************************/ - public PDFObject getRelatedFile() { - return this.relatedFile; - } - - /************************************************************************* - * Dictionary of related files. - * @param relatedFile - ************************************************************************/ - public void setRelatedFile(PDFObject relatedFile) { - this.relatedFile = relatedFile; - } - - /************************************************************************* - * File specification description - * @return String - ************************************************************************/ - public String getDescription() { - return this.description; - } - - /************************************************************************* - * File specification description - * @param description - ************************************************************************/ - public void setDescription(String description) { - this.description = description; - } - - /************************************************************************* - * Collection item dictionary - * @return PDFObject - ************************************************************************/ - public PDFObject getCollectionItem() { - return this.collectionItem; - } - - /************************************************************************* - * Collection item dictionary - * @param collectionItem - ************************************************************************/ - public void setCollectionItem(PDFObject collectionItem) { - this.collectionItem = collectionItem; - } - } + // file separator according to PDF spec + public final static String SOLIDUS = "/"; + + /** the file/application to be opened (optional)*/ + private FileSpec file; + /** should a new window be opened (optional)*/ + private boolean newWindow = false; + private PDFObject unixParam; + private PDFObject macParam; + private WinLaunchParam winParam; + + /** + * Creates a new instance of LaunchAction from an object + * + * @param obj - the PDFObject with the action information + * @param root - the root object + */ + public LaunchAction(PDFObject obj, PDFObject root) throws IOException { + super("Launch"); + // find the file/application and parse it + PDFObject fileObj = obj.getDictRef("F"); + this.file = parseFileSpecification(fileObj); + + // find the new window flag and parse it + PDFObject newWinObj = obj.getDictRef("NewWindow"); + if (newWinObj != null) { + this.newWindow = newWinObj.getBooleanValue(); + } + // parse the OS specific launch parameters: + this.winParam = parseWinDict(obj.getDictRef("Win")); + // unix and mac dictionaries are not further specified, so can not be parsed yet. + this.unixParam = obj.getDictRef("Unix"); + this.macParam = obj.getDictRef("Mac"); + + // check if at least the file or one of the OS specific launch parameters is set: + if ((this.file == null) + && (this.winParam == null) + && (this.unixParam == null) + && (this.macParam == null)) { + throw new PDFParseException("Could not parse launch action (file or OS " + + "specific launch parameters are missing): " + obj.toString()); + } + } + + /************************************************************************* + * Is the file name absolute (if not, it is relative to the path of the + * currently opened PDF file). + * If the file name starts with a "/", it is considered to be absolute. + * + * @return boolean + ************************************************************************/ + public static boolean isAbsolute(String fileName) { + return fileName.startsWith(SOLIDUS); + } + + /************************************************************************* + * Parse the file specification object + * @param fileObj + * @return FileSpec - might be null in case the passed object is null + * @throws IOException + * @throws PDFParseException + ************************************************************************/ + private FileSpec parseFileSpecification(PDFObject fileObj) throws PDFParseException, IOException { + FileSpec file = null; + if (fileObj != null) { + file = new FileSpec(); + if(fileObj.getType() == PDFObject.DICTIONARY){ + file.setFileSystem(PdfObjectParseUtil.parseStringFromDict("FS", fileObj, false)); + file.setFileName(PdfObjectParseUtil.parseStringFromDict("F", fileObj, false)); + file.setUnicode(PdfObjectParseUtil.parseStringFromDict("UF", fileObj, false)); + file.setDosFileName(PdfObjectParseUtil.parseStringFromDict("DOS", fileObj, false)); + file.setMacFileName(PdfObjectParseUtil.parseStringFromDict("Mac", fileObj, false)); + file.setUnixFileName(PdfObjectParseUtil.parseStringFromDict("Unix", fileObj, false)); + file.setVolatileFile(PdfObjectParseUtil.parseBooleanFromDict("V", fileObj, false)); + file.setDescription(PdfObjectParseUtil.parseStringFromDict("Desc", fileObj, false)); + file.setId(fileObj.getDictRef("ID")); + file.setEmbeddedFile(fileObj.getDictRef("EF")); + file.setRelatedFile(fileObj.getDictRef("RF")); + file.setCollectionItem(fileObj.getDictRef("CI")); + }else if(fileObj.getType() == PDFObject.STRING){ + file.setFileName(fileObj.getStringValue()); + }else{ + throw new PDFParseException("File specification could not be parsed " + + "(should be of type 'Dictionary' or 'String'): " + fileObj.toString()); + } + } + return file; + } + + + /************************************************************************* + * Parse the windows specific launch parameters + * @param winDict + * @throws IOException - in case of a problem during parsing content + ************************************************************************/ + private WinLaunchParam parseWinDict(PDFObject winDict) throws IOException { + if (winDict == null) { + return null; + } + WinLaunchParam param = new WinLaunchParam(); + + // find and parse the file/application name + param.setFileName(PdfObjectParseUtil.parseStringFromDict("F", winDict, true)); + + // find and parse the directory + param.setDirectory(PdfObjectParseUtil.parseStringFromDict("D", winDict, false)); + + // find and parse the operation to be performed + param.setOperation(PdfObjectParseUtil.parseStringFromDict("O", winDict, false)); + + // find and parse the parameter to be passed to the application + param.setParameter(PdfObjectParseUtil.parseStringFromDict("P", winDict, false)); + + return param; + } + + /************************************************************************* + * The file / application to be opened + * @return FileSpec + ************************************************************************/ + public FileSpec getFileSpecification() { + return this.file; + } + + /************************************************************************* + * Should a new window be opened for the file/application? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } + + /************************************************************************* + * Get the unix specific launch parameters. + * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject + * which is returned here is not parsed. + * @return PDFObject + ************************************************************************/ + public PDFObject getUnixParam() { + return this.unixParam; + } + + /************************************************************************* + * Get the mac specific launch parameters. + * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject + * which is returned here is not parsed. + * @return PDFObject + ************************************************************************/ + public PDFObject getMacParam() { + return this.macParam; + } + + /************************************************************************* + * Get the windows specific launch parameters. + * @return WinLaunchParam + ************************************************************************/ + public WinLaunchParam getWinParam() { + return this.winParam; + } + + /***************************************************************************** + * Internal class for the windows specific launch parameters + * + * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 08.07.2009 + ****************************************************************************/ + public class WinLaunchParam { + private String fileName; + private String directory; + private String operation = "open"; + private String parameter; + + /************************************************************************* + * The file/application name to be opened + * @return String + ************************************************************************/ + public String getFileName() { + return this.fileName; + } + + /************************************************************************* + * The file/application name to be opened + * @param fileName + ************************************************************************/ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /************************************************************************* + * The directory in standard DOS syntax + * @return String + ************************************************************************/ + public String getDirectory() { + return this.directory; + } + + /************************************************************************* + * The directory in standard DOS syntax + * @param directory + ************************************************************************/ + public void setDirectory(String directory) { + this.directory = directory; + } + + /************************************************************************* + * The operation to be performed (open or print). Ignored + * in case the "F" parameter describes a file to be opened. + * Default is "open". + * @return String + ************************************************************************/ + public String getOperation() { + return this.operation; + } + + /************************************************************************* + * The operation to be performed ("open" or "print").Ignored + * in case the "F" parameter describes a file to be opened. + * Default is "open". + * @param operation + ************************************************************************/ + public void setOperation(String operation) { + this.operation = operation; + } + + /************************************************************************* + * A parameter which shall be passed to the application. Ignored + * in case the "F" parameter describes a file to be opened. + * @return String + ************************************************************************/ + public String getParameter() { + return this.parameter; + } + + /************************************************************************* + * A parameter which shall be passed to the application. Ignored + * in case the "F" parameter describes a file to be opened. + * @param parameter + ************************************************************************/ + public void setParameter(String parameter) { + this.parameter = parameter; + } + } + + /***************************************************************************** + * Inner class for storing a file specification + * + * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 08.07.2009 + ****************************************************************************/ + public static class FileSpec{ + private String fileSystem; + private String fileName; + private String dosFileName; + private String unixFileName; + private String macFileName; + private String unicode; + private PDFObject id; + private boolean volatileFile; + private PDFObject embeddedFile; + private PDFObject relatedFile; + private String description; + private PDFObject collectionItem; + + /************************************************************************* + * The name of the file system that should be used to interpret this entry. + * @return String + ************************************************************************/ + public String getFileSystem() { + return this.fileSystem; + } + + /************************************************************************* + * The name of the file system that should be used to interpret this entry. + * @param fileSystem + ************************************************************************/ + public void setFileSystem(String fileSystem) { + this.fileSystem = fileSystem; + } + + /************************************************************************* + * Get the filename: + * first try to get the file name for the used OS, if it's not available + * return the common file name. + * @return String + ************************************************************************/ + public String getFileName() { + String system = System.getProperty("os.name"); + if(system.startsWith("Windows")){ + if(this.dosFileName != null){ + return this.dosFileName; + } + }else if(system.startsWith("mac os x")){ + if(this.macFileName != null){ + return this.macFileName; + } + }else { + if(this.unixFileName != null){ + return this.unixFileName; + } + } + return this.fileName; + } + + /************************************************************************* + * The file name. + * @param fileName + ************************************************************************/ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /************************************************************************* + * A file specification string representing a DOS file name. + * @return String + ************************************************************************/ + public String getDosFileName() { + return this.dosFileName; + } + + /************************************************************************* + * A file specification string representing a DOS file name. + * @param dosFileName + ************************************************************************/ + public void setDosFileName(String dosFileName) { + this.dosFileName = dosFileName; + } + + /************************************************************************* + * A file specification string representing a unix file name. + * @return String + ************************************************************************/ + public String getUnixFileName() { + return this.unixFileName; + } + + /************************************************************************* + * A file specification string representing a unix file name. + * @param unixFileName + ************************************************************************/ + public void setUnixFileName(String unixFileName) { + this.unixFileName = unixFileName; + } + + /************************************************************************* + * A file specification string representing a mac file name. + * @return String + ************************************************************************/ + public String getMacFileName() { + return this.macFileName; + } + + /************************************************************************* + * A file specification string representing a mac file name. + * @param macFileName + ************************************************************************/ + public void setMacFileName(String macFileName) { + this.macFileName = macFileName; + } + + /************************************************************************* + * Unicode file name + * @return String + ************************************************************************/ + public String getUnicode() { + return this.unicode; + } + + /************************************************************************* + * Unicode file name + * @param unicode + ************************************************************************/ + public void setUnicode(String unicode) { + this.unicode = unicode; + } + + /************************************************************************* + * ID - array of two byte strings constituting a file identifier, which + * should be included in the referenced file. + * + * @return PDFObject + ************************************************************************/ + public PDFObject getId() { + return this.id; + } + + /************************************************************************* + * ID - array of two byte strings constituting a file identifier, which + * should be included in the referenced file. + * + * @param id + ************************************************************************/ + public void setId(PDFObject id) { + this.id = id; + } + + /************************************************************************* + * Is the file volatile? + * @return boolean + ************************************************************************/ + public boolean isVolatileFile() { + return this.volatileFile; + } + + /************************************************************************* + * Is the file volatile? + * @param volatileFile + ************************************************************************/ + public void setVolatileFile(boolean volatileFile) { + this.volatileFile = volatileFile; + } + + /************************************************************************* + * Dictionary of embedded file streams + * @return PDFObject + ************************************************************************/ + public PDFObject getEmbeddedFile() { + return this.embeddedFile; + } + + /************************************************************************* + * Dictionary of embedded file streams + * @param embeddedFile + ************************************************************************/ + public void setEmbeddedFile(PDFObject embeddedFile) { + this.embeddedFile = embeddedFile; + } + + /************************************************************************* + * Dictionary of related files. + * @return PDFObject + ************************************************************************/ + public PDFObject getRelatedFile() { + return this.relatedFile; + } + + /************************************************************************* + * Dictionary of related files. + * @param relatedFile + ************************************************************************/ + public void setRelatedFile(PDFObject relatedFile) { + this.relatedFile = relatedFile; + } + + /************************************************************************* + * File specification description + * @return String + ************************************************************************/ + public String getDescription() { + return this.description; + } + + /************************************************************************* + * File specification description + * @param description + ************************************************************************/ + public void setDescription(String description) { + this.description = description; + } + + /************************************************************************* + * Collection item dictionary + * @return PDFObject + ************************************************************************/ + public PDFObject getCollectionItem() { + return this.collectionItem; + } + + /************************************************************************* + * Collection item dictionary + * @param collectionItem + ************************************************************************/ + public void setCollectionItem(PDFObject collectionItem) { + this.collectionItem = collectionItem; + } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PDFAction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PDFAction.java index 224969700..656098cdf 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PDFAction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PDFAction.java @@ -60,13 +60,13 @@ public static PDFAction getAction(PDFObject obj, PDFObject root) if (type.equals("GoTo")) { action = new GoToAction(obj, root); }else if(type.equals("GoToE")){ - action = new GoToEAction(obj, root); + action = new GoToEAction(obj, root); }else if(type.equals("GoToR")){ - action = new GoToRAction(obj, root); + action = new GoToRAction(obj, root); }else if(type.equals("URI")){ - action = new UriAction(obj, root); + action = new UriAction(obj, root); }else if(type.equals("Launch")){ - action = new LaunchAction(obj, root); + action = new LaunchAction(obj, root); } else { /** [JK FIXME: Implement other action types! ] */ diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PdfObjectParseUtil.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PdfObjectParseUtil.java index 8c9e27974..a274b662d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PdfObjectParseUtil.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/PdfObjectParseUtil.java @@ -13,88 +13,88 @@ * @since 08.07.2009 ****************************************************************************/ public class PdfObjectParseUtil { - - /************************************************************************* - * Parse a String value with the given key from parent object. If it's mandatory - * and not available, an exception will be thrown. - * @param key - * @param parent - * @param mandatory - * @return String - can be null if not mandatory - * @throws IOException - in case of a parsing error - ************************************************************************/ - public static String parseStringFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ - PDFObject val = parent; - while (val.getType() == PDFObject.DICTIONARY) { - val = val.getDictRef(key); - if(val == null){ - if(mandatory){ - throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); - } - return null; - } - } - return val.getStringValue(); - } + + /************************************************************************* + * Parse a String value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return String - can be null if not mandatory + * @throws IOException - in case of a parsing error + ************************************************************************/ + public static String parseStringFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent; + while (val.getType() == PDFObject.DICTIONARY) { + val = val.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return null; + } + } + return val.getStringValue(); + } - /************************************************************************* - * Parse a Boolean value with the given key from parent object. If it's mandatory - * and not available, an exception will be thrown. - * @param key - * @param parent - * @param mandatory - * @return boolean - false if not available and not mandatory - * @throws IOException - ************************************************************************/ - public static boolean parseBooleanFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ - PDFObject val = parent.getDictRef(key); - if(val == null){ - if(mandatory){ - throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); - } - return false; - } - return val.getBooleanValue(); - } - - /************************************************************************* - * Parse a integer value with the given key from parent object. If it's mandatory - * and not available, an exception will be thrown. - * @param key - * @param parent - * @param mandatory - * @return int - returns "0" in case the value is not a number - * @throws IOException - ************************************************************************/ - public static int parseIntegerFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ - PDFObject val = parent.getDictRef(key); - if(val == null){ - if(mandatory){ - throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); - } - return 0; - } - return val.getIntValue(); - } - - /************************************************************************* - * Parse a destination object - * @param key - * @param parent - * @param root - * @param mandatory - * @return PDFDestination - can be null if not mandatory - * @throws IOException - ************************************************************************/ - public static PDFDestination parseDestination(String key, PDFObject parent, PDFObject root, boolean mandatory) throws IOException{ - PDFObject destObj = parent.getDictRef(key); - if (destObj == null) { - if(mandatory){ - throw new PDFParseException("Error parsing destination " + parent); - } - return null; - } - return PDFDestination.getDestination(destObj, root); + /************************************************************************* + * Parse a Boolean value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return boolean - false if not available and not mandatory + * @throws IOException + ************************************************************************/ + public static boolean parseBooleanFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return false; + } + return val.getBooleanValue(); + } + + /************************************************************************* + * Parse a integer value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return int - returns "0" in case the value is not a number + * @throws IOException + ************************************************************************/ + public static int parseIntegerFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return 0; + } + return val.getIntValue(); + } + + /************************************************************************* + * Parse a destination object + * @param key + * @param parent + * @param root + * @param mandatory + * @return PDFDestination - can be null if not mandatory + * @throws IOException + ************************************************************************/ + public static PDFDestination parseDestination(String key, PDFObject parent, PDFObject root, boolean mandatory) throws IOException{ + PDFObject destObj = parent.getDictRef(key); + if (destObj == null) { + if(mandatory){ + throw new PDFParseException("Error parsing destination " + parent); + } + return null; + } + return PDFDestination.getDestination(destObj, root); - } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/UriAction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/UriAction.java index 1da70f75f..09a46f073 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/action/UriAction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/action/UriAction.java @@ -12,34 +12,34 @@ ****************************************************************************/ public class UriAction extends PDFAction { - /** The URL this action links to */ - private String uri; - - /************************************************************************* - * Constructor, reading the URL from the given action object - * @param type - * @throws IOException - in case the action can not be parsed - ************************************************************************/ - public UriAction(PDFObject obj, PDFObject root) throws IOException { - super("URI"); - this.uri = PdfObjectParseUtil.parseStringFromDict("URI", obj, true); - } - - /************************************************************************* - * Constructor - * @param type - * @throws IOException - ************************************************************************/ - public UriAction(String uri) throws IOException { - super("URI"); - this.uri = uri; - } + /** The URL this action links to */ + private String uri; + + /************************************************************************* + * Constructor, reading the URL from the given action object + * @param type + * @throws IOException - in case the action can not be parsed + ************************************************************************/ + public UriAction(PDFObject obj, PDFObject root) throws IOException { + super("URI"); + this.uri = PdfObjectParseUtil.parseStringFromDict("URI", obj, true); + } + + /************************************************************************* + * Constructor + * @param type + * @throws IOException + ************************************************************************/ + public UriAction(String uri) throws IOException { + super("URI"); + this.uri = uri; + } - /************************************************************************* - * Get the URI this action directs to - * @return String - ************************************************************************/ - public String getUri() { - return this.uri; - } + /************************************************************************* + * Get the URI this action directs to + * @return String + ************************************************************************/ + public String getUri() { + return this.uri; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationBorderStyle.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationBorderStyle.java index 22f776d3d..6e5b0e45b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationBorderStyle.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationBorderStyle.java @@ -9,80 +9,80 @@ * @author Bernd Rosstauscher */ public class AnnotationBorderStyle { - - public enum BorderStyle { - SOLID("S"), - DASHED("D"), - BEVELED("B"), - INSET("I"), - UNDERLINE("U"); + + public enum BorderStyle { + SOLID("S"), + DASHED("D"), + BEVELED("B"), + INSET("I"), + UNDERLINE("U"); - private String code; - - private BorderStyle(String code) { - this.code = code; - } - - public String getCode() { - return code; - } - - public static BorderStyle fromCode(String code) { - for (BorderStyle bs : BorderStyle.values()) { - if (bs.getCode().equals(code)) { - return bs; - } - } - return SOLID; - } - - } - - private Integer width; - private BorderStyle borderStyle; - private int[] dashArray; - - /** - * Creates a annotation border style - */ - public AnnotationBorderStyle() { - super(); - } - - /** - * Parse a border style from a BS dictionary. - * @param bs the pdf dictionary to parse. - * @return the border style object. - * @throws IOException - */ - public static AnnotationBorderStyle parseFromDictionary(PDFObject bs) throws IOException { - AnnotationBorderStyle result = new AnnotationBorderStyle(); - result.width = bs.getDictRefAsInt("W"); - result.borderStyle = BorderStyle.fromCode(bs.getDictRefAsString("S")); - result.dashArray = bs.getDictRefAsIntArray("D"); - // TODO BE Border effect not supported yet - return result; - } - - /** - * @return the border style enum - */ - public BorderStyle getBorderStyle() { - return borderStyle; - } - - /** - * @return the width of the border line - */ - public Integer getWidth() { - return width; - } - - /** - * @return specifying the dash for the border line - */ - public int[] getDashArray() { - return dashArray; - } + private String code; + + private BorderStyle(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static BorderStyle fromCode(String code) { + for (BorderStyle bs : BorderStyle.values()) { + if (bs.getCode().equals(code)) { + return bs; + } + } + return SOLID; + } + + } + + private Integer width; + private BorderStyle borderStyle; + private int[] dashArray; + + /** + * Creates a annotation border style + */ + public AnnotationBorderStyle() { + super(); + } + + /** + * Parse a border style from a BS dictionary. + * @param bs the pdf dictionary to parse. + * @return the border style object. + * @throws IOException + */ + public static AnnotationBorderStyle parseFromDictionary(PDFObject bs) throws IOException { + AnnotationBorderStyle result = new AnnotationBorderStyle(); + result.width = bs.getDictRefAsInt("W"); + result.borderStyle = BorderStyle.fromCode(bs.getDictRefAsString("S")); + result.dashArray = bs.getDictRefAsIntArray("D"); + // TODO BE Border effect not supported yet + return result; + } + + /** + * @return the border style enum + */ + public BorderStyle getBorderStyle() { + return borderStyle; + } + + /** + * @return the width of the border line + */ + public Integer getWidth() { + return width; + } + + /** + * @return specifying the dash for the border line + */ + public int[] getDashArray() { + return dashArray; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationType.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationType.java index 43bc6969c..602233cf8 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationType.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/AnnotationType.java @@ -7,100 +7,100 @@ * */ public enum AnnotationType{ - UNKNOWN("-", 0, PDFAnnotation.class), - LINK("Link", 1, LinkAnnotation.class), - WIDGET("Widget", 2, WidgetAnnotation.class), - STAMP("Stamp", 3, StampAnnotation.class), - FREETEXT("FreeText", 5, FreetextAnnotation.class), - SIGNATURE("Sig", 6, WidgetAnnotation.class), + UNKNOWN("-", 0, PDFAnnotation.class), + LINK("Link", 1, LinkAnnotation.class), + WIDGET("Widget", 2, WidgetAnnotation.class), + STAMP("Stamp", 3, StampAnnotation.class), + FREETEXT("FreeText", 5, FreetextAnnotation.class), + SIGNATURE("Sig", 6, WidgetAnnotation.class), - // added more annotation types. Most of them only with basic features - // We render them all via the base class MarkupAnnotation - - TEXT("Text", 7, MarkupAnnotation.class), - LINE("Line", 8, MarkupAnnotation.class), - SQUARE("Square", 9, SquareAnnotation.class), - CIRCLE("Circle", 10, CircleAnnotation.class), - POLYGON("Polygon", 11, MarkupAnnotation.class), - POLYLINE("PolyLine", 12, MarkupAnnotation.class), - HIGHLIGHT("Highlight", 13, TextMarkupAnnotation.class), - UNDERLINE("Underline", 14, TextMarkupAnnotation.class), - SQUIGGLY("Squiggly", 15, TextMarkupAnnotation.class), - STRIKEOUT("StrikeOut", 16, TextMarkupAnnotation.class), - CARET("Caret", 17, MarkupAnnotation.class), - INK("Ink", 18, MarkupAnnotation.class), - //POPUP("Popup", 19, MarkupAnnotation.class), - FILEATTACHMENT("FileAttachment", 20, PDFAnnotation.class), - SOUND("Sound", 21, PDFAnnotation.class), - MOVIE("Movie", 22, PDFAnnotation.class), - SCREEN("Screen", 23, PDFAnnotation.class), - PRINTERMARK("PrinterMark", 24, PDFAnnotation.class), - TRAPNET("TrapNet", 25, PDFAnnotation.class), - WATERMARK("Watermark", 26, PDFAnnotation.class), - THREED("3D", 27, PDFAnnotation.class), - REDACT("Redact", 28, MarkupAnnotation.class), - ; - - /** - * @return true if this annotation type should be displayed else false. - */ - boolean displayAnnotation() { - switch(this) { - case STAMP: return Configuration.getInstance().isPrintStampAnnotations(); - case WIDGET: return Configuration.getInstance().isPrintWidgetAnnotations(); - case FREETEXT: return Configuration.getInstance().isPrintFreetextAnnotations(); - case LINK: return Configuration.getInstance().isPrintLinkAnnotations(); - case SIGNATURE: return Configuration.getInstance().isPrintSignatureFields(); - case UNKNOWN: return false; - default: { - // Fallback for all the annotation types that are currently mapped to MarkupAnnotation - return MarkupAnnotation.class.isAssignableFrom(this.className) - && Configuration.getInstance().isPrintFreetextAnnotations(); - } - } - } - - private String definition; - private int internalId; - private Class className; - - private AnnotationType(String definition, int typeId, Class className) { - this.definition = definition; - this.internalId = typeId; - this.className = className; - } - - /** - * @return the definition - */ - public String getDefinition() { - return definition; - } - /** - * @return the internalId - */ - public int getInternalId() { - return internalId; - } - - /** - * @return the className - */ - public Class getClassName() { - return className; - } - - /** - * Get annotation type by it's type - * @param definition - * @return - */ - public static AnnotationType getByDefinition(String definition) { - for (AnnotationType type : values()) { - if(type.definition.equals(definition)) { - return type; - } - } - return UNKNOWN; - } + // added more annotation types. Most of them only with basic features + // We render them all via the base class MarkupAnnotation + + TEXT("Text", 7, MarkupAnnotation.class), + LINE("Line", 8, MarkupAnnotation.class), + SQUARE("Square", 9, SquareAnnotation.class), + CIRCLE("Circle", 10, CircleAnnotation.class), + POLYGON("Polygon", 11, MarkupAnnotation.class), + POLYLINE("PolyLine", 12, MarkupAnnotation.class), + HIGHLIGHT("Highlight", 13, TextMarkupAnnotation.class), + UNDERLINE("Underline", 14, TextMarkupAnnotation.class), + SQUIGGLY("Squiggly", 15, TextMarkupAnnotation.class), + STRIKEOUT("StrikeOut", 16, TextMarkupAnnotation.class), + CARET("Caret", 17, MarkupAnnotation.class), + INK("Ink", 18, MarkupAnnotation.class), + //POPUP("Popup", 19, MarkupAnnotation.class), + FILEATTACHMENT("FileAttachment", 20, PDFAnnotation.class), + SOUND("Sound", 21, PDFAnnotation.class), + MOVIE("Movie", 22, PDFAnnotation.class), + SCREEN("Screen", 23, PDFAnnotation.class), + PRINTERMARK("PrinterMark", 24, PDFAnnotation.class), + TRAPNET("TrapNet", 25, PDFAnnotation.class), + WATERMARK("Watermark", 26, PDFAnnotation.class), + THREED("3D", 27, PDFAnnotation.class), + REDACT("Redact", 28, MarkupAnnotation.class), + ; + + /** + * @return true if this annotation type should be displayed else false. + */ + boolean displayAnnotation() { + switch(this) { + case STAMP: return Configuration.getInstance().isPrintStampAnnotations(); + case WIDGET: return Configuration.getInstance().isPrintWidgetAnnotations(); + case FREETEXT: return Configuration.getInstance().isPrintFreetextAnnotations(); + case LINK: return Configuration.getInstance().isPrintLinkAnnotations(); + case SIGNATURE: return Configuration.getInstance().isPrintSignatureFields(); + case UNKNOWN: return false; + default: { + // Fallback for all the annotation types that are currently mapped to MarkupAnnotation + return MarkupAnnotation.class.isAssignableFrom(this.className) + && Configuration.getInstance().isPrintFreetextAnnotations(); + } + } + } + + private String definition; + private int internalId; + private Class className; + + private AnnotationType(String definition, int typeId, Class className) { + this.definition = definition; + this.internalId = typeId; + this.className = className; + } + + /** + * @return the definition + */ + public String getDefinition() { + return definition; + } + /** + * @return the internalId + */ + public int getInternalId() { + return internalId; + } + + /** + * @return the className + */ + public Class getClassName() { + return className; + } + + /** + * Get annotation type by it's type + * @param definition + * @return + */ + public static AnnotationType getByDefinition(String definition) { + for (AnnotationType type : values()) { + if(type.definition.equals(definition)) { + return type; + } + } + return UNKNOWN; + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/CircleAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/CircleAnnotation.java index 63f2649a9..1c9f40965 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/CircleAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/CircleAnnotation.java @@ -10,17 +10,17 @@ * @author Bernd Rosstauscher ****************************************************************************/ public class CircleAnnotation extends MarkupAnnotation { - - // TODO Not all of this is fully implemented yet. - // But it will work if the visual representation is done via an "Appearance Stream" - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public CircleAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.CIRCLE); - - } + + // TODO Not all of this is fully implemented yet. + // But it will work if the visual representation is done via an "Appearance Stream" + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public CircleAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.CIRCLE); + + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/FreetextAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/FreetextAnnotation.java index 1de7c25a0..a2bf54850 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/FreetextAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/FreetextAnnotation.java @@ -12,13 +12,13 @@ * @since 28.03.2012 ****************************************************************************/ public class FreetextAnnotation extends MarkupAnnotation { - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public FreetextAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.FREETEXT); - } + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public FreetextAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.FREETEXT); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/LinkAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/LinkAnnotation.java index 99c7bd1f4..be3ca4497 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/LinkAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/LinkAnnotation.java @@ -27,41 +27,41 @@ ****************************************************************************/ public class LinkAnnotation extends PDFAnnotation { - private PDFAction action = null; + private PDFAction action = null; - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public LinkAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.LINK); - // a link annotation can either have an action (GoTo or URI) or a destination (DEST) - PDFObject actionObj = annotObject.getDictRef("A"); - if (actionObj != null) { - this.action = PDFAction.getAction(actionObj, annotObject.getRoot()); - } else { - // if a destination is given, create a GoToAction from it - PDFObject dest = annotObject.getDictRef("Dest"); - if(dest == null) { - dest = annotObject.getDictRef("DEST"); - } - if (dest != null) { - this.action = new GoToAction(PDFDestination.getDestination(dest, annotObject.getRoot())); - } else { - throw new PDFParseException( - "Could not parse link annotation (no Action or Destination found): " - + annotObject.toString()); - } - } - } - - /************************************************************************* - * Get the contained PDFAction - * @return PDFAction - can be null in case the contains - * a destination object - ************************************************************************/ - public PDFAction getAction() { - return this.action; - } + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public LinkAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.LINK); + // a link annotation can either have an action (GoTo or URI) or a destination (DEST) + PDFObject actionObj = annotObject.getDictRef("A"); + if (actionObj != null) { + this.action = PDFAction.getAction(actionObj, annotObject.getRoot()); + } else { + // if a destination is given, create a GoToAction from it + PDFObject dest = annotObject.getDictRef("Dest"); + if(dest == null) { + dest = annotObject.getDictRef("DEST"); + } + if (dest != null) { + this.action = new GoToAction(PDFDestination.getDestination(dest, annotObject.getRoot())); + } else { + throw new PDFParseException( + "Could not parse link annotation (no Action or Destination found): " + + annotObject.toString()); + } + } + } + + /************************************************************************* + * Get the contained PDFAction + * @return PDFAction - can be null in case the contains + * a destination object + ************************************************************************/ + public PDFAction getAction() { + return this.action; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/MarkupAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/MarkupAnnotation.java index 6f5ed4e5c..ee4c676dd 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/MarkupAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/MarkupAnnotation.java @@ -23,104 +23,104 @@ ****************************************************************************/ public class MarkupAnnotation extends PDFAnnotation { - private PDFObject onAppearance; - private PDFObject offAppearance; - private List onCmd; - private List offCmd; - private boolean appearanceStateOn; - private AnnotationBorderStyle borderStyle; - private String textLabel; - private PDFAnnotation popupAnnotation; + private PDFObject onAppearance; + private PDFObject offAppearance; + private List onCmd; + private List offCmd; + private boolean appearanceStateOn; + private AnnotationBorderStyle borderStyle; + private String textLabel; + private PDFAnnotation popupAnnotation; - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ - public MarkupAnnotation(PDFObject annotObject, AnnotationType type) throws IOException { - super(annotObject, type); - - this.textLabel = annotObject.getDictRefAsString("T"); - // TODO more is missing here like CA, RC, ... - - parsePopupAnnotation(annotObject.getDictRef("Popup")); - parseAP(annotObject.getDictRef("AP")); - parseBorderStyleDictionary(annotObject.getDictRef("BS")); - } - - /** - * Parses the appearance stream into PDF commands - * @param dictRef - * @throws IOException - */ - protected void parseAP(PDFObject dictRef) throws IOException { - if(dictRef == null) { - return; - } - PDFObject normalAP = dictRef.getDictRef("N"); - if(normalAP == null) { - return; - } - if(normalAP.getType() == PDFObject.DICTIONARY) { - this.onAppearance = normalAP.getDictRef("On"); - this.offAppearance = normalAP.getDictRef("Off"); - PDFObject as = dictRef.getDictRef("AS"); - this.appearanceStateOn = (as != null) && ("On".equals(as.getStringValue())); - }else { - this.onAppearance = normalAP; - this.offAppearance = null; - appearanceStateOn = true; - } - parseOnOffCommands(); - } + public MarkupAnnotation(PDFObject annotObject, AnnotationType type) throws IOException { + super(annotObject, type); + + this.textLabel = annotObject.getDictRefAsString("T"); + // TODO more is missing here like CA, RC, ... + + parsePopupAnnotation(annotObject.getDictRef("Popup")); + parseAP(annotObject.getDictRef("AP")); + parseBorderStyleDictionary(annotObject.getDictRef("BS")); + } + + /** + * Parses the appearance stream into PDF commands + * @param dictRef + * @throws IOException + */ + protected void parseAP(PDFObject dictRef) throws IOException { + if(dictRef == null) { + return; + } + PDFObject normalAP = dictRef.getDictRef("N"); + if(normalAP == null) { + return; + } + if(normalAP.getType() == PDFObject.DICTIONARY) { + this.onAppearance = normalAP.getDictRef("On"); + this.offAppearance = normalAP.getDictRef("Off"); + PDFObject as = dictRef.getDictRef("AS"); + this.appearanceStateOn = (as != null) && ("On".equals(as.getStringValue())); + }else { + this.onAppearance = normalAP; + this.offAppearance = null; + appearanceStateOn = true; + } + parseOnOffCommands(); + } - /** - * Parses the mouse On or Off appearance stream - * depending on which one is currently active. - * @throws IOException - */ - private void parseOnOffCommands() throws IOException { - if(onAppearance != null) { - onCmd = parseIntoPdfCommands(onAppearance); - } - if(offAppearance != null) { - offCmd = parseIntoPdfCommands(offAppearance); - } - } - - /** - * Parses the border style dictionary - * @param bs - * @throws IOException - */ - protected void parseBorderStyleDictionary(PDFObject bs) throws IOException { - if (bs != null) { - this.borderStyle = AnnotationBorderStyle.parseFromDictionary(bs); - } - } - - /** - * @return the border style or null if not specified. - */ - public AnnotationBorderStyle getBorderStyle() { - return borderStyle; - } - + /** + * Parses the mouse On or Off appearance stream + * depending on which one is currently active. + * @throws IOException + */ + private void parseOnOffCommands() throws IOException { + if(onAppearance != null) { + onCmd = parseIntoPdfCommands(onAppearance); + } + if(offAppearance != null) { + offCmd = parseIntoPdfCommands(offAppearance); + } + } + + /** + * Parses the border style dictionary + * @param bs + * @throws IOException + */ + protected void parseBorderStyleDictionary(PDFObject bs) throws IOException { + if (bs != null) { + this.borderStyle = AnnotationBorderStyle.parseFromDictionary(bs); + } + } + + /** + * @return the border style or null if not specified. + */ + public AnnotationBorderStyle getBorderStyle() { + return borderStyle; + } + /** * Parses the popup annotation * @param popupObj * @throws IOException */ private void parsePopupAnnotation(PDFObject popupObj) throws IOException { - this.popupAnnotation = (popupObj != null)?createAnnotation(popupObj):null; - } + this.popupAnnotation = (popupObj != null)?createAnnotation(popupObj):null; + } - private List parseIntoPdfCommands(PDFObject obj) throws IOException { - // TODO see also WidgetAnnotation.parseCommand which seems to be copied code - // We should merge these two + private List parseIntoPdfCommands(PDFObject obj) throws IOException { + // TODO see also WidgetAnnotation.parseCommand which seems to be copied code + // We should merge these two String type = obj.getDictRef("Subtype").getStringValue(); if (type == null) { type = obj.getDictRef ("S").getStringValue (); @@ -133,17 +133,17 @@ private List parseIntoPdfCommands(PDFObject obj) throws IOException { AffineTransform rectAt = getPositionTransformation(); result.add(PDFPage.createXFormCmd(rectAt)); - PDFImage img = PDFImage.createImage(obj, new HashMap() , false); - result.add(PDFPage.createImageCmd(img)); + PDFImage img = PDFImage.createImage(obj, new HashMap() , false); + result.add(PDFPage.createImageCmd(img)); } else if (type.equals("Form")) { - + // rats. parse it. PDFObject bobj = obj.getDictRef("BBox"); float xMin = bobj.getAt(0).getFloatValue(); float yMin = bobj.getAt(1).getFloatValue(); - float xMax = bobj.getAt(2).getFloatValue(); - float yMax = bobj.getAt(3).getFloatValue(); - Float bbox = new Rectangle2D.Float(xMin, + float xMax = bobj.getAt(2).getFloatValue(); + float yMax = bobj.getAt(3).getFloatValue(); + Float bbox = new Rectangle2D.Float(xMin, yMin, xMax - xMin, yMax - yMin); @@ -186,72 +186,72 @@ private List parseIntoPdfCommands(PDFObject obj) throws IOException { result.add(PDFPage.createPopCmd()); result.add(PDFPage.createPopCmd()); return result; - } + } - /** - * Transform to the position of the stamp annotation - * @return - */ - private AffineTransform getPositionTransformation() { - Float rect2 = getRect(); - double[] f = new double[] {1, - 0, - 0, - 1, - rect2.getMinX(), - rect2.getMinY()}; - return new AffineTransform(f); - } + /** + * Transform to the position of the stamp annotation + * @return + */ + private AffineTransform getPositionTransformation() { + Float rect2 = getRect(); + double[] f = new double[] {1, + 0, + 0, + 1, + rect2.getMinX(), + rect2.getMinY()}; + return new AffineTransform(f); + } - /** - * @return the onAppearance - */ - public PDFObject getOnAppearance() { - return onAppearance; - } + /** + * @return the onAppearance + */ + public PDFObject getOnAppearance() { + return onAppearance; + } - /** - * @return the offAppearance - */ - public PDFObject getOffAppearance() { - return offAppearance; - } + /** + * @return the offAppearance + */ + public PDFObject getOffAppearance() { + return offAppearance; + } - /** - * @return the appearanceStateOn - */ - public boolean isAppearanceStateOn() { - return appearanceStateOn; - } + /** + * @return the appearanceStateOn + */ + public boolean isAppearanceStateOn() { + return appearanceStateOn; + } - public void switchAppearance() { - this.appearanceStateOn = !this.appearanceStateOn; - } + public void switchAppearance() { + this.appearanceStateOn = !this.appearanceStateOn; + } - public PDFObject getCurrentAppearance() { - return appearanceStateOn?onAppearance:offAppearance; - } + public PDFObject getCurrentAppearance() { + return appearanceStateOn?onAppearance:offAppearance; + } - public List getCurrentCommand() { - return appearanceStateOn?onCmd:offCmd; - } + public List getCurrentCommand() { + return appearanceStateOn?onCmd:offCmd; + } - @Override - public List getPageCommandsForAnnotation() { - List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); - pageCommandsForAnnotation.addAll(getCurrentCommand()); - return pageCommandsForAnnotation; - } - - /** - * @return the popupAnnotation - */ - public PDFAnnotation getPopupAnnotation() { - return popupAnnotation; - } - - public String getTextLabel() { - return textLabel; - } + @Override + public List getPageCommandsForAnnotation() { + List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); + pageCommandsForAnnotation.addAll(getCurrentCommand()); + return pageCommandsForAnnotation; + } + + /** + * @return the popupAnnotation + */ + public PDFAnnotation getPopupAnnotation() { + return popupAnnotation; + } + + public String getTextLabel() { + return textLabel; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/PDFAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/PDFAnnotation.java index cf3e1703b..e7a7d0c0c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/PDFAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/PDFAnnotation.java @@ -23,119 +23,119 @@ * @since 03.07.2009 ****************************************************************************/ public class PDFAnnotation{ - - /** Definition of some annotation sub-types*/ - public static final String GOTO = "GoTo"; - public static final String GOTOE = "GoToE"; - public static final String GOTOR = "GoToR"; - public static final String URI = "URI"; - - public enum Flags { - UNKNOWN, // 0 - INVISIBLE, // 1 - HIDDEN, // 2 - PRINT, // 3 - NO_ZOOM, // 4 - NO_ROTATE, // 5 - NO_VIEW, // 6 - READ_ONLY, // 7 - LOCKED, // 8 - TOGGLE_NO_VIEW, // 9 - LOCKED_CONTENTS // 10 - } - - - private final PDFObject pdfObj; - private final AnnotationType type; - private final Float rect; - private final String subType; - private final String contents; - - private final String annotationName; - private String modified; - private Integer flags; - private String appearanceState; + + /** Definition of some annotation sub-types*/ + public static final String GOTO = "GoTo"; + public static final String GOTOE = "GoToE"; + public static final String GOTOR = "GoToR"; + public static final String URI = "URI"; + + public enum Flags { + UNKNOWN, // 0 + INVISIBLE, // 1 + HIDDEN, // 2 + PRINT, // 3 + NO_ZOOM, // 4 + NO_ROTATE, // 5 + NO_VIEW, // 6 + READ_ONLY, // 7 + LOCKED, // 8 + TOGGLE_NO_VIEW, // 9 + LOCKED_CONTENTS // 10 + } + + + private final PDFObject pdfObj; + private final AnnotationType type; + private final Float rect; + private final String subType; + private final String contents; + + private final String annotationName; + private String modified; + private Integer flags; + private String appearanceState; - /************************************************************************* - * Constructor - * @param annotObject - the PDFObject which contains the annotation description - * @throws IOException - ************************************************************************/ - public PDFAnnotation(PDFObject annotObject) throws IOException{ - this(annotObject, AnnotationType.UNKNOWN); - } + /************************************************************************* + * Constructor + * @param annotObject - the PDFObject which contains the annotation description + * @throws IOException + ************************************************************************/ + public PDFAnnotation(PDFObject annotObject) throws IOException{ + this(annotObject, AnnotationType.UNKNOWN); + } - /************************************************************************* - * Constructor - * @param annotObject - the PDFObject which contains the annotation description - * @throws IOException - ************************************************************************/ - public PDFAnnotation(PDFObject annotObject, AnnotationType type) throws IOException{ - this.pdfObj = annotObject; - // in case a general "PdfAnnotation" is created the type is unknown - this.type = type; - - this.subType = annotObject.getDictRefAsString("Subtype"); - this.contents = annotObject.getDictRefAsString("Contents"); - this.annotationName = annotObject.getDictRefAsString("NM"); - this.modified = annotObject.getDictRefAsString("M"); - this.flags = annotObject.getDictRefAsInt("F"); - this.appearanceState = annotObject.getDictRefAsString("AS"); - - // TODO add Border, C, StructParent, OC - - this.rect = this.parseRect(annotObject.getDictRef("Rect")); - } + /************************************************************************* + * Constructor + * @param annotObject - the PDFObject which contains the annotation description + * @throws IOException + ************************************************************************/ + public PDFAnnotation(PDFObject annotObject, AnnotationType type) throws IOException{ + this.pdfObj = annotObject; + // in case a general "PdfAnnotation" is created the type is unknown + this.type = type; + + this.subType = annotObject.getDictRefAsString("Subtype"); + this.contents = annotObject.getDictRefAsString("Contents"); + this.annotationName = annotObject.getDictRefAsString("NM"); + this.modified = annotObject.getDictRefAsString("M"); + this.flags = annotObject.getDictRefAsInt("F"); + this.appearanceState = annotObject.getDictRefAsString("AS"); + + // TODO add Border, C, StructParent, OC + + this.rect = this.parseRect(annotObject.getDictRef("Rect")); + } - /************************************************************************* - * Create a new PDF annotation object. - * - * Currently supported annotation types: - *
  • Link annotation
  • - * - * @param parent - * @return PDFAnnotation - * @throws IOException - ************************************************************************/ - public static PDFAnnotation createAnnotation(PDFObject parent) throws IOException{ - PDFObject subtypeValue = parent.getDictRef("Subtype"); - if(subtypeValue == null) { - return null; - } - String subtypeS = subtypeValue.getStringValue(); - AnnotationType annotationType = AnnotationType.getByDefinition(subtypeS); - - //if Subtype is Widget than check if it is also a Signature - if(annotationType == AnnotationType.WIDGET) { - PDFObject sigType = parent.getDictRef("FT"); - if(sigType != null) { - String sigTypeS = sigType.getStringValue(); - if(AnnotationType.getByDefinition(sigTypeS) == AnnotationType.SIGNATURE) { - annotationType = AnnotationType.getByDefinition(sigTypeS); - } - } - } - - if(annotationType.displayAnnotation()) { - Class className = annotationType.getClassName(); - - try { - if (className.equals(MarkupAnnotation.class) || className.equals(TextMarkupAnnotation.class)) { - Constructor constructor = className.getConstructor(PDFObject.class, AnnotationType.class); - return (PDFAnnotation)constructor.newInstance(parent, annotationType); - } else { - Constructor constructor = className.getConstructor(PDFObject.class); - return (PDFAnnotation)constructor.newInstance(parent); - } - } catch (Exception e) { - throw new PDFParseException("Could not parse annotation!", e); - } - } - - return null; - } + /************************************************************************* + * Create a new PDF annotation object. + * + * Currently supported annotation types: + *
  • Link annotation
  • + * + * @param parent + * @return PDFAnnotation + * @throws IOException + ************************************************************************/ + public static PDFAnnotation createAnnotation(PDFObject parent) throws IOException{ + PDFObject subtypeValue = parent.getDictRef("Subtype"); + if(subtypeValue == null) { + return null; + } + String subtypeS = subtypeValue.getStringValue(); + AnnotationType annotationType = AnnotationType.getByDefinition(subtypeS); + + //if Subtype is Widget than check if it is also a Signature + if(annotationType == AnnotationType.WIDGET) { + PDFObject sigType = parent.getDictRef("FT"); + if(sigType != null) { + String sigTypeS = sigType.getStringValue(); + if(AnnotationType.getByDefinition(sigTypeS) == AnnotationType.SIGNATURE) { + annotationType = AnnotationType.getByDefinition(sigTypeS); + } + } + } + + if(annotationType.displayAnnotation()) { + Class className = annotationType.getClassName(); + + try { + if (className.equals(MarkupAnnotation.class) || className.equals(TextMarkupAnnotation.class)) { + Constructor constructor = className.getConstructor(PDFObject.class, AnnotationType.class); + return (PDFAnnotation)constructor.newInstance(parent, annotationType); + } else { + Constructor constructor = className.getConstructor(PDFObject.class); + return (PDFAnnotation)constructor.newInstance(parent); + } + } catch (Exception e) { + throw new PDFParseException("Could not parse annotation!", e); + } + } + + return null; + } - /** + /** * Get a Rectangle2D.Float representation for a PDFObject that is an * array of four Numbers. * @param obj a PDFObject that represents an Array of exactly four @@ -157,79 +157,79 @@ public Rectangle2D.Float parseRect(PDFObject obj) throws IOException { } } - /************************************************************************* + /************************************************************************* * Get the PDF Object which contains the annotation values * @return PDFObject ************************************************************************/ - public PDFObject getPdfObj() { - return this.pdfObj; - } + public PDFObject getPdfObj() { + return this.pdfObj; + } - /************************************************************************* - * Get the annotation type - * @return int - ************************************************************************/ - public AnnotationType getType() { - return this.type; - } + /************************************************************************* + * Get the annotation type + * @return int + ************************************************************************/ + public AnnotationType getType() { + return this.type; + } - /************************************************************************* - * Get the rectangle on which the annotation should be applied to - * @return Rectangle2D.Float - ************************************************************************/ - public Float getRect() { - return this.rect; - } - - public String getSubType() { - return subType; - } - - public String getAnnotationName() { - return annotationName; - } - - public String getAppearanceState() { - return appearanceState; - } - - public String getContents() { - return contents; - } - - public Integer getFlags() { - return flags; - } - - public boolean isFlagSet(Flags flag) { - return flags != null - && BigInteger.valueOf(flags).testBit(flag.ordinal()); - } - - public String getModified() { - return modified; - } + /************************************************************************* + * Get the rectangle on which the annotation should be applied to + * @return Rectangle2D.Float + ************************************************************************/ + public Float getRect() { + return this.rect; + } + + public String getSubType() { + return subType; + } + + public String getAnnotationName() { + return annotationName; + } + + public String getAppearanceState() { + return appearanceState; + } + + public String getContents() { + return contents; + } + + public Integer getFlags() { + return flags; + } + + public boolean isFlagSet(Flags flag) { + return flags != null + && BigInteger.valueOf(flags).testBit(flag.ordinal()); + } + + public String getModified() { + return modified; + } - @Override - public String toString() { - return this.pdfObj.toString(); - } - - /** - * Get list of pdf commands for this annotation - * @return - */ - public List getPageCommandsForAnnotation() { - return new ArrayList(); - } - + @Override + public String toString() { + return this.pdfObj.toString(); + } + + /** + * Get list of pdf commands for this annotation + * @return + */ + public List getPageCommandsForAnnotation() { + return new ArrayList(); + } + - protected AffineTransform getScalingTransformation(Float bbox) { - AffineTransform at = new AffineTransform(); - double scaleHeight = getRect().getHeight()/bbox.getHeight(); + protected AffineTransform getScalingTransformation(Float bbox) { + AffineTransform at = new AffineTransform(); + double scaleHeight = getRect().getHeight()/bbox.getHeight(); double scaleWidth = getRect().getWidth()/bbox.getWidth(); at.scale(scaleWidth, scaleHeight); - return at; - } + return at; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/SquareAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/SquareAnnotation.java index 859b3511e..408a94ec0 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/SquareAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/SquareAnnotation.java @@ -10,16 +10,16 @@ * @author Bernd Rosstauscher ****************************************************************************/ public class SquareAnnotation extends MarkupAnnotation { - - // TODO Not all of this is fully implemented yet. - // But it will work if the visual representation is done via an "Appearance Stream" - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public SquareAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.SQUARE); - } + + // TODO Not all of this is fully implemented yet. + // But it will work if the visual representation is done via an "Appearance Stream" + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public SquareAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.SQUARE); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/StampAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/StampAnnotation.java index 60fa20bab..dd3f32705 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/StampAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/StampAnnotation.java @@ -14,57 +14,57 @@ ****************************************************************************/ public class StampAnnotation extends MarkupAnnotation { - private String iconName; - private List iconCommands; - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public StampAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.STAMP); - this.iconName = annotObject.getDictRefAsString("Name"); - - // No AP so use the icon name - if (iconName != null && annotObject.getDictRef("AP") == null) { - parseIconCommands(); - } - - } - - /** - * If the stamp is represented by one of the predefined icons - * this will parse it and create PDFCommands for them. - */ - private void parseIconCommands() { - // TODO Add code for the different icon constants. - // fill iconCommands - - // These command names exist. - - // Approved, Experimental, NotApproved, AsIs, Expired , - // NotForPublicRelease, Confidential, Final, Sold, - // Departmental, ForComment, TopSecret, Draft, ForPublicRelease - } - - /** - * @return the iconName - */ - public String getIconName() { - return iconName; - } - - /** - *@return the PDF commands to render this annotation - */ - @Override - public List getCurrentCommand() { - List apCommand = super.getCurrentCommand(); - if (apCommand != null) { - return apCommand; - } - return this.iconCommands; - } - + private String iconName; + private List iconCommands; + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public StampAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.STAMP); + this.iconName = annotObject.getDictRefAsString("Name"); + + // No AP so use the icon name + if (iconName != null && annotObject.getDictRef("AP") == null) { + parseIconCommands(); + } + + } + + /** + * If the stamp is represented by one of the predefined icons + * this will parse it and create PDFCommands for them. + */ + private void parseIconCommands() { + // TODO Add code for the different icon constants. + // fill iconCommands + + // These command names exist. + + // Approved, Experimental, NotApproved, AsIs, Expired , + // NotForPublicRelease, Confidential, Final, Sold, + // Departmental, ForComment, TopSecret, Draft, ForPublicRelease + } + + /** + * @return the iconName + */ + public String getIconName() { + return iconName; + } + + /** + *@return the PDF commands to render this annotation + */ + @Override + public List getCurrentCommand() { + List apCommand = super.getCurrentCommand(); + if (apCommand != null) { + return apCommand; + } + return this.iconCommands; + } + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/TextMarkupAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/TextMarkupAnnotation.java index 8bb3d6d27..4272848eb 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/TextMarkupAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/TextMarkupAnnotation.java @@ -18,58 +18,58 @@ ****************************************************************************/ public class TextMarkupAnnotation extends MarkupAnnotation { - private int[] quadPoints; - private List highlightCommands; - - /************************************************************************* - * Constructor - * @param annotObject - * @throws IOException - ************************************************************************/ - public TextMarkupAnnotation(PDFObject annotObject, AnnotationType annotationType) throws IOException { - super(annotObject, annotationType); - this.quadPoints = annotObject.getDictRefAsIntArray("QuadPoints"); - - // No AP so use the quad points and highlight mode - if (annotObject.getDictRef("AP") == null) { - parseHighlightCommands(); - } - - } - - /** - * Parse the highlight commands - */ - private void parseHighlightCommands() { - // invalid quad points - if (this.quadPoints == null || this.quadPoints.length % 4 != 0) { - return; - } - highlightCommands = new ArrayList(); - highlightCommands.add(PDFPage.createPushCmd()); - - //TODO currently we use the same code for: Highlight, Underline, Squiggle, StrikeOut - // We should also set the correct colors and such. - - // Draw a box - for (int i = 0; i < quadPoints.length; i+=4) { - GeneralPath gp = new GeneralPath(new Rectangle(quadPoints[i], quadPoints[i+1], quadPoints[i+2], quadPoints[i+3])); - highlightCommands.add(new PDFShapeCmd(gp, PDFShapeCmd.FILL, true)); - } - highlightCommands.add(PDFPage.createPopCmd()); - } - - /** - * Gets the highlight painting commands - * Use either Quads or Appearance Stream - */ - @Override - public List getCurrentCommand() { - List apCommand = super.getCurrentCommand(); - if (apCommand != null) { - return apCommand; - } - return this.highlightCommands; - } - + private int[] quadPoints; + private List highlightCommands; + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public TextMarkupAnnotation(PDFObject annotObject, AnnotationType annotationType) throws IOException { + super(annotObject, annotationType); + this.quadPoints = annotObject.getDictRefAsIntArray("QuadPoints"); + + // No AP so use the quad points and highlight mode + if (annotObject.getDictRef("AP") == null) { + parseHighlightCommands(); + } + + } + + /** + * Parse the highlight commands + */ + private void parseHighlightCommands() { + // invalid quad points + if (this.quadPoints == null || this.quadPoints.length % 4 != 0) { + return; + } + highlightCommands = new ArrayList(); + highlightCommands.add(PDFPage.createPushCmd()); + + //TODO currently we use the same code for: Highlight, Underline, Squiggle, StrikeOut + // We should also set the correct colors and such. + + // Draw a box + for (int i = 0; i < quadPoints.length; i+=4) { + GeneralPath gp = new GeneralPath(new Rectangle(quadPoints[i], quadPoints[i+1], quadPoints[i+2], quadPoints[i+3])); + highlightCommands.add(new PDFShapeCmd(gp, PDFShapeCmd.FILL, true)); + } + highlightCommands.add(PDFPage.createPopCmd()); + } + + /** + * Gets the highlight painting commands + * Use either Quads or Appearance Stream + */ + @Override + public List getCurrentCommand() { + List apCommand = super.getCurrentCommand(); + if (apCommand != null) { + return apCommand; + } + return this.highlightCommands; + } + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/WidgetAnnotation.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/WidgetAnnotation.java index c39222835..f8ce57f61 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/WidgetAnnotation.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/annotation/WidgetAnnotation.java @@ -21,162 +21,162 @@ */ public class WidgetAnnotation extends PDFAnnotation { - private String fieldValue; - private FieldType fieldType; - private String fieldName; - private PDFObject fieldValueRef; - private List cmd; + private String fieldValue; + private FieldType fieldType; + private String fieldName; + private PDFObject fieldValueRef; + private List cmd; - /** - * Type for PDF form elements - * @version $Id: WidgetAnnotation.java,v 1.2 2010-09-30 10:34:44 xphc Exp $ - * @author xphc - * @since Aug 20, 2010 - */ - public enum FieldType { - /** Button Field */ - Button("Btn"), - /** Text Field */ - Text("Tx"), - /** Choice Field */ - Choice("Ch"), - /** Signature Field */ - Signature("Sig"); - - private final String typeCode; + /** + * Type for PDF form elements + * @version $Id: WidgetAnnotation.java,v 1.2 2010-09-30 10:34:44 xphc Exp $ + * @author xphc + * @since Aug 20, 2010 + */ + public enum FieldType { + /** Button Field */ + Button("Btn"), + /** Text Field */ + Text("Tx"), + /** Choice Field */ + Choice("Ch"), + /** Signature Field */ + Signature("Sig"); + + private final String typeCode; - FieldType(String typeCode) { - this.typeCode = typeCode; - } - - static FieldType getByCode(String typeCode) { - FieldType[] values = values(); - for (FieldType value : values) { - if (value.typeCode.equals(typeCode)) - return value; - } - return null; - } - } + FieldType(String typeCode) { + this.typeCode = typeCode; + } + + static FieldType getByCode(String typeCode) { + FieldType[] values = values(); + for (FieldType value : values) { + if (value.typeCode.equals(typeCode)) + return value; + } + return null; + } + } - public WidgetAnnotation(PDFObject annotObject) throws IOException { - super(annotObject, AnnotationType.WIDGET); - - // The type of field that this dictionary describes. Field type is - // present for terminal fields but is inherited from parent if absent - // (see PDF Reference 1.7 table 8.69) - PDFObject fieldTypeRef = annotObject.getDictRef("FT"); - if (fieldTypeRef != null) { - // terminal field - this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); - } - else { - // must check parent since field type is inherited - PDFObject parent = annotObject.getDictRef("Parent"); - while (parent != null && parent.isIndirect()) { - parent = parent.dereference(); - } - if (parent != null) { - fieldTypeRef = parent.getDictRef("FT"); - this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); - } - } - - // Name defined for the field - PDFObject fieldNameRef = annotObject.getDictRef("T"); - if (fieldNameRef != null) { - this.fieldName = fieldNameRef.getTextStringValue(); - } - this.fieldValueRef = annotObject.getDictRef("V"); - if (this.fieldValueRef != null) { - this.fieldValue = this.fieldValueRef.getTextStringValue(); - } - parseAP(annotObject.getDictRef("AP")); - } - - private void parseAP(PDFObject dictRef) throws IOException { - if(dictRef == null) { - return; - } - PDFObject normalAP = dictRef.getDictRef("N"); - if(normalAP == null) { - return; - } - cmd = parseCommand(normalAP); - } - - /** - * @param obj - * @return - * @throws IOException - */ - private List parseCommand(PDFObject obj) throws IOException { - // TODO see also MarkupAnnotation.parseIntoPdfCommands() which seems to be copied code - // We should merge these two - PDFObject dictRefSubType = obj.getDictRef("Subtype"); - String type = null; - if(dictRefSubType != null) { - type = dictRefSubType.getStringValue(); - } - + public WidgetAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.WIDGET); + + // The type of field that this dictionary describes. Field type is + // present for terminal fields but is inherited from parent if absent + // (see PDF Reference 1.7 table 8.69) + PDFObject fieldTypeRef = annotObject.getDictRef("FT"); + if (fieldTypeRef != null) { + // terminal field + this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); + } + else { + // must check parent since field type is inherited + PDFObject parent = annotObject.getDictRef("Parent"); + while (parent != null && parent.isIndirect()) { + parent = parent.dereference(); + } + if (parent != null) { + fieldTypeRef = parent.getDictRef("FT"); + this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); + } + } + + // Name defined for the field + PDFObject fieldNameRef = annotObject.getDictRef("T"); + if (fieldNameRef != null) { + this.fieldName = fieldNameRef.getTextStringValue(); + } + this.fieldValueRef = annotObject.getDictRef("V"); + if (this.fieldValueRef != null) { + this.fieldValue = this.fieldValueRef.getTextStringValue(); + } + parseAP(annotObject.getDictRef("AP")); + } + + private void parseAP(PDFObject dictRef) throws IOException { + if(dictRef == null) { + return; + } + PDFObject normalAP = dictRef.getDictRef("N"); + if(normalAP == null) { + return; + } + cmd = parseCommand(normalAP); + } + + /** + * @param obj + * @return + * @throws IOException + */ + private List parseCommand(PDFObject obj) throws IOException { + // TODO see also MarkupAnnotation.parseIntoPdfCommands() which seems to be copied code + // We should merge these two + PDFObject dictRefSubType = obj.getDictRef("Subtype"); + String type = null; + if(dictRefSubType != null) { + type = dictRefSubType.getStringValue(); + } + if (type == null) { - PDFObject dictRefS = obj.getDictRef("S"); - if(dictRefS != null) { - type = dictRefS.getStringValue(); - } + PDFObject dictRefS = obj.getDictRef("S"); + if(dictRefS != null) { + type = dictRefS.getStringValue(); + } } //if type is still null, check for AcroForm, if AcroForm is available the PDF could be not compatible //with the PDF specification, anyway check if obj is in AcroForm, if so, proceed as for a good PDF if(type == null) { - PDFObject acroForm = obj.getRoot().getDictRef("AcroForm"); - PDFObject fields = acroForm.getDictRef("Fields"); - PDFObject[] arrayFields = fields.getArray(); - - for (PDFObject pdfObject : arrayFields) { - PDFObject dictRefAP = pdfObject.getDictRef("AP"); - if(dictRefAP != null) { - PDFObject dictRefN = dictRefAP.getDictRef("N"); - - if(dictRefN.equals(obj)) { - PDFObject dictRefAS = pdfObject.getDictRef("AS"); - if(dictRefAS != null) { //this is a combobox - PDFObject dictRef = dictRefN.getDictRef(dictRefAS.getStringValue()); - obj = dictRef; - } - - type = "Form"; - break; - } - } - } - - if(type == null) { //check for radiobutton - PDFObject dictRef = obj.getDictRef("Off"); - if(dictRef != null) { - for (PDFObject pdfObject : arrayFields) { - PDFObject dictRefT = pdfObject.getDictRef("T"); - if(dictRefT != null && dictRefT.getStringValue().contains("Group")) { - PDFObject kids = pdfObject.getDictRef("Kids"); - PDFObject[] arrayKids = kids.getArray(); - for (PDFObject kid : arrayKids) { - PDFObject kidAP = kid.getDictRef("AP"); - PDFObject kidN = kidAP.getDictRef("N"); - if(kidN.equals(obj)) { - PDFObject kidAS = kid.getDictRef("AS"); - if(kidAS != null) { - PDFObject kidRef = kidN.getDictRef(kidAS.getStringValue()); - obj = kidRef; - } - - type = "Form"; - break; - } - } - } - } - } - } + PDFObject acroForm = obj.getRoot().getDictRef("AcroForm"); + PDFObject fields = acroForm.getDictRef("Fields"); + PDFObject[] arrayFields = fields.getArray(); + + for (PDFObject pdfObject : arrayFields) { + PDFObject dictRefAP = pdfObject.getDictRef("AP"); + if(dictRefAP != null) { + PDFObject dictRefN = dictRefAP.getDictRef("N"); + + if(dictRefN.equals(obj)) { + PDFObject dictRefAS = pdfObject.getDictRef("AS"); + if(dictRefAS != null) { //this is a combobox + PDFObject dictRef = dictRefN.getDictRef(dictRefAS.getStringValue()); + obj = dictRef; + } + + type = "Form"; + break; + } + } + } + + if(type == null) { //check for radiobutton + PDFObject dictRef = obj.getDictRef("Off"); + if(dictRef != null) { + for (PDFObject pdfObject : arrayFields) { + PDFObject dictRefT = pdfObject.getDictRef("T"); + if(dictRefT != null && dictRefT.getStringValue().contains("Group")) { + PDFObject kids = pdfObject.getDictRef("Kids"); + PDFObject[] arrayKids = kids.getArray(); + for (PDFObject kid : arrayKids) { + PDFObject kidAP = kid.getDictRef("AP"); + PDFObject kidN = kidAP.getDictRef("N"); + if(kidN.equals(obj)) { + PDFObject kidAS = kid.getDictRef("AS"); + if(kidAS != null) { + PDFObject kidRef = kidN.getDictRef(kidAS.getStringValue()); + obj = kidRef; + } + + type = "Form"; + break; + } + } + } + } + } + } } ArrayList result = new ArrayList(); @@ -187,8 +187,8 @@ private List parseCommand(PDFObject obj) throws IOException { AffineTransform rectAt = getPositionTransformation(); result.add(PDFPage.createXFormCmd(rectAt)); - PDFImage img = PDFImage.createImage(obj, new HashMap() , false); - result.add(PDFPage.createImageCmd(img)); + PDFImage img = PDFImage.createImage(obj, new HashMap() , false); + result.add(PDFPage.createImageCmd(img)); } else if ("Form".equals(type)) { // rats. parse it. PDFObject bobj = obj.getDictRef("BBox"); @@ -234,67 +234,67 @@ private List parseCommand(PDFObject obj) throws IOException { result.add(PDFPage.createPopCmd()); result.add(PDFPage.createPopCmd()); return result; - } - - /** - * Transform to the position of the stamp annotation - * @return - */ - private AffineTransform getPositionTransformation() { - Float rect2 = getRect(); - double[] f = new double[] {1, - 0, - 0, - 1, - rect2.getMinX(), - rect2.getMinY()}; - return new AffineTransform(f); - } + } + + /** + * Transform to the position of the stamp annotation + * @return + */ + private AffineTransform getPositionTransformation() { + Float rect2 = getRect(); + double[] f = new double[] {1, + 0, + 0, + 1, + rect2.getMinX(), + rect2.getMinY()}; + return new AffineTransform(f); + } - /** - * Returns the type of the field - * @return Field type - */ - public FieldType getFieldType() { - return this.fieldType; - } - - /** - * The field's value as a string. Might be {@code null}. - * @return The field value or {@code null}. - */ - public String getFieldValue() { - return this.fieldValue; - } + /** + * Returns the type of the field + * @return Field type + */ + public FieldType getFieldType() { + return this.fieldType; + } + + /** + * The field's value as a string. Might be {@code null}. + * @return The field value or {@code null}. + */ + public String getFieldValue() { + return this.fieldValue; + } - /** - * Sets the field value for a text field. Note: this doesn't actually change - * the PDF file yet. - * - * @param fieldValue - * The new value for the text field - */ - public void setFieldValue(String fieldValue) { - this.fieldValue = fieldValue; - } + /** + * Sets the field value for a text field. Note: this doesn't actually change + * the PDF file yet. + * + * @param fieldValue + * The new value for the text field + */ + public void setFieldValue(String fieldValue) { + this.fieldValue = fieldValue; + } - /** - * Name for this widget. - * @return Widget name - */ - public String getFieldName() { - return this.fieldName; - } - - @Override - public List getPageCommandsForAnnotation() { - List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); - // cmd might be null if there is no AP (appearance dictionary) - // AP is optional see PDF Reference 1.7 table 8.15 - if (this.cmd != null) { - pageCommandsForAnnotation.addAll(this.cmd); - } - return pageCommandsForAnnotation; - } - + /** + * Name for this widget. + * @return Widget name + */ + public String getFieldName() { + return this.fieldName; + } + + @Override + public List getPageCommandsForAnnotation() { + List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); + // cmd might be null if there is no AP (appearance dictionary) + // AP is optional see PDF Reference 1.7 table 8.15 + if (this.cmd != null) { + pageCommandsForAnnotation.addAll(this.cmd); + } + return pageCommandsForAnnotation; + } + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AltColorSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AltColorSpace.java index 630979b23..fb392ce7c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AltColorSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AltColorSpace.java @@ -13,61 +13,61 @@ ****************************************************************************/ public class AltColorSpace extends ColorSpace { - private PDFFunction fkt; - private ColorSpace origCs; - /** - * Create a new CMYKColorSpace Instance. - */ - public AltColorSpace(PDFFunction fkt, ColorSpace origCs) { - super(origCs.getType(), fkt.getNumInputs()); - this.fkt = fkt; - this.origCs = origCs; - } + private PDFFunction fkt; + private ColorSpace origCs; + /** + * Create a new CMYKColorSpace Instance. + */ + public AltColorSpace(PDFFunction fkt, ColorSpace origCs) { + super(origCs.getType(), fkt.getNumInputs()); + this.fkt = fkt; + this.origCs = origCs; + } - /** - * Converts from CIEXYZ. - * - * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) - * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ - */ - @Override - public float[] fromCIEXYZ(float[] p_colorvalue) { - p_colorvalue = this.fkt.calculate(p_colorvalue); - return this.origCs.fromCIEXYZ(p_colorvalue); - } + /** + * Converts from CIEXYZ. + * + * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) + * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ + */ + @Override + public float[] fromCIEXYZ(float[] p_colorvalue) { + p_colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.fromCIEXYZ(p_colorvalue); + } - /** - * Converts a given RGB. - * - * @param p_rgbvalue - The color to translate - * @return a float[4] of the CMYK values. - * @see java.awt.color.ColorSpace#fromRGB(float[]) - */ - @Override - public float[] fromRGB(float[] p_rgbvalue) { - p_rgbvalue = this.fkt.calculate(p_rgbvalue); - return this.origCs.fromCIEXYZ(p_rgbvalue); - } + /** + * Converts a given RGB. + * + * @param p_rgbvalue - The color to translate + * @return a float[4] of the CMYK values. + * @see java.awt.color.ColorSpace#fromRGB(float[]) + */ + @Override + public float[] fromRGB(float[] p_rgbvalue) { + p_rgbvalue = this.fkt.calculate(p_rgbvalue); + return this.origCs.fromCIEXYZ(p_rgbvalue); + } - /** - * Converts to CIEXYZ. - * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) - */ - @Override - public float[] toCIEXYZ(float[] p_colorvalue) { - float[] colorvalue = this.fkt.calculate(p_colorvalue); - return this.origCs.toCIEXYZ(colorvalue); - } + /** + * Converts to CIEXYZ. + * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) + */ + @Override + public float[] toCIEXYZ(float[] p_colorvalue) { + float[] colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.toCIEXYZ(colorvalue); + } - /** - * Converts to RGB. - * - * @param p_colorvalue The color in CMYK. - * @see java.awt.color.ColorSpace#toRGB(float[]) - */ - @Override - public float[] toRGB(float[] p_colorvalue) { - float[] colorvalue = this.fkt.calculate(p_colorvalue); - return this.origCs.toRGB(colorvalue); - } + /** + * Converts to RGB. + * + * @param p_colorvalue The color in CMYK. + * @see java.awt.color.ColorSpace#toRGB(float[]) + */ + @Override + public float[] toRGB(float[] p_colorvalue) { + float[] colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.toRGB(colorvalue); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AlternateColorSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AlternateColorSpace.java index 3e933c9ef..2c417a7e2 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AlternateColorSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/AlternateColorSpace.java @@ -50,7 +50,7 @@ public AlternateColorSpace(PDFColorSpace alternate, PDFFunction function) { * get the number of components expected in the getPaint command */ @Override public int getNumComponents() { - if (this.function != null) { + if (this.function != null) { return this.function.getNumInputs(); } else { return this.alternate.getNumComponents(); @@ -78,18 +78,18 @@ public AlternateColorSpace(PDFColorSpace alternate, PDFFunction function) { * get the original Java ColorSpace. */ @Override public ColorSpace getColorSpace() { - if (altcolorspace == null) altcolorspace = new AltColorSpace(function, alternate.getColorSpace()); - return altcolorspace; - //return this.alternate.getColorSpace(); + if (altcolorspace == null) altcolorspace = new AltColorSpace(function, alternate.getColorSpace()); + return altcolorspace; + //return this.alternate.getColorSpace(); } - /************************************************************************* - * Get the PDF function - * @return PDFFunction - ************************************************************************/ - public PDFFunction getFunktion() { - return this.function; - } - - + /************************************************************************* + * Get the PDF function + * @return PDFFunction + ************************************************************************/ + public PDFFunction getFunktion() { + return this.function; + } + + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CMYKColorSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CMYKColorSpace.java index bddfd7ce1..0385a0cff 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CMYKColorSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CMYKColorSpace.java @@ -37,12 +37,12 @@ */ public class CMYKColorSpace extends ColorSpace { - private ICC_Profile icc; - private ICC_ColorSpace icc_cs; - - /** - * Create a new CMYKColorSpace Instance. - */ + private ICC_Profile icc; + private ICC_ColorSpace icc_cs; + + /** + * Create a new CMYKColorSpace Instance. + */ public CMYKColorSpace() { super(ColorSpace.TYPE_CMYK, 4); @@ -66,131 +66,131 @@ public CMYKColorSpace() { - /** - * Converts to CMYK from CIEXYZ. We cheat here, using the RGB colorspace - * to do the math for us. The toCIEXYZ function has a description of how - * this is supposed to work, which may be implemented in the future. - * - * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) - * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ - */ - @Override - public float[] fromCIEXYZ(float[] p_colorvalue) { - if (icc_cs != null) { - return icc_cs.fromCIEXYZ(p_colorvalue); - } - ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB); - float[] l_rgb = l_cs.toCIEXYZ(p_colorvalue); - return fromRGB(l_rgb); - } - - /** - * Converts a given RGB to CMYK. RGB doesn't really use black, so K will - * always be 0. On printers, the black should actually look dark brown. - * RGB (an additive space) is simply the backwards from CMY (a subtractive - * space), so all we do is: - * - * C = 1-R - * M = 1-G - * Y = 1-B - * - * @param p_rgbvalue - The color to translate - * @return a float[4] of the CMYK values. - * @see java.awt.color.ColorSpace#fromRGB(float[]) - */ - @Override - public float[] fromRGB(float[] p_rgbvalue) { - if (icc_cs != null) { - return icc_cs.fromRGB(p_rgbvalue); - } - - /* TODO: Maybe we should do a better job to determine when black should - * be used and pulled out? -- At this time, it's not necessary for our - * (Scantegrity's) uses. - */ - float[] l_res = {0,0,0,0}; - if (p_rgbvalue.length >= 3) { - l_res[0] = (float)1.0 - p_rgbvalue[0]; - l_res[1] = (float)1.0 - p_rgbvalue[1]; - l_res[2] = (float)1.0 - p_rgbvalue[2]; - } - return normalize(l_res); - } - - /** - * Converts the CMYK color to CIEXYZ. Because CIEXYZ is 3-component, we - * cheat, converting to RGB and then using the RGB colorspace function - * to do the conversion. Details on this colorspace are available on - * wikipedia: - * - * http://en.wikipedia.org/wiki/CIE_XYZ_color_space - * - * There is also an "ideal relationship" to CMYK, which might be implemented - * in the future (don't recall the reference we got this from, probably - * color.org): - * - * C = (C' - K)/(1 - K) - * M = (M' - K)/(1 - K) - * Y = (Y' - K)/(1 - K) - * K = Min(C', M', Y') - * - * X 41.2453 35.7580 18.0423 | 1-C' - * Y = 21.2671 71.5160 07.2169 | 1-M' - * Z 01.9334 11.9193 95.0227 | 1-Y' - * - * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) - */ - @Override - public float[] toCIEXYZ(float[] p_colorvalue) { - if (icc_cs != null) { - return icc_cs.toCIEXYZ(p_colorvalue); - } - - float[] l_rgb = toRGB(p_colorvalue); - ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB); - return l_cs.toCIEXYZ(l_rgb); - } - - /** - * Converts CMYK colors to RGB. Note that converting back will be lossy. The - * formula for this is: - * - * K = 1 - K (go to additive) - * R = K * (1 - C) - * G = K * (1 - M) - * B = K * (1 - Y) - * - * @param p_colorvalue The color in CMYK. - * @see java.awt.color.ColorSpace#toRGB(float[]) - */ - @Override - public float[] toRGB(float[] p_colorvalue) { - if (icc_cs != null) { - return icc_cs.toRGB(p_colorvalue); - } - float[] l_res = {0,0,0}; - if (p_colorvalue.length >= 4) - { - float l_black = (float)1.0 - p_colorvalue[3]; - l_res[0] = l_black * ((float)1.0 - p_colorvalue[0]); - l_res[1] = l_black * ((float)1.0 - p_colorvalue[1]); - l_res[2] = l_black * ((float)1.0 - p_colorvalue[2]); - } - return normalize(l_res); - } - - /** - * Normalize ensures all color values returned are between 0 and 1. - * - * @param p_colors - * @return p_colors, with any values greater than 1 set to 1, and less than - * 0 set to 0. - */ - public float[] normalize(float[] p_colors) { - for (int l_i = 0; l_i < p_colors.length; l_i++) { - if (p_colors[l_i] > (float)1.0) p_colors[l_i] = (float)1.0; - else if (p_colors[l_i] < (float)0.0) p_colors[l_i] = (float)0.0; - } - return p_colors; - } + /** + * Converts to CMYK from CIEXYZ. We cheat here, using the RGB colorspace + * to do the math for us. The toCIEXYZ function has a description of how + * this is supposed to work, which may be implemented in the future. + * + * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) + * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ + */ + @Override + public float[] fromCIEXYZ(float[] p_colorvalue) { + if (icc_cs != null) { + return icc_cs.fromCIEXYZ(p_colorvalue); + } + ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB); + float[] l_rgb = l_cs.toCIEXYZ(p_colorvalue); + return fromRGB(l_rgb); + } + + /** + * Converts a given RGB to CMYK. RGB doesn't really use black, so K will + * always be 0. On printers, the black should actually look dark brown. + * RGB (an additive space) is simply the backwards from CMY (a subtractive + * space), so all we do is: + * + * C = 1-R + * M = 1-G + * Y = 1-B + * + * @param p_rgbvalue - The color to translate + * @return a float[4] of the CMYK values. + * @see java.awt.color.ColorSpace#fromRGB(float[]) + */ + @Override + public float[] fromRGB(float[] p_rgbvalue) { + if (icc_cs != null) { + return icc_cs.fromRGB(p_rgbvalue); + } + + /* TODO: Maybe we should do a better job to determine when black should + * be used and pulled out? -- At this time, it's not necessary for our + * (Scantegrity's) uses. + */ + float[] l_res = {0,0,0,0}; + if (p_rgbvalue.length >= 3) { + l_res[0] = (float)1.0 - p_rgbvalue[0]; + l_res[1] = (float)1.0 - p_rgbvalue[1]; + l_res[2] = (float)1.0 - p_rgbvalue[2]; + } + return normalize(l_res); + } + + /** + * Converts the CMYK color to CIEXYZ. Because CIEXYZ is 3-component, we + * cheat, converting to RGB and then using the RGB colorspace function + * to do the conversion. Details on this colorspace are available on + * wikipedia: + * + * http://en.wikipedia.org/wiki/CIE_XYZ_color_space + * + * There is also an "ideal relationship" to CMYK, which might be implemented + * in the future (don't recall the reference we got this from, probably + * color.org): + * + * C = (C' - K)/(1 - K) + * M = (M' - K)/(1 - K) + * Y = (Y' - K)/(1 - K) + * K = Min(C', M', Y') + * + * X 41.2453 35.7580 18.0423 | 1-C' + * Y = 21.2671 71.5160 07.2169 | 1-M' + * Z 01.9334 11.9193 95.0227 | 1-Y' + * + * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) + */ + @Override + public float[] toCIEXYZ(float[] p_colorvalue) { + if (icc_cs != null) { + return icc_cs.toCIEXYZ(p_colorvalue); + } + + float[] l_rgb = toRGB(p_colorvalue); + ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB); + return l_cs.toCIEXYZ(l_rgb); + } + + /** + * Converts CMYK colors to RGB. Note that converting back will be lossy. The + * formula for this is: + * + * K = 1 - K (go to additive) + * R = K * (1 - C) + * G = K * (1 - M) + * B = K * (1 - Y) + * + * @param p_colorvalue The color in CMYK. + * @see java.awt.color.ColorSpace#toRGB(float[]) + */ + @Override + public float[] toRGB(float[] p_colorvalue) { + if (icc_cs != null) { + return icc_cs.toRGB(p_colorvalue); + } + float[] l_res = {0,0,0}; + if (p_colorvalue.length >= 4) + { + float l_black = (float)1.0 - p_colorvalue[3]; + l_res[0] = l_black * ((float)1.0 - p_colorvalue[0]); + l_res[1] = l_black * ((float)1.0 - p_colorvalue[1]); + l_res[2] = l_black * ((float)1.0 - p_colorvalue[2]); + } + return normalize(l_res); + } + + /** + * Normalize ensures all color values returned are between 0 and 1. + * + * @param p_colors + * @return p_colors, with any values greater than 1 set to 1, and less than + * 0 set to 0. + */ + public float[] normalize(float[] p_colors) { + for (int l_i = 0; l_i < p_colors.length; l_i++) { + if (p_colors[l_i] > (float)1.0) p_colors[l_i] = (float)1.0; + else if (p_colors[l_i] < (float)0.0) p_colors[l_i] = (float)0.0; + } + return p_colors; + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalGrayColor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalGrayColor.java index 8c155c2db..9bb1401b6 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalGrayColor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalGrayColor.java @@ -41,27 +41,27 @@ public class CalGrayColor extends ColorSpace { * for "WhitePoint" and "BlackPoint", and a Number for "Gamma" */ public CalGrayColor(PDFObject obj) throws IOException { - // obj is a dictionary that has the following parts: - // WhitePoint [a b c] - // BlackPoint [a b c] - // Gamma a - super(TYPE_GRAY, 1); - PDFObject ary= obj.getDictRef("WhitePoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.white[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("BlackPoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.black[i]= ary.getAt(i).getFloatValue(); - } - } - PDFObject g= obj.getDictRef("Gamma"); - if (g!=null) { - this.gamma= g.getFloatValue(); - } + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(TYPE_GRAY, 1); + PDFObject ary= obj.getDictRef("WhitePoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + PDFObject g= obj.getDictRef("Gamma"); + if (g!=null) { + this.gamma= g.getFloatValue(); + } } /** @@ -76,7 +76,7 @@ public CalGrayColor() { * get the number of components (1). */ @Override public int getNumComponents() { - return 1; + return 1; } /** @@ -85,49 +85,49 @@ public CalGrayColor() { * @return the RGB values (0-1) */ @Override - public float[] toRGB(float comp[]) { - if (comp.length==1) { - float mul= (float)Math.pow(comp[0], this.gamma); - float xyz[] = { - this.white[0]*mul, - 0, - 0}; - float rgb[]= cie.fromCIEXYZ(xyz); - return rgb; - } else { - return this.black; - } + public float[] toRGB(float comp[]) { + if (comp.length==1) { + float mul= (float)Math.pow(comp[0], this.gamma); + float xyz[] = { + this.white[0]*mul, + 0, + 0}; + float rgb[]= cie.fromCIEXYZ(xyz); + return rgb; + } else { + return this.black; + } } /** * convert from RGB to Calibrated Gray. NOT IMPLEMENTED */ @Override - public float[] fromRGB(float[] rgbvalue) { - return new float[1]; + public float[] fromRGB(float[] rgbvalue) { + return new float[1]; } /** * convert from CIEXYZ to Calibrated Gray. NOT IMPLEMENTED */ @Override - public float[] fromCIEXYZ(float[] colorvalue) { - return new float[1]; + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[1]; } /** * get the type of this ColorSpace (TYPE_GRAY) */ @Override public int getType() { - return TYPE_GRAY; + return TYPE_GRAY; } /** * convert from Calibrated Gray to CIEXYZ. NOT IMPLEMENTED */ @Override - public float[] toCIEXYZ(float[] colorvalue) { - return new float[3]; + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalRGBColor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalRGBColor.java index b1f557825..64d06a295 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalRGBColor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/CalRGBColor.java @@ -65,11 +65,11 @@ public class CalRGBColor extends ColorSpace { * an array of 9 Numbers for "Matrix". */ public CalRGBColor(PDFObject obj) throws IOException { - // obj is a dictionary that has the following parts: - // WhitePoint [a b c] - // BlackPoint [a b c] - // Gamma a - super(CS_sRGB, 3); + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(CS_sRGB, 3); // find out what what is according to the CIE color space // note that this is not reflexive (i.e. passing this value @@ -77,29 +77,29 @@ public CalRGBColor(PDFObject obj) throws IOException { // cieWhite = cieCS.fromRGB(new float[] { 1.0f, 1.0f, 1.0f } ); PDFObject ary= obj.getDictRef("WhitePoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.white[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("BlackPoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.black[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("Gamma"); - if (ary!=null) { - for (int i=0; i<3; i++) { - this.gamma[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("Matrix"); - if (ary!=null) { - for (int i=0; i<9; i++) { - this.matrix[i]= ary.getAt(i).getFloatValue(); - } - } + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Gamma"); + if (ary!=null) { + for (int i=0; i<3; i++) { + this.gamma[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Matrix"); + if (ary!=null) { + for (int i=0; i<9; i++) { + this.matrix[i]= ary.getAt(i).getFloatValue(); + } + } // create a scale matrix relative to the 50 CIE color space. // see http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html @@ -123,7 +123,7 @@ public CalRGBColor(PDFObject obj) throws IOException { * get the number of components (3) */ @Override public int getNumComponents() { - return 3; + return 3; } /** @@ -132,19 +132,19 @@ public CalRGBColor(PDFObject obj) throws IOException { * @return the RGB values (0-1) */ @Override - public float[] toRGB(float comp[]) { - if (comp.length==3) { + public float[] toRGB(float comp[]) { + if (comp.length==3) { // compute r', g' and b' by raising the given values to the // correct gamma - float a = (float)Math.pow(comp[0], this.gamma[0]); - float b = (float)Math.pow(comp[1], this.gamma[1]); - float c = (float)Math.pow(comp[2], this.gamma[2]); - + float a = (float)Math.pow(comp[0], this.gamma[0]); + float b = (float)Math.pow(comp[1], this.gamma[1]); + float c = (float)Math.pow(comp[2], this.gamma[2]); + // now multiply by the matrix to get X, Y and Z values float[] xyz = new float[] { - this.matrix[0]*a + this.matrix[3]*b + this.matrix[6]*c, - this.matrix[1]*a + this.matrix[4]*b + this.matrix[7]*c, - this.matrix[2]*a + this.matrix[5]*b + this.matrix[8]*c}; + this.matrix[0]*a + this.matrix[3]*b + this.matrix[6]*c, + this.matrix[1]*a + this.matrix[4]*b + this.matrix[7]*c, + this.matrix[2]*a + this.matrix[5]*b + this.matrix[8]*c}; // now scale the xyz values xyz = matrixMult(xyz, this.scale, 3); @@ -163,9 +163,9 @@ public float[] toRGB(float comp[]) { } return rgb; - } else { - return this.black; - } + } else { + return this.black; + } } /** @@ -196,31 +196,31 @@ private float[] ciexyzToSRGB(float[] xyz) { * convert from RGB to Calibrated RGB. NOT IMPLEMENTED */ @Override - public float[] fromRGB(float[] rgbvalue) { - return new float[3]; + public float[] fromRGB(float[] rgbvalue) { + return new float[3]; } /** * convert from CIEXYZ to Calibrated RGB. NOT IMPLEMENTED */ @Override - public float[] fromCIEXYZ(float[] colorvalue) { - return new float[3]; + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[3]; } /** * get the type of this color space (TYPE_RGB) */ @Override public int getType() { - return TYPE_RGB; + return TYPE_RGB; } /** * convert from Calibrated RGB to CIEXYZ. NOT IMPLEMENTED */ @Override - public float[] toCIEXYZ(float[] colorvalue) { - return new float[3]; + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; } /** diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/LabColor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/LabColor.java index f791c3c12..1d762b9bd 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/LabColor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/LabColor.java @@ -42,36 +42,36 @@ public class LabColor extends ColorSpace { * "Range". */ public LabColor(PDFObject obj) throws IOException { - // obj is a dictionary that has the following parts: - // WhitePoint [a b c] - // BlackPoint [a b c] - // Gamma a - super(TYPE_Lab, 3); - PDFObject ary= obj.getDictRef("WhitePoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.white[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("BlackPoint"); - if (ary!=null) { - for(int i=0; i<3; i++) { - this.black[i]= ary.getAt(i).getFloatValue(); - } - } - ary= obj.getDictRef("Range"); - if (ary!=null) { - for (int i=0; i<4; i++) { - this.range[i]= ary.getAt(i).getFloatValue(); - } - } + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(TYPE_Lab, 3); + PDFObject ary= obj.getDictRef("WhitePoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Range"); + if (ary!=null) { + for (int i=0; i<4; i++) { + this.range[i]= ary.getAt(i).getFloatValue(); + } + } } /** * get the number of components for this color space (3) */ @Override public int getNumComponents() { - return 3; + return 3; } /** @@ -79,7 +79,7 @@ public LabColor(PDFObject obj) throws IOException { * it gets invoked for each component */ public final float stage2(float s1) { - return (s1>=6f/29f)?s1*s1*s1:108f/841f*(s1-4f/29f); + return (s1>=6f/29f)?s1*s1*s1:108f/841f*(s1-4f/29f); } /** @@ -88,51 +88,51 @@ public final float stage2(float s1) { * @return the RGB values (0-1) */ @Override - public float[] toRGB(float comp[]) { - if (comp.length==3) { - float l= (comp[0]+16)/116+comp[1]/500; - float m= (comp[0]+16)/116; - float n= (comp[0]+16)/116-comp[2]/200; - float xyz[]= { - this.white[0]*stage2(l), - this.white[0]*stage2(m), - this.white[0]*stage2(n)}; - float rgb[]= cie.fromCIEXYZ(xyz); - return rgb; - } else { - return this.black; - } + public float[] toRGB(float comp[]) { + if (comp.length==3) { + float l= (comp[0]+16)/116+comp[1]/500; + float m= (comp[0]+16)/116; + float n= (comp[0]+16)/116-comp[2]/200; + float xyz[]= { + this.white[0]*stage2(l), + this.white[0]*stage2(m), + this.white[0]*stage2(n)}; + float rgb[]= cie.fromCIEXYZ(xyz); + return rgb; + } else { + return this.black; + } } /** * convert from RGB to Lab. NOT IMPLEMENTED */ @Override - public float[] fromRGB(float[] rgbvalue) { - return new float[3]; + public float[] fromRGB(float[] rgbvalue) { + return new float[3]; } /** * convert from CIEXYZ to Lab. NOT IMPLEMENTED */ @Override - public float[] fromCIEXYZ(float[] colorvalue) { - return new float[3]; + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[3]; } /** * get the type of this colorspace (TYPE_Lab) */ @Override public int getType() { - return TYPE_Lab; + return TYPE_Lab; } /** * convert from Lab to CIEXYZ. NOT IMPLEMENTED */ @Override - public float[] toCIEXYZ(float[] colorvalue) { - return new float[3]; + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/MaskColorSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/MaskColorSpace.java index 8e20a8beb..0f41e8cdb 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/MaskColorSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/MaskColorSpace.java @@ -41,7 +41,7 @@ public MaskColorSpace(PDFPaint paint) { } @Override - public float[] fromCIEXYZ(float[] colorvalue) { + public float[] fromCIEXYZ(float[] colorvalue) { float x = colorvalue[0]; float y = colorvalue[1]; float z = colorvalue[2]; @@ -58,7 +58,7 @@ public float[] fromCIEXYZ(float[] colorvalue) { } @Override - public float[] fromRGB(float[] rgbvalue) { + public float[] fromRGB(float[] rgbvalue) { float r = rgbvalue[0]; float g = rgbvalue[1]; float b = rgbvalue[2]; @@ -79,23 +79,23 @@ public float[] fromRGB(float[] rgbvalue) { float[] prev0= this.cie.fromRGB(toRGB(new float[] {0.0f})); @Override - public float[] toCIEXYZ(float[] colorvalue) { - if (colorvalue[0]==1) { - return this.prev1; - } else if (colorvalue[0]==0) { - return this.prev0; - } else { - return this.cie.fromRGB(toRGB(colorvalue)); - } + public float[] toCIEXYZ(float[] colorvalue) { + if (colorvalue[0]==1) { + return this.prev1; + } else if (colorvalue[0]==0) { + return this.prev0; + } else { + return this.cie.fromRGB(toRGB(colorvalue)); + } } @Override - public float[] toRGB(float[] colorvalue) { + public float[] toRGB(float[] colorvalue) { return ((Color) this.paint.getPaint()).getRGBColorComponents(null); } @Override public int getNumComponents() { - return 1; + return 1; } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PDFColorSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PDFColorSpace.java index 37a078a96..e0ccb2d3f 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PDFColorSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PDFColorSpace.java @@ -171,15 +171,15 @@ public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) PDFObject[] ary = csobj.getArray(); name = ary[0].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("CalGray")) { - value = new PDFColorSpace(new CalGrayColor(ary[1])); - } else if (name.equals("CalRGB")) { + 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("CalGray")) { + value = new PDFColorSpace(new CalGrayColor(ary[1])); + } else if (name.equals("CalRGB")) { value = new PDFColorSpace(new CalRGBColor(ary[1])); } else if (name.equals("Lab")) { value = new PDFColorSpace(new LabColor(ary[1])); @@ -224,11 +224,11 @@ public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) return new PatternSpace(base); } else if(name.equals("DeviceRGB")) { - return getColorSpace(COLORSPACE_RGB); + return getColorSpace(COLORSPACE_RGB); } else if(name.equals("DeviceCMYK")) { - return getColorSpace(COLORSPACE_CMYK); - } else { - // removed access to ary[1] dur to index out of bounds exceptions + return getColorSpace(COLORSPACE_CMYK); + } else { + // removed access to ary[1] dur to index out of bounds exceptions throw new PDFParseException("Unknown color space: " + name); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PatternSpace.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PatternSpace.java index ff3b140ca..ca2a127a4 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PatternSpace.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/colorspace/PatternSpace.java @@ -36,7 +36,7 @@ public class PatternSpace extends PDFColorSpace { private PDFColorSpace base; public PatternSpace() { - super(null); + super(null); } /** @@ -59,7 +59,7 @@ public PDFColorSpace getBase() { * Get the number of components we want */ @Override public int getNumComponents() { - if (this.base == null) { + if (this.base == null) { return 0; } else { return this.base.getNumComponents(); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ASCIIHexDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ASCIIHexDecode.java index 362bcd7ba..79108e998 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ASCIIHexDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ASCIIHexDecode.java @@ -38,7 +38,7 @@ public class ASCIIHexDecode { * initialize the decoder with an array of bytes in ASCIIHex format */ private ASCIIHexDecode(ByteBuffer buf) { - this.buf = buf; + this.buf = buf; } /** @@ -73,7 +73,7 @@ private int readHexDigit() throws PDFParseException { } // end of stream reached - throw new PDFParseException("Short stream in ASCIIHex decode"); + throw new PDFParseException("Short stream in ASCIIHex decode"); } /** @@ -118,9 +118,9 @@ private ByteBuffer decode() throws PDFParseException { * @return the decoded bytes */ public static ByteBuffer decode(ByteBuffer buf, PDFObject params) - throws PDFParseException + throws PDFParseException { - ASCIIHexDecode me = new ASCIIHexDecode(buf); - return me.decode(); + ASCIIHexDecode me = new ASCIIHexDecode(buf); + return me.decode(); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecode.java index 5a3176b4f..2ba09a06f 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecode.java @@ -10,102 +10,102 @@ public class CCITTFaxDecode { - protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws IOException { - byte[] bytes = new byte[buf.remaining()]; - buf.get(bytes, 0, bytes.length); - return ByteBuffer.wrap(decode(dict, bytes)); - } - - - protected static byte[] decode(PDFObject dict, byte[] source) throws IOException { - int width = 1728; - PDFObject widthDef = dict.getDictRef("Width"); - if (widthDef == null) { - widthDef = dict.getDictRef("W"); - } - if (widthDef != null) { - width = widthDef.getIntValue(); - } - int height = 0; - PDFObject heightDef = dict.getDictRef("Height"); - if (heightDef == null) { - heightDef = dict.getDictRef("H"); - } - if (heightDef != null) { - height = heightDef.getIntValue(); - } - - // - int columns = getOptionFieldInt(dict, "Columns", width); - int rows = getOptionFieldInt(dict, "Rows", height); - int k = getOptionFieldInt(dict, "K", 0); - int size = rows * ((columns + 7) >> 3); - byte[] destination = new byte[size]; - - boolean align = getOptionFieldBoolean(dict, "EncodedByteAlign", false); - - CCITTFaxDecoder decoder = new CCITTFaxDecoder(1, columns, rows); - decoder.setAlign(align); - try { - if (k == 0) { - decoder.decodeT41D(destination, source, 0, rows); - } else if (k > 0) { - decoder.decodeT42D(destination, source, 0, rows); - } else if (k < 0) { - decoder.decodeT6(destination, source, 0, rows); - } - }catch (Exception e) { - PDFDebugger.debug("Error decoding CCITTFax image k: "+ k); - // some PDf producer don't correctly assign a k value for the deocde, - // as result we can try one more time using the T6. - //first, reset buffer - destination = new byte[size]; - try { - decoder.decodeT6(destination, source, 0, rows); - }catch (Exception e1) { - // do nothing - PDFDebugger.debug("Error decoding CCITTFax image"); - } - } - if (!getOptionFieldBoolean(dict, "BlackIs1", false)) { - for (int i = 0; i < destination.length; i++) { - // bitwise not - destination[i] = (byte) ~destination[i]; - } - } - - return destination; - } - - public static int getOptionFieldInt(PDFObject dict, String name, int defaultValue) throws IOException { + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes, 0, bytes.length); + return ByteBuffer.wrap(decode(dict, bytes)); + } + + + protected static byte[] decode(PDFObject dict, byte[] source) throws IOException { + int width = 1728; + PDFObject widthDef = dict.getDictRef("Width"); + if (widthDef == null) { + widthDef = dict.getDictRef("W"); + } + if (widthDef != null) { + width = widthDef.getIntValue(); + } + int height = 0; + PDFObject heightDef = dict.getDictRef("Height"); + if (heightDef == null) { + heightDef = dict.getDictRef("H"); + } + if (heightDef != null) { + height = heightDef.getIntValue(); + } + + // + int columns = getOptionFieldInt(dict, "Columns", width); + int rows = getOptionFieldInt(dict, "Rows", height); + int k = getOptionFieldInt(dict, "K", 0); + int size = rows * ((columns + 7) >> 3); + byte[] destination = new byte[size]; + + boolean align = getOptionFieldBoolean(dict, "EncodedByteAlign", false); + + CCITTFaxDecoder decoder = new CCITTFaxDecoder(1, columns, rows); + decoder.setAlign(align); + try { + if (k == 0) { + decoder.decodeT41D(destination, source, 0, rows); + } else if (k > 0) { + decoder.decodeT42D(destination, source, 0, rows); + } else if (k < 0) { + decoder.decodeT6(destination, source, 0, rows); + } + }catch (Exception e) { + PDFDebugger.debug("Error decoding CCITTFax image k: "+ k); + // some PDf producer don't correctly assign a k value for the deocde, + // as result we can try one more time using the T6. + //first, reset buffer + destination = new byte[size]; + try { + decoder.decodeT6(destination, source, 0, rows); + }catch (Exception e1) { + // do nothing + PDFDebugger.debug("Error decoding CCITTFax image"); + } + } + if (!getOptionFieldBoolean(dict, "BlackIs1", false)) { + for (int i = 0; i < destination.length; i++) { + // bitwise not + destination[i] = (byte) ~destination[i]; + } + } + + return destination; + } + + public static int getOptionFieldInt(PDFObject dict, String name, int defaultValue) throws IOException { PDFObject dictParams = getDecodeParams(dict); - if (dictParams == null) { - return defaultValue; - } - PDFObject value = dictParams.getDictRef(name); - if (value == null) { - return defaultValue; - } - return value.getIntValue(); - } + if (dictParams == null) { + return defaultValue; + } + PDFObject value = dictParams.getDictRef(name); + if (value == null) { + return defaultValue; + } + return value.getIntValue(); + } - public static boolean getOptionFieldBoolean(PDFObject dict, String name, boolean defaultValue) throws IOException { + public static boolean getOptionFieldBoolean(PDFObject dict, String name, boolean defaultValue) throws IOException { PDFObject dictParams = getDecodeParams(dict); - if (dictParams == null) { - return defaultValue; - } - PDFObject value = dictParams.getDictRef(name); - if (value == null) { - return defaultValue; - } - return value.getBooleanValue(); - } + if (dictParams == null) { + return defaultValue; + } + PDFObject value = dictParams.getDictRef(name); + if (value == null) { + return defaultValue; + } + return value.getBooleanValue(); + } private static PDFObject getDecodeParams(PDFObject dict) throws IOException { PDFObject decdParams = dict.getDictRef("DecodeParms"); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecoder.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecoder.java index 72059d0c8..21bf4def8 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecoder.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/CCITTFaxDecoder.java @@ -65,1517 +65,1517 @@ package org.openpdf.renderer.decode; public class CCITTFaxDecoder { - static int[] table1 = { 0x00, // 0 bits are left in first byte - SHOULD - // NOT HAPPEN - 0x01, // 1 bits are left in first byte - 0x03, // 2 bits are left in first byte - 0x07, // 3 bits are left in first byte - 0x0f, // 4 bits are left in first byte - 0x1f, // 5 bits are left in first byte - 0x3f, // 6 bits are left in first byte - 0x7f, // 7 bits are left in first byte - 0xff // 8 bits are left in first byte - }; - - static int[] table2 = { 0x00, // 0 - 0x80, // 1 - 0xc0, // 2 - 0xe0, // 3 - 0xf0, // 4 - 0xf8, // 5 - 0xfc, // 6 - 0xfe, // 7 - 0xff // 8 - }; - - // Table to be used when fillOrder = 2, for flipping bytes. - static byte[] flipTable = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, - 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, - 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, - 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, - 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, - 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, - 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, - 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, - 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, - 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, - -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, - -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, - -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, - -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, - -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, - -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, - -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, - -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, - -97, 95, -33, 63, -65, 127, -1, }; - - // The main 10 bit white runs lookup table - static short white[] = { - // 0 - 7 - 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, - // 8 - 15 - 944, 944, 944, 944, 976, 976, 976, 976, - // 16 - 23 - 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, - // 24 - 31 - 718, 718, 718, 718, 718, 718, 718, 718, - // 32 - 39 - 750, 750, 750, 750, 750, 750, 750, 750, - // 40 - 47 - 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, - // 48 - 55 - 428, 428, 428, 428, 428, 428, 428, 428, - // 56 - 63 - 428, 428, 428, 428, 428, 428, 428, 428, - // 64 - 71 - 654, 654, 654, 654, 654, 654, 654, 654, - // 72 - 79 - 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, - // 80 - 87 - 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, - // 88 - 95 - 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, - // 96 - 103 - 622, 622, 622, 622, 622, 622, 622, 622, - // 104 - 111 - 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, - // 112 - 119 - 44, 44, 44, 44, 44, 44, 44, 44, - // 120 - 127 - 44, 44, 44, 44, 44, 44, 44, 44, - // 128 - 135 - 396, 396, 396, 396, 396, 396, 396, 396, - // 136 - 143 - 396, 396, 396, 396, 396, 396, 396, 396, - // 144 - 151 - 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, - // 152 - 159 - 846, 846, 846, 846, 846, 846, 846, 846, - // 160 - 167 - 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, - // 168 - 175 - 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, - // 176 - 183 - 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, - // 184 - 191 - 686, 686, 686, 686, 686, 686, 686, 686, - // 192 - 199 - 910, 910, 910, 910, 910, 910, 910, 910, - // 200 - 207 - 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, - // 208 - 215 - 2032, 2032, 2032, 2032, 16, 16, 16, 16, - // 216 - 223 - 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, - // 224 - 231 - 330, 330, 330, 330, 330, 330, 330, 330, - // 232 - 239 - 330, 330, 330, 330, 330, 330, 330, 330, - // 240 - 247 - 330, 330, 330, 330, 330, 330, 330, 330, - // 248 - 255 - 330, 330, 330, 330, 330, 330, 330, 330, - // 256 - 263 - 362, 362, 362, 362, 362, 362, 362, 362, - // 264 - 271 - 362, 362, 362, 362, 362, 362, 362, 362, - // 272 - 279 - 362, 362, 362, 362, 362, 362, 362, 362, - // 280 - 287 - 362, 362, 362, 362, 362, 362, 362, 362, - // 288 - 295 - 878, 878, 878, 878, 878, 878, 878, 878, - // 296 - 303 - 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, - // 304 - 311 - -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, - // 312 - 319 - 590, 590, 590, 590, 590, 590, 590, 590, - // 320 - 327 - 782, 782, 782, 782, 782, 782, 782, 782, - // 328 - 335 - 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, - // 336 - 343 - 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, - // 344 - 351 - 814, 814, 814, 814, 814, 814, 814, 814, - // 352 - 359 - 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, - // 360 - 367 - 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, - // 368 - 375 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 376 - 383 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 384 - 391 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 392 - 399 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 400 - 407 - 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, - // 408 - 415 - 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, - // 416 - 423 - 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, - // 424 - 431 - 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, - // 432 - 439 - -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, - // 440 - 447 - 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, - // 448 - 455 - 72, 72, 72, 72, 72, 72, 72, 72, - // 456 - 463 - 72, 72, 72, 72, 72, 72, 72, 72, - // 464 - 471 - 72, 72, 72, 72, 72, 72, 72, 72, - // 472 - 479 - 72, 72, 72, 72, 72, 72, 72, 72, - // 480 - 487 - 72, 72, 72, 72, 72, 72, 72, 72, - // 488 - 495 - 72, 72, 72, 72, 72, 72, 72, 72, - // 496 - 503 - 72, 72, 72, 72, 72, 72, 72, 72, - // 504 - 511 - 72, 72, 72, 72, 72, 72, 72, 72, - // 512 - 519 - 104, 104, 104, 104, 104, 104, 104, 104, - // 520 - 527 - 104, 104, 104, 104, 104, 104, 104, 104, - // 528 - 535 - 104, 104, 104, 104, 104, 104, 104, 104, - // 536 - 543 - 104, 104, 104, 104, 104, 104, 104, 104, - // 544 - 551 - 104, 104, 104, 104, 104, 104, 104, 104, - // 552 - 559 - 104, 104, 104, 104, 104, 104, 104, 104, - // 560 - 567 - 104, 104, 104, 104, 104, 104, 104, 104, - // 568 - 575 - 104, 104, 104, 104, 104, 104, 104, 104, - // 576 - 583 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 584 - 591 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 592 - 599 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 600 - 607 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 608 - 615 - 266, 266, 266, 266, 266, 266, 266, 266, - // 616 - 623 - 266, 266, 266, 266, 266, 266, 266, 266, - // 624 - 631 - 266, 266, 266, 266, 266, 266, 266, 266, - // 632 - 639 - 266, 266, 266, 266, 266, 266, 266, 266, - // 640 - 647 - 298, 298, 298, 298, 298, 298, 298, 298, - // 648 - 655 - 298, 298, 298, 298, 298, 298, 298, 298, - // 656 - 663 - 298, 298, 298, 298, 298, 298, 298, 298, - // 664 - 671 - 298, 298, 298, 298, 298, 298, 298, 298, - // 672 - 679 - 524, 524, 524, 524, 524, 524, 524, 524, - // 680 - 687 - 524, 524, 524, 524, 524, 524, 524, 524, - // 688 - 695 - 556, 556, 556, 556, 556, 556, 556, 556, - // 696 - 703 - 556, 556, 556, 556, 556, 556, 556, 556, - // 704 - 711 - 136, 136, 136, 136, 136, 136, 136, 136, - // 712 - 719 - 136, 136, 136, 136, 136, 136, 136, 136, - // 720 - 727 - 136, 136, 136, 136, 136, 136, 136, 136, - // 728 - 735 - 136, 136, 136, 136, 136, 136, 136, 136, - // 736 - 743 - 136, 136, 136, 136, 136, 136, 136, 136, - // 744 - 751 - 136, 136, 136, 136, 136, 136, 136, 136, - // 752 - 759 - 136, 136, 136, 136, 136, 136, 136, 136, - // 760 - 767 - 136, 136, 136, 136, 136, 136, 136, 136, - // 768 - 775 - 168, 168, 168, 168, 168, 168, 168, 168, - // 776 - 783 - 168, 168, 168, 168, 168, 168, 168, 168, - // 784 - 791 - 168, 168, 168, 168, 168, 168, 168, 168, - // 792 - 799 - 168, 168, 168, 168, 168, 168, 168, 168, - // 800 - 807 - 168, 168, 168, 168, 168, 168, 168, 168, - // 808 - 815 - 168, 168, 168, 168, 168, 168, 168, 168, - // 816 - 823 - 168, 168, 168, 168, 168, 168, 168, 168, - // 824 - 831 - 168, 168, 168, 168, 168, 168, 168, 168, - // 832 - 839 - 460, 460, 460, 460, 460, 460, 460, 460, - // 840 - 847 - 460, 460, 460, 460, 460, 460, 460, 460, - // 848 - 855 - 492, 492, 492, 492, 492, 492, 492, 492, - // 856 - 863 - 492, 492, 492, 492, 492, 492, 492, 492, - // 864 - 871 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 872 - 879 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 880 - 887 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 888 - 895 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 896 - 903 - 200, 200, 200, 200, 200, 200, 200, 200, - // 904 - 911 - 200, 200, 200, 200, 200, 200, 200, 200, - // 912 - 919 - 200, 200, 200, 200, 200, 200, 200, 200, - // 920 - 927 - 200, 200, 200, 200, 200, 200, 200, 200, - // 928 - 935 - 200, 200, 200, 200, 200, 200, 200, 200, - // 936 - 943 - 200, 200, 200, 200, 200, 200, 200, 200, - // 944 - 951 - 200, 200, 200, 200, 200, 200, 200, 200, - // 952 - 959 - 200, 200, 200, 200, 200, 200, 200, 200, - // 960 - 967 - 232, 232, 232, 232, 232, 232, 232, 232, - // 968 - 975 - 232, 232, 232, 232, 232, 232, 232, 232, - // 976 - 983 - 232, 232, 232, 232, 232, 232, 232, 232, - // 984 - 991 - 232, 232, 232, 232, 232, 232, 232, 232, - // 992 - 999 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1000 - 1007 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1008 - 1015 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1016 - 1023 - 232, 232, 232, 232, 232, 232, 232, 232, }; - - // Additional make up codes for both White and Black runs - static short[] additionalMakeup = { 28679, 28679, 31752, (short) 32777, - (short) 33801, (short) 34825, (short) 35849, (short) 36873, - (short) 29703, (short) 29703, (short) 30727, (short) 30727, - (short) 37897, (short) 38921, (short) 39945, (short) 40969 }; - - // Initial black run look up table, uses the first 4 bits of a code - static short[] initBlack = { - // 0 - 7 - 3226, 6412, 200, 168, 38, 38, 134, 134, // 8 - 15 - 100, 100, 100, 100, 68, 68, 68, 68 }; - - // - static short[] twoBitBlack = { 292, 260, 226, 226 }; // 0 - 3 - - // Main black run table, using the last 9 bits of possible 13 bit code - static short black[] = { - // 0 - 7 - 62, 62, 30, 30, 0, 0, 0, 0, - // 8 - 15 - 0, 0, 0, 0, 0, 0, 0, 0, - // 16 - 23 - 0, 0, 0, 0, 0, 0, 0, 0, - // 24 - 31 - 0, 0, 0, 0, 0, 0, 0, 0, - // 32 - 39 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 40 - 47 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 48 - 55 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 56 - 63 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 64 - 71 - 588, 588, 588, 588, 588, 588, 588, 588, - // 72 - 79 - 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, - // 80 - 87 - 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, - // 88 - 95 - 1936, 1936, -16365, -14317, 782, 782, 782, 782, - // 96 - 103 - 814, 814, 814, 814, -12269, -10221, 10257, 10257, - // 104 - 111 - 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, - // 112 - 119 - 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, - // 120 - 127 - 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, - // 128 - 135 - 424, 424, 424, 424, 424, 424, 424, 424, - // 136 - 143 - 424, 424, 424, 424, 424, 424, 424, 424, - // 144 - 151 - 424, 424, 424, 424, 424, 424, 424, 424, - // 152 - 159 - 424, 424, 424, 424, 424, 424, 424, 424, - // 160 - 167 - 750, 750, 750, 750, 1616, 1616, 1648, 1648, - // 168 - 175 - 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, - // 176 - 183 - 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, - // 184 - 191 - 524, 524, 524, 524, 524, 524, 524, 524, - // 192 - 199 - 556, 556, 556, 556, 556, 556, 556, 556, - // 200 - 207 - 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, - // 208 - 215 - 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, - // 216 - 223 - 1296, 1296, 1328, 1328, 718, 718, 718, 718, - // 224 - 231 - 456, 456, 456, 456, 456, 456, 456, 456, - // 232 - 239 - 456, 456, 456, 456, 456, 456, 456, 456, - // 240 - 247 - 456, 456, 456, 456, 456, 456, 456, 456, - // 248 - 255 - 456, 456, 456, 456, 456, 456, 456, 456, - // 256 - 263 - 326, 326, 326, 326, 326, 326, 326, 326, - // 264 - 271 - 326, 326, 326, 326, 326, 326, 326, 326, - // 272 - 279 - 326, 326, 326, 326, 326, 326, 326, 326, - // 280 - 287 - 326, 326, 326, 326, 326, 326, 326, 326, - // 288 - 295 - 326, 326, 326, 326, 326, 326, 326, 326, - // 296 - 303 - 326, 326, 326, 326, 326, 326, 326, 326, - // 304 - 311 - 326, 326, 326, 326, 326, 326, 326, 326, - // 312 - 319 - 326, 326, 326, 326, 326, 326, 326, 326, - // 320 - 327 - 358, 358, 358, 358, 358, 358, 358, 358, - // 328 - 335 - 358, 358, 358, 358, 358, 358, 358, 358, - // 336 - 343 - 358, 358, 358, 358, 358, 358, 358, 358, - // 344 - 351 - 358, 358, 358, 358, 358, 358, 358, 358, - // 352 - 359 - 358, 358, 358, 358, 358, 358, 358, 358, - // 360 - 367 - 358, 358, 358, 358, 358, 358, 358, 358, - // 368 - 375 - 358, 358, 358, 358, 358, 358, 358, 358, - // 376 - 383 - 358, 358, 358, 358, 358, 358, 358, 358, - // 384 - 391 - 490, 490, 490, 490, 490, 490, 490, 490, - // 392 - 399 - 490, 490, 490, 490, 490, 490, 490, 490, - // 400 - 407 - 4113, 4113, 6161, 6161, 848, 848, 880, 880, - // 408 - 415 - 912, 912, 944, 944, 622, 622, 622, 622, - // 416 - 423 - 654, 654, 654, 654, 1104, 1104, 1136, 1136, - // 424 - 431 - 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, - // 432 - 439 - 686, 686, 686, 686, 1360, 1360, 1392, 1392, - // 440 - 447 - 12, 12, 12, 12, 12, 12, 12, 12, - // 448 - 455 - 390, 390, 390, 390, 390, 390, 390, 390, - // 456 - 463 - 390, 390, 390, 390, 390, 390, 390, 390, - // 464 - 471 - 390, 390, 390, 390, 390, 390, 390, 390, - // 472 - 479 - 390, 390, 390, 390, 390, 390, 390, 390, - // 480 - 487 - 390, 390, 390, 390, 390, 390, 390, 390, - // 488 - 495 - 390, 390, 390, 390, 390, 390, 390, 390, - // 496 - 503 - 390, 390, 390, 390, 390, 390, 390, 390, - // 504 - 511 - 390, 390, 390, 390, 390, 390, 390, 390, }; - - static byte[] twoDCodes = { - // 0 - 7 - 80, 88, 23, 71, 30, 30, 62, 62, // 8 - 15 - 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 23 - 11, 11, 11, 11, 11, 11, 11, 11, // 24 - 31 - 11, 11, 11, 11, 11, 11, 11, 11, // 32 - 39 - 35, 35, 35, 35, 35, 35, 35, 35, // 40 - 47 - 35, 35, 35, 35, 35, 35, 35, 35, // 48 - 55 - 51, 51, 51, 51, 51, 51, 51, 51, // 56 - 63 - 51, 51, 51, 51, 51, 51, 51, 51, // 64 - 71 - 41, 41, 41, 41, 41, 41, 41, 41, // 72 - 79 - 41, 41, 41, 41, 41, 41, 41, 41, // 80 - 87 - 41, 41, 41, 41, 41, 41, 41, 41, // 88 - 95 - 41, 41, 41, 41, 41, 41, 41, 41, // 96 - 103 - 41, 41, 41, 41, 41, 41, 41, 41, // 104 - 111 - 41, 41, 41, 41, 41, 41, 41, 41, // 112 - 119 - 41, 41, 41, 41, 41, 41, 41, 41, // 120 - 127 - 41, 41, 41, 41, 41, 41, 41, 41, }; - - private int bitPointer; - - private int bytePointer; - - private byte[] data; - - private int w; - - private boolean align = false; - - private int fillOrder; - - // Data structures needed to store changing elements for the previous - // and the current scanline - private int changingElemSize = 0; - - private int[] prevChangingElems; - - private int[] currChangingElems; - - // Element at which to start search in getNextChangingElement - private int lastChangingElement = 0; - - private boolean fillBits = false; - - /** - * @param fillOrder - * The fill order of the compressed data bytes. - * @param w - * @param h - */ - public CCITTFaxDecoder(int fillOrder, int w, int h) { - this.fillOrder = fillOrder; - // Some of the decode methods assume prevChangingElms - // and currChaningElems are at least of length 2. - if(w<2) { - w=2; - } - - this.w = w; - - this.bitPointer = 0; - this.bytePointer = 0; - this.prevChangingElems = new int[w]; - this.currChangingElems = new int[w]; - } - - private boolean align() { - if (this.align && this.bitPointer != 0) { - this.bytePointer++; - this.bitPointer = 0; - return true; - } - return false; - } - - protected boolean consumeEOL() { - // Get the next 12 bits. - int next12Bits = nextNBits(12); - if (next12Bits == 1) { - // EOL found & consumed - return true; - } - // no EOL - unread and return - updatePointer(12); - return false; - } - - // Returns run length - private int decodeBlackCodeWord() { - int current; - int entry; - int bits; - int isT; - int code = -1; - int runLength = 0; - boolean isWhite = false; - - while (!isWhite) { - current = nextLesserThan8Bits(4); - entry = initBlack[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) { - current = nextNBits(9); - entry = black[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - - updatePointer(4 - bits); - } else if (bits == 15) { - // EOL code - throw new RuntimeException( - "EOL code word encountered in Black run."); //$NON-NLS-1$ - } else { - runLength += code; - updatePointer(9 - bits); - if (isT == 0) { - isWhite = true; - } - } - } else if (code == 200) { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = twoBitBlack[current]; - code = (entry >>> 5) & 0x07ff; - runLength += code; - bits = (entry >>> 1) & 0x0f; - updatePointer(2 - bits); - isWhite = true; - } else { - // Is a Terminating code - runLength += code; - updatePointer(4 - bits); - isWhite = true; - } - } - - return runLength; - } - - protected void decodeNextScanline(byte[] buffer, int lineOffset, - int bitOffset) { - int bits = 0; - int code = 0; - int isT = 0; - int current; - int entry; - int twoBits; - boolean isWhite = true; - - // Initialize starting of the changing elements array - this.changingElemSize = 0; - - // While scanline not complete - while (bitOffset < this.w) { - while (isWhite) { - // White run - current = nextNBits(10); - entry = white[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - bitOffset += code; // Skip white run - - updatePointer(4 - bits); - } else if (bits == 0) { // ERROR - throw new RuntimeException("Invalid code encountered."); - } else if (bits == 15) { - // EOL recover - // move bits back... - updatePointer(10); - return; - } else { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - bitOffset += code; - - updatePointer(10 - bits); - if (isT == 0) { - isWhite = false; - this.currChangingElems[this.changingElemSize++] = bitOffset; - } - } - } - - // Check whether this run completed one width, if so - // advance to next byte boundary for compression = 2. - if (bitOffset == this.w) { - align(); - break; - } - - while (isWhite == false) { - // Black run - current = nextLesserThan8Bits(4); - entry = initBlack[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) { - current = nextNBits(9); - entry = black[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - } else if (bits == 15) { - // EOL recover - // unread bits ??? - updatePointer(9); - return; - } else { - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(9 - bits); - if (isT == 0) { - isWhite = true; - this.currChangingElems[this.changingElemSize++] = bitOffset; - } - } - } else if (code == 200) { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = twoBitBlack[current]; - code = (entry >>> 5) & 0x07ff; - bits = (entry >>> 1) & 0x0f; - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(2 - bits); - isWhite = true; - this.currChangingElems[this.changingElemSize++] = bitOffset; - } else { - // Is a Terminating code - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - isWhite = true; - this.currChangingElems[this.changingElemSize++] = bitOffset; - } - } - - // Check whether this run completed one width - if (bitOffset == this.w) { - align(); - break; - } - } - - this.currChangingElems[this.changingElemSize++] = bitOffset; - } - - // One-dimensional decoding methods - public void decodeT41D(byte[] buffer, byte[] compData, int startX, - int height) { - this.data = compData; - int scanlineStride = (this.w + 7) / 8; - this.bitPointer = 0; - this.bytePointer = 0; - - int lineOffset = 0; - for (int i = 0; i < height; i++) { - consumeEOL(); - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - } - } - - // Two-dimensional decoding methods - public void decodeT42D(byte[] buffer, byte[] compData, int startX, - int height) { - this.data = compData; - int scanlineStride = (this.w + 7) / 8; - this.bitPointer = 0; - this.bytePointer = 0; - - int a0; - int a1; - int b1; - int b2; - int[] b = new int[2]; - int entry; - int code; - int bits; - boolean isWhite; - int currIndex = 0; - int[] temp; - - // The data must start with an EOL code - if (readEOL(true) != 1) { - throw new RuntimeException("First scanline must be 1D encoded."); //$NON-NLS-1$ - } - - int lineOffset = 0; - int bitOffset; - - // Then the 1D encoded scanline data will occur, changing elements - // array gets set. - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - - for (int lines = 1; lines < height; lines++) { - // Every line must begin with an EOL followed by a bit which - // indicates whether the following scanline is 1D or 2D encoded. - if (readEOL(false) == 0) { - // 2D encoded scanline follows - - // Initialize previous scanlines changing elements, and - // initialize current scanline's changing elements array - temp = this.prevChangingElems; - this.prevChangingElems = this.currChangingElems; - this.currChangingElems = temp; - currIndex = 0; - - // a0 has to be set just before the start of this scanline. - a0 = -1; - isWhite = true; - bitOffset = startX; - - this.lastChangingElement = 0; - - while (bitOffset < this.w) { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - - // Run these through the 2DCodes table - entry = (twoDCodes[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) { - if (!isWhite) { - setToBlack(buffer, lineOffset, bitOffset, b2 - - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to consume the correct number of bits. - updatePointer(7 - bits); - } else if (code == 1) { - // Horizontal - updatePointer(7 - bits); - - // identify the next 2 codes. - int number; - if (isWhite) { - number = decodeWhiteCodeWord(); - bitOffset += number; - this.currChangingElems[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - this.currChangingElems[currIndex++] = bitOffset; - } else { - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - this.currChangingElems[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - this.currChangingElems[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } else if (code <= 8) { - // Vertical - a1 = b1 + (code - 5); - - this.currChangingElems[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) { - setToBlack(buffer, lineOffset, bitOffset, a1 - - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } else { - throw new RuntimeException( - "Invalid code encountered while decoding 2D group 3 compressed data."); //$NON-NLS-1$ - } - } - - // Add the changing element beyond the current scanline for the - // other color too - this.currChangingElems[currIndex++] = bitOffset; - this.changingElemSize = currIndex; - } else { - // 1D encoded scanline follows - decodeNextScanline(buffer, lineOffset, startX); - } - - lineOffset += scanlineStride; - } - } - - public synchronized void decodeT6(byte[] buffer, byte[] compData, - int startX, int height) { - this.data = compData; - int scanlineStride = (this.w + 7) / 8; - this.bitPointer = 0; - this.bytePointer = 0; - - int a0; - int a1; - int b1; - int b2; - int entry; - int code; - int bits; - boolean isWhite; - int currIndex; - int[] temp; - - // Return values from getNextChangingElement - int[] b = new int[2]; - - // uncompressedMode - have written some code for this, but this - // has not been tested due to lack of test images using this optional - - // Local cached reference - int[] cce = this.currChangingElems; - - // Assume invisible preceding row of all white pixels and insert - // both black and white changing elements beyond the end of this - // imaginary scanline. - this.changingElemSize = 0; - cce[this.changingElemSize++] = this.w; - cce[this.changingElemSize++] = this.w; - - int lineOffset = 0; - int bitOffset; - - for (int lines = 0; lines < height; lines++) { - // a0 has to be set just before the start of the scanline. - a0 = -1; - isWhite = true; - - // Assign the changing elements of the previous scanline to - // prevChangingElems and start putting this new scanline's - // changing elements into the currChangingElems. - temp = this.prevChangingElems; - this.prevChangingElems = this.currChangingElems; - cce = this.currChangingElems = temp; - currIndex = 0; - - // Start decoding the scanline at startX in the raster - bitOffset = startX; - - // Reset search start position for getNextChangingElement - this.lastChangingElement = 0; - - // Till one whole scanline is decoded - while (bitOffset < this.w) { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - // Run these through the 2DCodes table - entry = (twoDCodes[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) { // Pass - // We always assume WhiteIsZero format for fax. - if (!isWhite) { - if (b2 > this.w) { - b2 = this.w; - } - setToBlack(buffer, lineOffset, bitOffset, b2 - - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - } else if (code == 1) { // Horizontal - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - - // identify the next 2 alternating color codes. - int number; - if (isWhite) { - // Following are white and black runs - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - if (number > this.w - bitOffset) { - number = this.w - bitOffset; - } - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - } else { - // First a black run and then a white run follows - number = decodeBlackCodeWord(); - if (number > this.w - bitOffset) { - number = this.w - bitOffset; - } - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } else if (code <= 8) { // Vertical - a1 = b1 + (code - 5); - cce[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) { - if (a1 > this.w) { - a1 = this.w; - } - setToBlack(buffer, lineOffset, bitOffset, a1 - - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } else if (code == 11) { - if (nextLesserThan8Bits(3) != 7) { - throw new RuntimeException( - "Invalid code encountered while decoding 2D group 4 compressed data."); //$NON-NLS-1$ - } - - int zeros = 0; - boolean exit = false; - - while (!exit) { - while (nextLesserThan8Bits(1) != 1) { - zeros++; - } - - if (zeros > 5) { - // Exit code - - // Zeros before exit code - zeros = zeros - 6; - - if (!isWhite && (zeros > 0)) { - cce[currIndex++] = bitOffset; - } - - // Zeros before the exit code - bitOffset += zeros; - if (zeros > 0) { - // Some zeros have been written - isWhite = true; - } - - // Read in the bit which specifies the color of - // the following run - if (nextLesserThan8Bits(1) == 0) { - if (!isWhite) { - cce[currIndex++] = bitOffset; - } - isWhite = true; - } else { - if (isWhite) { - cce[currIndex++] = bitOffset; - } - isWhite = false; - } - - exit = true; - } - - if (zeros == 5) { - if (!isWhite) { - cce[currIndex++] = bitOffset; - } - bitOffset += zeros; - - // Last thing written was white - isWhite = true; - } else { - bitOffset += zeros; - - cce[currIndex++] = bitOffset; - setToBlack(buffer, lineOffset, bitOffset, 1); - ++bitOffset; - - // Last thing written was black - isWhite = false; - } - } - } else { - // break line - seems to be a common failure - // unread - updatePointer(7 - bits); - // and mark lines as complete - bitOffset = this.w; - // throw new RuntimeException( - // "Invalid code encountered while decoding 2D group 4 - // compressed data."); //$NON-NLS-1$ - } - } - - align(); - - // Add the changing element beyond the current scanline for the - // other color too - // make sure that the index does not exceed the bounds of the array - if (currIndex < this.w) { - cce[currIndex++] = bitOffset; - } - - // Number of changing elements in this scanline. - this.changingElemSize = currIndex; - - lineOffset += scanlineStride; - } - } - - // Returns run length - private int decodeWhiteCodeWord() { - int current; - int entry; - int bits; - int isT; - int twoBits; - int code = -1; - int runLength = 0; - boolean isWhite = true; - - while (isWhite) { - current = nextNBits(10); - entry = white[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - updatePointer(4 - bits); - } else if (bits == 0) { // ERROR - throw new RuntimeException("Invalid code encountered."); //$NON-NLS-1$ - } else if (bits == 15) { // EOL - throw new RuntimeException( - "EOL code word encountered in White run."); //$NON-NLS-1$ - } else { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - runLength += code; - updatePointer(10 - bits); - if (isT == 0) { - isWhite = false; - } - } - } - - return runLength; - } - - private void getNextChangingElement(int a0, boolean isWhite, int[] ret) { - // Local copies of instance variables - int[] pce = this.prevChangingElems; - int ces = this.changingElemSize; - - // If the previous match was at an odd element, we still - // have to search the preceeding element. - // int start = lastChangingElement & ~0x1; - int start = (this.lastChangingElement > 0) ? (this.lastChangingElement - 1) : 0; - if (isWhite) { - start &= ~0x1; // Search even numbered elements - } else { - start |= 0x1; // Search odd numbered elements - } - - int i = start; - for (; i < ces; i += 2) { - int temp = pce[i]; - if (temp > a0) { - this.lastChangingElement = i; - ret[0] = temp; - break; - } - } - - if ((i + 1) < ces) { - ret[1] = pce[i + 1]; - } - } - - public boolean isAlign() { - return this.align; - } - - public boolean isFillBits() { - return this.fillBits; - } - - private int nextLesserThan8Bits(int bitsToGet) { - byte b; - byte next; - int l = this.data.length - 1; - int bp = this.bytePointer; - - if (this.fillOrder == 1) { - b = this.data[bp]; - if (bp == l) { - next = 0x00; - } else { - next = this.data[bp + 1]; - } - } else if (this.fillOrder == 2) { - b = flipTable[this.data[bp] & 0xff]; - if (bp == l) { - next = 0x00; - } else { - next = flipTable[this.data[bp + 1] & 0xff]; - } - } else { - throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ - } - - int bitsLeft = 8 - this.bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - - int shift = bitsLeft - bitsToGet; - int i1; - int i2; - if (shift >= 0) { - i1 = (b & table1[bitsLeft]) >>> shift; - this.bitPointer += bitsToGet; - if (this.bitPointer == 8) { - this.bitPointer = 0; - this.bytePointer++; - } - } else { - i1 = (b & table1[bitsLeft]) << (-shift); - i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - i1 |= i2; - this.bytePointer++; - this.bitPointer = bitsFromNextByte; - } - - return i1; - } - - private int nextNBits(int bitsToGet) { - byte b; - byte next; - byte next2next; - int l = this.data.length - 1; - int bp = this.bytePointer; - - if (this.fillOrder == 1) { - b = this.data[bp]; - - if (bp == l) { - next = 0x00; - next2next = 0x00; - } else if ((bp + 1) == l) { - next = this.data[bp + 1]; - next2next = 0x00; - } else { - next = this.data[bp + 1]; - next2next = this.data[bp + 2]; - } - } else if (this.fillOrder == 2) { - b = flipTable[this.data[bp] & 0xff]; - - if (bp == l) { - next = 0x00; - next2next = 0x00; - } else if ((bp + 1) == l) { - next = flipTable[this.data[bp + 1] & 0xff]; - next2next = 0x00; - } else { - next = flipTable[this.data[bp + 1] & 0xff]; - next2next = flipTable[this.data[bp + 2] & 0xff]; - } - } else { - throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ - } - - int bitsLeft = 8 - this.bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - int bitsFromNext2NextByte = 0; - if (bitsFromNextByte > 8) { - bitsFromNext2NextByte = bitsFromNextByte - 8; - bitsFromNextByte = 8; - } - - this.bytePointer++; - - int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); - int i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - int i3 = 0; - if (bitsFromNext2NextByte != 0) { - i2 <<= bitsFromNext2NextByte; - i3 = (next2next & table2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); - i2 |= i3; - this.bytePointer++; - this.bitPointer = bitsFromNext2NextByte; - } else { - if (bitsFromNextByte == 8) { - this.bitPointer = 0; - this.bytePointer++; - } else { - this.bitPointer = bitsFromNextByte; - } - } - - int i = i1 | i2; - return i; - } - - private int readEOL(boolean isFirstEOL) { - // Seek to the next EOL. - if (!seekEOL()) { - throw new RuntimeException("EOL not found"); - } - - if (!this.fillBits) { - int next12Bits = nextNBits(12); - if (isFirstEOL && (next12Bits == 0)) { - // Might have the case of EOL padding being used even - // though it was not flagged. - // This was observed to be the case in TIFFs produced - // by a well known vendor who shall remain nameless. - if (nextNBits(4) == 1) { - // EOL must be padded: reset the fillBits flag. - this.fillBits = true; - return 1; - } - } - if (next12Bits != 1) { - throw new RuntimeException( - "Scanline must begin with EOL code word."); //$NON-NLS-1$ - } - } else { - // First EOL code word xxxx 0000 0000 0001 will occur - // As many fill bits will be present as required to make - // the EOL code of 12 bits end on a byte boundary. - int bitsLeft = 8 - this.bitPointer; - - if (nextNBits(bitsLeft) != 0) { - throw new RuntimeException( - "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ - } - - // If the number of bitsLeft is less than 8, then to have a 12 - // bit EOL sequence, two more bytes are certainly going to be - // required. The first of them has to be all zeros, so ensure - // that. - if (bitsLeft < 4) { - if (nextNBits(8) != 0) { - throw new RuntimeException( - "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ - } - } - - // - // Some encoders under Group 3 Fax compression 1D writes TIFF - // files without the fill bits, but say otherwise. - // Need to check for this here. - // - int next8 = nextNBits(8); - - if (isFirstEOL && (next8 & 0xf0) == 0x10) { - // - // Fill bits are not actually used despite what the flag - // says. So switch fillBits off and then rewind so that - // only 12 bits have effectively been read. - // - this.fillBits = false; - updatePointer(4); - } else { - // - // This is the normal case. - // There might be a random number of fill bytes with 0s, so - // loop till the EOL of 0000 0001 is found, as long as all - // the bytes preceding it are 0's. - // - while (next8 != 1) { - // If not all zeros - if (next8 != 0) { - throw new RuntimeException("0 bits expected before EOL"); - } - next8 = nextNBits(8); - } - } - } - // The next one bit signifies 1D/2D encoding of next line. - return nextLesserThan8Bits(1); - } - - // Seeks to the next EOL in the compressed bitstream. - // Returns 'true' if and only if an EOL is found; if 'false' - // is returned it may be inferred that the EOF was reached first. - private boolean seekEOL() { - // Set maximum and current bit index into the compressed data. - int bitIndexMax = this.data.length * 8 - 1; - int bitIndex = this.bytePointer * 8 + this.bitPointer; - - // Loop while at least 12 bits are available. - while (bitIndex <= bitIndexMax - 12) { - // Get the next 12 bits. - int next12Bits = nextNBits(12); - bitIndex += 12; - - // Loop while the 12 bits are not unity, i.e., while the EOL - // has not been reached, and there is at least one bit left. - while (next12Bits != 1 && bitIndex < bitIndexMax) { - next12Bits = ((next12Bits & 0x000007ff) << 1) - | (nextLesserThan8Bits(1) & 0x00000001); - bitIndex++; - } - - // If EOL reached, rewind the pointers and return 'true'. - if (next12Bits == 1) { - updatePointer(12); - return true; - } - } - - // EOL not found: return 'false'. - return false; - } - - public void setAlign(boolean align) { - this.align = align; - } - - public void setFillBits(boolean fillBits) { - this.fillBits = fillBits; - } - - private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, - int numBits) { - int bitNum = (8 * lineOffset) + bitOffset; - int lastBit = bitNum + numBits; - - int byteNum = bitNum >> 3; - - // Handle bits in first byte - int shift = bitNum & 0x7; - if (shift > 0) { - int maskVal = 1 << (7 - shift); - byte val = buffer[byteNum]; - while ((maskVal > 0) && (bitNum < lastBit)) { - val |= maskVal; - maskVal >>= 1; - ++bitNum; - } - buffer[byteNum] = val; - } - - // Fill in 8 bits at a time - byteNum = bitNum >> 3; - while (bitNum < (lastBit - 7)) { - buffer[byteNum++] = (byte) 255; - bitNum += 8; - } - - // Fill in remaining bits - while (bitNum < lastBit) { - byteNum = bitNum >> 3; - buffer[byteNum] |= (1 << (7 - (bitNum & 0x7))); - ++bitNum; - } - } - - // Move pointer backwards by given amount of bits - private void updatePointer(int bitsToMoveBack) { - if (bitsToMoveBack > 8) { - this.bytePointer -= bitsToMoveBack / 8; - bitsToMoveBack %= 8; - } - - int i = this.bitPointer - bitsToMoveBack; - - if (i < 0) { - this.bytePointer--; - this.bitPointer = 8 + i; - } else { - this.bitPointer = i; - } - } + static int[] table1 = { 0x00, // 0 bits are left in first byte - SHOULD + // NOT HAPPEN + 0x01, // 1 bits are left in first byte + 0x03, // 2 bits are left in first byte + 0x07, // 3 bits are left in first byte + 0x0f, // 4 bits are left in first byte + 0x1f, // 5 bits are left in first byte + 0x3f, // 6 bits are left in first byte + 0x7f, // 7 bits are left in first byte + 0xff // 8 bits are left in first byte + }; + + static int[] table2 = { 0x00, // 0 + 0x80, // 1 + 0xc0, // 2 + 0xe0, // 3 + 0xf0, // 4 + 0xf8, // 5 + 0xfc, // 6 + 0xfe, // 7 + 0xff // 8 + }; + + // Table to be used when fillOrder = 2, for flipping bytes. + static byte[] flipTable = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, + 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, + 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, + 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, + 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, + 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, + 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, + 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, + 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, + 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, + -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, + -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, + -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, + -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, + -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, + -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, + -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, + -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, + -97, 95, -33, 63, -65, 127, -1, }; + + // The main 10 bit white runs lookup table + static short white[] = { + // 0 - 7 + 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, + // 8 - 15 + 944, 944, 944, 944, 976, 976, 976, 976, + // 16 - 23 + 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, + // 24 - 31 + 718, 718, 718, 718, 718, 718, 718, 718, + // 32 - 39 + 750, 750, 750, 750, 750, 750, 750, 750, + // 40 - 47 + 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, + // 48 - 55 + 428, 428, 428, 428, 428, 428, 428, 428, + // 56 - 63 + 428, 428, 428, 428, 428, 428, 428, 428, + // 64 - 71 + 654, 654, 654, 654, 654, 654, 654, 654, + // 72 - 79 + 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, + // 80 - 87 + 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, + // 88 - 95 + 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, + // 96 - 103 + 622, 622, 622, 622, 622, 622, 622, 622, + // 104 - 111 + 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, + // 112 - 119 + 44, 44, 44, 44, 44, 44, 44, 44, + // 120 - 127 + 44, 44, 44, 44, 44, 44, 44, 44, + // 128 - 135 + 396, 396, 396, 396, 396, 396, 396, 396, + // 136 - 143 + 396, 396, 396, 396, 396, 396, 396, 396, + // 144 - 151 + 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, + // 152 - 159 + 846, 846, 846, 846, 846, 846, 846, 846, + // 160 - 167 + 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, + // 168 - 175 + 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, + // 176 - 183 + 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, + // 184 - 191 + 686, 686, 686, 686, 686, 686, 686, 686, + // 192 - 199 + 910, 910, 910, 910, 910, 910, 910, 910, + // 200 - 207 + 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, + // 208 - 215 + 2032, 2032, 2032, 2032, 16, 16, 16, 16, + // 216 - 223 + 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, + // 224 - 231 + 330, 330, 330, 330, 330, 330, 330, 330, + // 232 - 239 + 330, 330, 330, 330, 330, 330, 330, 330, + // 240 - 247 + 330, 330, 330, 330, 330, 330, 330, 330, + // 248 - 255 + 330, 330, 330, 330, 330, 330, 330, 330, + // 256 - 263 + 362, 362, 362, 362, 362, 362, 362, 362, + // 264 - 271 + 362, 362, 362, 362, 362, 362, 362, 362, + // 272 - 279 + 362, 362, 362, 362, 362, 362, 362, 362, + // 280 - 287 + 362, 362, 362, 362, 362, 362, 362, 362, + // 288 - 295 + 878, 878, 878, 878, 878, 878, 878, 878, + // 296 - 303 + 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, + // 304 - 311 + -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, + // 312 - 319 + 590, 590, 590, 590, 590, 590, 590, 590, + // 320 - 327 + 782, 782, 782, 782, 782, 782, 782, 782, + // 328 - 335 + 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, + // 336 - 343 + 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, + // 344 - 351 + 814, 814, 814, 814, 814, 814, 814, 814, + // 352 - 359 + 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, + // 360 - 367 + 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, + // 368 - 375 + 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, + // 376 - 383 + 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, + // 384 - 391 + -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, + // 392 - 399 + -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, + // 400 - 407 + 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, + // 408 - 415 + 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, + // 416 - 423 + 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, + // 424 - 431 + 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, + // 432 - 439 + -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, + // 440 - 447 + 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, + // 448 - 455 + 72, 72, 72, 72, 72, 72, 72, 72, + // 456 - 463 + 72, 72, 72, 72, 72, 72, 72, 72, + // 464 - 471 + 72, 72, 72, 72, 72, 72, 72, 72, + // 472 - 479 + 72, 72, 72, 72, 72, 72, 72, 72, + // 480 - 487 + 72, 72, 72, 72, 72, 72, 72, 72, + // 488 - 495 + 72, 72, 72, 72, 72, 72, 72, 72, + // 496 - 503 + 72, 72, 72, 72, 72, 72, 72, 72, + // 504 - 511 + 72, 72, 72, 72, 72, 72, 72, 72, + // 512 - 519 + 104, 104, 104, 104, 104, 104, 104, 104, + // 520 - 527 + 104, 104, 104, 104, 104, 104, 104, 104, + // 528 - 535 + 104, 104, 104, 104, 104, 104, 104, 104, + // 536 - 543 + 104, 104, 104, 104, 104, 104, 104, 104, + // 544 - 551 + 104, 104, 104, 104, 104, 104, 104, 104, + // 552 - 559 + 104, 104, 104, 104, 104, 104, 104, 104, + // 560 - 567 + 104, 104, 104, 104, 104, 104, 104, 104, + // 568 - 575 + 104, 104, 104, 104, 104, 104, 104, 104, + // 576 - 583 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 584 - 591 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 592 - 599 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 600 - 607 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 608 - 615 + 266, 266, 266, 266, 266, 266, 266, 266, + // 616 - 623 + 266, 266, 266, 266, 266, 266, 266, 266, + // 624 - 631 + 266, 266, 266, 266, 266, 266, 266, 266, + // 632 - 639 + 266, 266, 266, 266, 266, 266, 266, 266, + // 640 - 647 + 298, 298, 298, 298, 298, 298, 298, 298, + // 648 - 655 + 298, 298, 298, 298, 298, 298, 298, 298, + // 656 - 663 + 298, 298, 298, 298, 298, 298, 298, 298, + // 664 - 671 + 298, 298, 298, 298, 298, 298, 298, 298, + // 672 - 679 + 524, 524, 524, 524, 524, 524, 524, 524, + // 680 - 687 + 524, 524, 524, 524, 524, 524, 524, 524, + // 688 - 695 + 556, 556, 556, 556, 556, 556, 556, 556, + // 696 - 703 + 556, 556, 556, 556, 556, 556, 556, 556, + // 704 - 711 + 136, 136, 136, 136, 136, 136, 136, 136, + // 712 - 719 + 136, 136, 136, 136, 136, 136, 136, 136, + // 720 - 727 + 136, 136, 136, 136, 136, 136, 136, 136, + // 728 - 735 + 136, 136, 136, 136, 136, 136, 136, 136, + // 736 - 743 + 136, 136, 136, 136, 136, 136, 136, 136, + // 744 - 751 + 136, 136, 136, 136, 136, 136, 136, 136, + // 752 - 759 + 136, 136, 136, 136, 136, 136, 136, 136, + // 760 - 767 + 136, 136, 136, 136, 136, 136, 136, 136, + // 768 - 775 + 168, 168, 168, 168, 168, 168, 168, 168, + // 776 - 783 + 168, 168, 168, 168, 168, 168, 168, 168, + // 784 - 791 + 168, 168, 168, 168, 168, 168, 168, 168, + // 792 - 799 + 168, 168, 168, 168, 168, 168, 168, 168, + // 800 - 807 + 168, 168, 168, 168, 168, 168, 168, 168, + // 808 - 815 + 168, 168, 168, 168, 168, 168, 168, 168, + // 816 - 823 + 168, 168, 168, 168, 168, 168, 168, 168, + // 824 - 831 + 168, 168, 168, 168, 168, 168, 168, 168, + // 832 - 839 + 460, 460, 460, 460, 460, 460, 460, 460, + // 840 - 847 + 460, 460, 460, 460, 460, 460, 460, 460, + // 848 - 855 + 492, 492, 492, 492, 492, 492, 492, 492, + // 856 - 863 + 492, 492, 492, 492, 492, 492, 492, 492, + // 864 - 871 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 872 - 879 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 880 - 887 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 888 - 895 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 896 - 903 + 200, 200, 200, 200, 200, 200, 200, 200, + // 904 - 911 + 200, 200, 200, 200, 200, 200, 200, 200, + // 912 - 919 + 200, 200, 200, 200, 200, 200, 200, 200, + // 920 - 927 + 200, 200, 200, 200, 200, 200, 200, 200, + // 928 - 935 + 200, 200, 200, 200, 200, 200, 200, 200, + // 936 - 943 + 200, 200, 200, 200, 200, 200, 200, 200, + // 944 - 951 + 200, 200, 200, 200, 200, 200, 200, 200, + // 952 - 959 + 200, 200, 200, 200, 200, 200, 200, 200, + // 960 - 967 + 232, 232, 232, 232, 232, 232, 232, 232, + // 968 - 975 + 232, 232, 232, 232, 232, 232, 232, 232, + // 976 - 983 + 232, 232, 232, 232, 232, 232, 232, 232, + // 984 - 991 + 232, 232, 232, 232, 232, 232, 232, 232, + // 992 - 999 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1000 - 1007 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1008 - 1015 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1016 - 1023 + 232, 232, 232, 232, 232, 232, 232, 232, }; + + // Additional make up codes for both White and Black runs + static short[] additionalMakeup = { 28679, 28679, 31752, (short) 32777, + (short) 33801, (short) 34825, (short) 35849, (short) 36873, + (short) 29703, (short) 29703, (short) 30727, (short) 30727, + (short) 37897, (short) 38921, (short) 39945, (short) 40969 }; + + // Initial black run look up table, uses the first 4 bits of a code + static short[] initBlack = { + // 0 - 7 + 3226, 6412, 200, 168, 38, 38, 134, 134, // 8 - 15 + 100, 100, 100, 100, 68, 68, 68, 68 }; + + // + static short[] twoBitBlack = { 292, 260, 226, 226 }; // 0 - 3 + + // Main black run table, using the last 9 bits of possible 13 bit code + static short black[] = { + // 0 - 7 + 62, 62, 30, 30, 0, 0, 0, 0, + // 8 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, + // 16 - 23 + 0, 0, 0, 0, 0, 0, 0, 0, + // 24 - 31 + 0, 0, 0, 0, 0, 0, 0, 0, + // 32 - 39 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 40 - 47 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 48 - 55 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 56 - 63 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 64 - 71 + 588, 588, 588, 588, 588, 588, 588, 588, + // 72 - 79 + 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, + // 80 - 87 + 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, + // 88 - 95 + 1936, 1936, -16365, -14317, 782, 782, 782, 782, + // 96 - 103 + 814, 814, 814, 814, -12269, -10221, 10257, 10257, + // 104 - 111 + 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, + // 112 - 119 + 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, + // 120 - 127 + 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, + // 128 - 135 + 424, 424, 424, 424, 424, 424, 424, 424, + // 136 - 143 + 424, 424, 424, 424, 424, 424, 424, 424, + // 144 - 151 + 424, 424, 424, 424, 424, 424, 424, 424, + // 152 - 159 + 424, 424, 424, 424, 424, 424, 424, 424, + // 160 - 167 + 750, 750, 750, 750, 1616, 1616, 1648, 1648, + // 168 - 175 + 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, + // 176 - 183 + 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, + // 184 - 191 + 524, 524, 524, 524, 524, 524, 524, 524, + // 192 - 199 + 556, 556, 556, 556, 556, 556, 556, 556, + // 200 - 207 + 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, + // 208 - 215 + 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, + // 216 - 223 + 1296, 1296, 1328, 1328, 718, 718, 718, 718, + // 224 - 231 + 456, 456, 456, 456, 456, 456, 456, 456, + // 232 - 239 + 456, 456, 456, 456, 456, 456, 456, 456, + // 240 - 247 + 456, 456, 456, 456, 456, 456, 456, 456, + // 248 - 255 + 456, 456, 456, 456, 456, 456, 456, 456, + // 256 - 263 + 326, 326, 326, 326, 326, 326, 326, 326, + // 264 - 271 + 326, 326, 326, 326, 326, 326, 326, 326, + // 272 - 279 + 326, 326, 326, 326, 326, 326, 326, 326, + // 280 - 287 + 326, 326, 326, 326, 326, 326, 326, 326, + // 288 - 295 + 326, 326, 326, 326, 326, 326, 326, 326, + // 296 - 303 + 326, 326, 326, 326, 326, 326, 326, 326, + // 304 - 311 + 326, 326, 326, 326, 326, 326, 326, 326, + // 312 - 319 + 326, 326, 326, 326, 326, 326, 326, 326, + // 320 - 327 + 358, 358, 358, 358, 358, 358, 358, 358, + // 328 - 335 + 358, 358, 358, 358, 358, 358, 358, 358, + // 336 - 343 + 358, 358, 358, 358, 358, 358, 358, 358, + // 344 - 351 + 358, 358, 358, 358, 358, 358, 358, 358, + // 352 - 359 + 358, 358, 358, 358, 358, 358, 358, 358, + // 360 - 367 + 358, 358, 358, 358, 358, 358, 358, 358, + // 368 - 375 + 358, 358, 358, 358, 358, 358, 358, 358, + // 376 - 383 + 358, 358, 358, 358, 358, 358, 358, 358, + // 384 - 391 + 490, 490, 490, 490, 490, 490, 490, 490, + // 392 - 399 + 490, 490, 490, 490, 490, 490, 490, 490, + // 400 - 407 + 4113, 4113, 6161, 6161, 848, 848, 880, 880, + // 408 - 415 + 912, 912, 944, 944, 622, 622, 622, 622, + // 416 - 423 + 654, 654, 654, 654, 1104, 1104, 1136, 1136, + // 424 - 431 + 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, + // 432 - 439 + 686, 686, 686, 686, 1360, 1360, 1392, 1392, + // 440 - 447 + 12, 12, 12, 12, 12, 12, 12, 12, + // 448 - 455 + 390, 390, 390, 390, 390, 390, 390, 390, + // 456 - 463 + 390, 390, 390, 390, 390, 390, 390, 390, + // 464 - 471 + 390, 390, 390, 390, 390, 390, 390, 390, + // 472 - 479 + 390, 390, 390, 390, 390, 390, 390, 390, + // 480 - 487 + 390, 390, 390, 390, 390, 390, 390, 390, + // 488 - 495 + 390, 390, 390, 390, 390, 390, 390, 390, + // 496 - 503 + 390, 390, 390, 390, 390, 390, 390, 390, + // 504 - 511 + 390, 390, 390, 390, 390, 390, 390, 390, }; + + static byte[] twoDCodes = { + // 0 - 7 + 80, 88, 23, 71, 30, 30, 62, 62, // 8 - 15 + 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 23 + 11, 11, 11, 11, 11, 11, 11, 11, // 24 - 31 + 11, 11, 11, 11, 11, 11, 11, 11, // 32 - 39 + 35, 35, 35, 35, 35, 35, 35, 35, // 40 - 47 + 35, 35, 35, 35, 35, 35, 35, 35, // 48 - 55 + 51, 51, 51, 51, 51, 51, 51, 51, // 56 - 63 + 51, 51, 51, 51, 51, 51, 51, 51, // 64 - 71 + 41, 41, 41, 41, 41, 41, 41, 41, // 72 - 79 + 41, 41, 41, 41, 41, 41, 41, 41, // 80 - 87 + 41, 41, 41, 41, 41, 41, 41, 41, // 88 - 95 + 41, 41, 41, 41, 41, 41, 41, 41, // 96 - 103 + 41, 41, 41, 41, 41, 41, 41, 41, // 104 - 111 + 41, 41, 41, 41, 41, 41, 41, 41, // 112 - 119 + 41, 41, 41, 41, 41, 41, 41, 41, // 120 - 127 + 41, 41, 41, 41, 41, 41, 41, 41, }; + + private int bitPointer; + + private int bytePointer; + + private byte[] data; + + private int w; + + private boolean align = false; + + private int fillOrder; + + // Data structures needed to store changing elements for the previous + // and the current scanline + private int changingElemSize = 0; + + private int[] prevChangingElems; + + private int[] currChangingElems; + + // Element at which to start search in getNextChangingElement + private int lastChangingElement = 0; + + private boolean fillBits = false; + + /** + * @param fillOrder + * The fill order of the compressed data bytes. + * @param w + * @param h + */ + public CCITTFaxDecoder(int fillOrder, int w, int h) { + this.fillOrder = fillOrder; + // Some of the decode methods assume prevChangingElms + // and currChaningElems are at least of length 2. + if(w<2) { + w=2; + } + + this.w = w; + + this.bitPointer = 0; + this.bytePointer = 0; + this.prevChangingElems = new int[w]; + this.currChangingElems = new int[w]; + } + + private boolean align() { + if (this.align && this.bitPointer != 0) { + this.bytePointer++; + this.bitPointer = 0; + return true; + } + return false; + } + + protected boolean consumeEOL() { + // Get the next 12 bits. + int next12Bits = nextNBits(12); + if (next12Bits == 1) { + // EOL found & consumed + return true; + } + // no EOL - unread and return + updatePointer(12); + return false; + } + + // Returns run length + private int decodeBlackCodeWord() { + int current; + int entry; + int bits; + int isT; + int code = -1; + int runLength = 0; + boolean isWhite = false; + + while (!isWhite) { + current = nextLesserThan8Bits(4); + entry = initBlack[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x000f; + code = (entry >>> 5) & 0x07ff; + + if (code == 100) { + current = nextNBits(9); + entry = black[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x000f; + code = (entry >>> 5) & 0x07ff; + + if (bits == 12) { + // Additional makeup codes + updatePointer(5); + current = nextLesserThan8Bits(4); + entry = additionalMakeup[current]; + bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >>> 4) & 0x0fff; // 12 bits + runLength += code; + + updatePointer(4 - bits); + } else if (bits == 15) { + // EOL code + throw new RuntimeException( + "EOL code word encountered in Black run."); //$NON-NLS-1$ + } else { + runLength += code; + updatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + } + } + } else if (code == 200) { + // Is a Terminating code + current = nextLesserThan8Bits(2); + entry = twoBitBlack[current]; + code = (entry >>> 5) & 0x07ff; + runLength += code; + bits = (entry >>> 1) & 0x0f; + updatePointer(2 - bits); + isWhite = true; + } else { + // Is a Terminating code + runLength += code; + updatePointer(4 - bits); + isWhite = true; + } + } + + return runLength; + } + + protected void decodeNextScanline(byte[] buffer, int lineOffset, + int bitOffset) { + int bits = 0; + int code = 0; + int isT = 0; + int current; + int entry; + int twoBits; + boolean isWhite = true; + + // Initialize starting of the changing elements array + this.changingElemSize = 0; + + // While scanline not complete + while (bitOffset < this.w) { + while (isWhite) { + // White run + current = nextNBits(10); + entry = white[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x0f; + + if (bits == 12) { // Additional Make up code + // Get the next 2 bits + twoBits = nextLesserThan8Bits(2); + // Consolidate the 2 new bits and last 2 bits into 4 bits + current = ((current << 2) & 0x000c) | twoBits; + entry = additionalMakeup[current]; + bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >>> 4) & 0x0fff; // 12 bits + bitOffset += code; // Skip white run + + updatePointer(4 - bits); + } else if (bits == 0) { // ERROR + throw new RuntimeException("Invalid code encountered."); + } else if (bits == 15) { + // EOL recover + // move bits back... + updatePointer(10); + return; + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >>> 5) & 0x07ff; + bitOffset += code; + + updatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + } + + // Check whether this run completed one width, if so + // advance to next byte boundary for compression = 2. + if (bitOffset == this.w) { + align(); + break; + } + + while (isWhite == false) { + // Black run + current = nextLesserThan8Bits(4); + entry = initBlack[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x000f; + code = (entry >>> 5) & 0x07ff; + + if (code == 100) { + current = nextNBits(9); + entry = black[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x000f; + code = (entry >>> 5) & 0x07ff; + + if (bits == 12) { + // Additional makeup codes + updatePointer(5); + current = nextLesserThan8Bits(4); + entry = additionalMakeup[current]; + bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >>> 4) & 0x0fff; // 12 bits + + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(4 - bits); + } else if (bits == 15) { + // EOL recover + // unread bits ??? + updatePointer(9); + return; + } else { + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + } else if (code == 200) { + // Is a Terminating code + current = nextLesserThan8Bits(2); + entry = twoBitBlack[current]; + code = (entry >>> 5) & 0x07ff; + bits = (entry >>> 1) & 0x0f; + + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(2 - bits); + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } else { + // Is a Terminating code + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(4 - bits); + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + + // Check whether this run completed one width + if (bitOffset == this.w) { + align(); + break; + } + } + + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + + // One-dimensional decoding methods + public void decodeT41D(byte[] buffer, byte[] compData, int startX, + int height) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int lineOffset = 0; + for (int i = 0; i < height; i++) { + consumeEOL(); + decodeNextScanline(buffer, lineOffset, startX); + lineOffset += scanlineStride; + } + } + + // Two-dimensional decoding methods + public void decodeT42D(byte[] buffer, byte[] compData, int startX, + int height) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int a0; + int a1; + int b1; + int b2; + int[] b = new int[2]; + int entry; + int code; + int bits; + boolean isWhite; + int currIndex = 0; + int[] temp; + + // The data must start with an EOL code + if (readEOL(true) != 1) { + throw new RuntimeException("First scanline must be 1D encoded."); //$NON-NLS-1$ + } + + int lineOffset = 0; + int bitOffset; + + // Then the 1D encoded scanline data will occur, changing elements + // array gets set. + decodeNextScanline(buffer, lineOffset, startX); + lineOffset += scanlineStride; + + for (int lines = 1; lines < height; lines++) { + // Every line must begin with an EOL followed by a bit which + // indicates whether the following scanline is 1D or 2D encoded. + if (readEOL(false) == 0) { + // 2D encoded scanline follows + + // Initialize previous scanlines changing elements, and + // initialize current scanline's changing elements array + temp = this.prevChangingElems; + this.prevChangingElems = this.currChangingElems; + this.currChangingElems = temp; + currIndex = 0; + + // a0 has to be set just before the start of this scanline. + a0 = -1; + isWhite = true; + bitOffset = startX; + + this.lastChangingElement = 0; + + while (bitOffset < this.w) { + // Get the next changing element + getNextChangingElement(a0, isWhite, b); + + b1 = b[0]; + b2 = b[1]; + + // Get the next seven bits + entry = nextLesserThan8Bits(7); + + // Run these through the 2DCodes table + entry = (twoDCodes[entry] & 0xff); + + // Get the code and the number of bits used up + code = (entry & 0x78) >>> 3; + bits = entry & 0x07; + + if (code == 0) { + if (!isWhite) { + setToBlack(buffer, lineOffset, bitOffset, b2 + - bitOffset); + } + bitOffset = a0 = b2; + + // Set pointer to consume the correct number of bits. + updatePointer(7 - bits); + } else if (code == 1) { + // Horizontal + updatePointer(7 - bits); + + // identify the next 2 codes. + int number; + if (isWhite) { + number = decodeWhiteCodeWord(); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + + number = decodeBlackCodeWord(); + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + } else { + number = decodeBlackCodeWord(); + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + + number = decodeWhiteCodeWord(); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + } + + a0 = bitOffset; + } else if (code <= 8) { + // Vertical + a1 = b1 + (code - 5); + + this.currChangingElems[currIndex++] = a1; + + // We write the current color till a1 - 1 pos, + // since a1 is where the next color starts + if (!isWhite) { + setToBlack(buffer, lineOffset, bitOffset, a1 + - bitOffset); + } + bitOffset = a0 = a1; + isWhite = !isWhite; + + updatePointer(7 - bits); + } else { + throw new RuntimeException( + "Invalid code encountered while decoding 2D group 3 compressed data."); //$NON-NLS-1$ + } + } + + // Add the changing element beyond the current scanline for the + // other color too + this.currChangingElems[currIndex++] = bitOffset; + this.changingElemSize = currIndex; + } else { + // 1D encoded scanline follows + decodeNextScanline(buffer, lineOffset, startX); + } + + lineOffset += scanlineStride; + } + } + + public synchronized void decodeT6(byte[] buffer, byte[] compData, + int startX, int height) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int a0; + int a1; + int b1; + int b2; + int entry; + int code; + int bits; + boolean isWhite; + int currIndex; + int[] temp; + + // Return values from getNextChangingElement + int[] b = new int[2]; + + // uncompressedMode - have written some code for this, but this + // has not been tested due to lack of test images using this optional + + // Local cached reference + int[] cce = this.currChangingElems; + + // Assume invisible preceding row of all white pixels and insert + // both black and white changing elements beyond the end of this + // imaginary scanline. + this.changingElemSize = 0; + cce[this.changingElemSize++] = this.w; + cce[this.changingElemSize++] = this.w; + + int lineOffset = 0; + int bitOffset; + + for (int lines = 0; lines < height; lines++) { + // a0 has to be set just before the start of the scanline. + a0 = -1; + isWhite = true; + + // Assign the changing elements of the previous scanline to + // prevChangingElems and start putting this new scanline's + // changing elements into the currChangingElems. + temp = this.prevChangingElems; + this.prevChangingElems = this.currChangingElems; + cce = this.currChangingElems = temp; + currIndex = 0; + + // Start decoding the scanline at startX in the raster + bitOffset = startX; + + // Reset search start position for getNextChangingElement + this.lastChangingElement = 0; + + // Till one whole scanline is decoded + while (bitOffset < this.w) { + // Get the next changing element + getNextChangingElement(a0, isWhite, b); + b1 = b[0]; + b2 = b[1]; + + // Get the next seven bits + entry = nextLesserThan8Bits(7); + // Run these through the 2DCodes table + entry = (twoDCodes[entry] & 0xff); + + // Get the code and the number of bits used up + code = (entry & 0x78) >>> 3; + bits = entry & 0x07; + + if (code == 0) { // Pass + // We always assume WhiteIsZero format for fax. + if (!isWhite) { + if (b2 > this.w) { + b2 = this.w; + } + setToBlack(buffer, lineOffset, bitOffset, b2 + - bitOffset); + } + bitOffset = a0 = b2; + + // Set pointer to only consume the correct number of bits. + updatePointer(7 - bits); + } else if (code == 1) { // Horizontal + // Set pointer to only consume the correct number of bits. + updatePointer(7 - bits); + + // identify the next 2 alternating color codes. + int number; + if (isWhite) { + // Following are white and black runs + number = decodeWhiteCodeWord(); + bitOffset += number; + cce[currIndex++] = bitOffset; + + number = decodeBlackCodeWord(); + if (number > this.w - bitOffset) { + number = this.w - bitOffset; + } + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + cce[currIndex++] = bitOffset; + } else { + // First a black run and then a white run follows + number = decodeBlackCodeWord(); + if (number > this.w - bitOffset) { + number = this.w - bitOffset; + } + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + cce[currIndex++] = bitOffset; + + number = decodeWhiteCodeWord(); + bitOffset += number; + cce[currIndex++] = bitOffset; + } + + a0 = bitOffset; + } else if (code <= 8) { // Vertical + a1 = b1 + (code - 5); + cce[currIndex++] = a1; + + // We write the current color till a1 - 1 pos, + // since a1 is where the next color starts + if (!isWhite) { + if (a1 > this.w) { + a1 = this.w; + } + setToBlack(buffer, lineOffset, bitOffset, a1 + - bitOffset); + } + bitOffset = a0 = a1; + isWhite = !isWhite; + + updatePointer(7 - bits); + } else if (code == 11) { + if (nextLesserThan8Bits(3) != 7) { + throw new RuntimeException( + "Invalid code encountered while decoding 2D group 4 compressed data."); //$NON-NLS-1$ + } + + int zeros = 0; + boolean exit = false; + + while (!exit) { + while (nextLesserThan8Bits(1) != 1) { + zeros++; + } + + if (zeros > 5) { + // Exit code + + // Zeros before exit code + zeros = zeros - 6; + + if (!isWhite && (zeros > 0)) { + cce[currIndex++] = bitOffset; + } + + // Zeros before the exit code + bitOffset += zeros; + if (zeros > 0) { + // Some zeros have been written + isWhite = true; + } + + // Read in the bit which specifies the color of + // the following run + if (nextLesserThan8Bits(1) == 0) { + if (!isWhite) { + cce[currIndex++] = bitOffset; + } + isWhite = true; + } else { + if (isWhite) { + cce[currIndex++] = bitOffset; + } + isWhite = false; + } + + exit = true; + } + + if (zeros == 5) { + if (!isWhite) { + cce[currIndex++] = bitOffset; + } + bitOffset += zeros; + + // Last thing written was white + isWhite = true; + } else { + bitOffset += zeros; + + cce[currIndex++] = bitOffset; + setToBlack(buffer, lineOffset, bitOffset, 1); + ++bitOffset; + + // Last thing written was black + isWhite = false; + } + } + } else { + // break line - seems to be a common failure + // unread + updatePointer(7 - bits); + // and mark lines as complete + bitOffset = this.w; + // throw new RuntimeException( + // "Invalid code encountered while decoding 2D group 4 + // compressed data."); //$NON-NLS-1$ + } + } + + align(); + + // Add the changing element beyond the current scanline for the + // other color too + // make sure that the index does not exceed the bounds of the array + if (currIndex < this.w) { + cce[currIndex++] = bitOffset; + } + + // Number of changing elements in this scanline. + this.changingElemSize = currIndex; + + lineOffset += scanlineStride; + } + } + + // Returns run length + private int decodeWhiteCodeWord() { + int current; + int entry; + int bits; + int isT; + int twoBits; + int code = -1; + int runLength = 0; + boolean isWhite = true; + + while (isWhite) { + current = nextNBits(10); + entry = white[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >>> 1) & 0x0f; + + if (bits == 12) { // Additional Make up code + // Get the next 2 bits + twoBits = nextLesserThan8Bits(2); + // Consolidate the 2 new bits and last 2 bits into 4 bits + current = ((current << 2) & 0x000c) | twoBits; + entry = additionalMakeup[current]; + bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >>> 4) & 0x0fff; // 12 bits + runLength += code; + updatePointer(4 - bits); + } else if (bits == 0) { // ERROR + throw new RuntimeException("Invalid code encountered."); //$NON-NLS-1$ + } else if (bits == 15) { // EOL + throw new RuntimeException( + "EOL code word encountered in White run."); //$NON-NLS-1$ + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >>> 5) & 0x07ff; + runLength += code; + updatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + } + } + } + + return runLength; + } + + private void getNextChangingElement(int a0, boolean isWhite, int[] ret) { + // Local copies of instance variables + int[] pce = this.prevChangingElems; + int ces = this.changingElemSize; + + // If the previous match was at an odd element, we still + // have to search the preceeding element. + // int start = lastChangingElement & ~0x1; + int start = (this.lastChangingElement > 0) ? (this.lastChangingElement - 1) : 0; + if (isWhite) { + start &= ~0x1; // Search even numbered elements + } else { + start |= 0x1; // Search odd numbered elements + } + + int i = start; + for (; i < ces; i += 2) { + int temp = pce[i]; + if (temp > a0) { + this.lastChangingElement = i; + ret[0] = temp; + break; + } + } + + if ((i + 1) < ces) { + ret[1] = pce[i + 1]; + } + } + + public boolean isAlign() { + return this.align; + } + + public boolean isFillBits() { + return this.fillBits; + } + + private int nextLesserThan8Bits(int bitsToGet) { + byte b; + byte next; + int l = this.data.length - 1; + int bp = this.bytePointer; + + if (this.fillOrder == 1) { + b = this.data[bp]; + if (bp == l) { + next = 0x00; + } else { + next = this.data[bp + 1]; + } + } else if (this.fillOrder == 2) { + b = flipTable[this.data[bp] & 0xff]; + if (bp == l) { + next = 0x00; + } else { + next = flipTable[this.data[bp + 1] & 0xff]; + } + } else { + throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ + } + + int bitsLeft = 8 - this.bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + + int shift = bitsLeft - bitsToGet; + int i1; + int i2; + if (shift >= 0) { + i1 = (b & table1[bitsLeft]) >>> shift; + this.bitPointer += bitsToGet; + if (this.bitPointer == 8) { + this.bitPointer = 0; + this.bytePointer++; + } + } else { + i1 = (b & table1[bitsLeft]) << (-shift); + i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); + + i1 |= i2; + this.bytePointer++; + this.bitPointer = bitsFromNextByte; + } + + return i1; + } + + private int nextNBits(int bitsToGet) { + byte b; + byte next; + byte next2next; + int l = this.data.length - 1; + int bp = this.bytePointer; + + if (this.fillOrder == 1) { + b = this.data[bp]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = this.data[bp + 1]; + next2next = 0x00; + } else { + next = this.data[bp + 1]; + next2next = this.data[bp + 2]; + } + } else if (this.fillOrder == 2) { + b = flipTable[this.data[bp] & 0xff]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = flipTable[this.data[bp + 1] & 0xff]; + next2next = 0x00; + } else { + next = flipTable[this.data[bp + 1] & 0xff]; + next2next = flipTable[this.data[bp + 2] & 0xff]; + } + } else { + throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ + } + + int bitsLeft = 8 - this.bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + int bitsFromNext2NextByte = 0; + if (bitsFromNextByte > 8) { + bitsFromNext2NextByte = bitsFromNextByte - 8; + bitsFromNextByte = 8; + } + + this.bytePointer++; + + int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); + int i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); + + int i3 = 0; + if (bitsFromNext2NextByte != 0) { + i2 <<= bitsFromNext2NextByte; + i3 = (next2next & table2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); + i2 |= i3; + this.bytePointer++; + this.bitPointer = bitsFromNext2NextByte; + } else { + if (bitsFromNextByte == 8) { + this.bitPointer = 0; + this.bytePointer++; + } else { + this.bitPointer = bitsFromNextByte; + } + } + + int i = i1 | i2; + return i; + } + + private int readEOL(boolean isFirstEOL) { + // Seek to the next EOL. + if (!seekEOL()) { + throw new RuntimeException("EOL not found"); + } + + if (!this.fillBits) { + int next12Bits = nextNBits(12); + if (isFirstEOL && (next12Bits == 0)) { + // Might have the case of EOL padding being used even + // though it was not flagged. + // This was observed to be the case in TIFFs produced + // by a well known vendor who shall remain nameless. + if (nextNBits(4) == 1) { + // EOL must be padded: reset the fillBits flag. + this.fillBits = true; + return 1; + } + } + if (next12Bits != 1) { + throw new RuntimeException( + "Scanline must begin with EOL code word."); //$NON-NLS-1$ + } + } else { + // First EOL code word xxxx 0000 0000 0001 will occur + // As many fill bits will be present as required to make + // the EOL code of 12 bits end on a byte boundary. + int bitsLeft = 8 - this.bitPointer; + + if (nextNBits(bitsLeft) != 0) { + throw new RuntimeException( + "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ + } + + // If the number of bitsLeft is less than 8, then to have a 12 + // bit EOL sequence, two more bytes are certainly going to be + // required. The first of them has to be all zeros, so ensure + // that. + if (bitsLeft < 4) { + if (nextNBits(8) != 0) { + throw new RuntimeException( + "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ + } + } + + // + // Some encoders under Group 3 Fax compression 1D writes TIFF + // files without the fill bits, but say otherwise. + // Need to check for this here. + // + int next8 = nextNBits(8); + + if (isFirstEOL && (next8 & 0xf0) == 0x10) { + // + // Fill bits are not actually used despite what the flag + // says. So switch fillBits off and then rewind so that + // only 12 bits have effectively been read. + // + this.fillBits = false; + updatePointer(4); + } else { + // + // This is the normal case. + // There might be a random number of fill bytes with 0s, so + // loop till the EOL of 0000 0001 is found, as long as all + // the bytes preceding it are 0's. + // + while (next8 != 1) { + // If not all zeros + if (next8 != 0) { + throw new RuntimeException("0 bits expected before EOL"); + } + next8 = nextNBits(8); + } + } + } + // The next one bit signifies 1D/2D encoding of next line. + return nextLesserThan8Bits(1); + } + + // Seeks to the next EOL in the compressed bitstream. + // Returns 'true' if and only if an EOL is found; if 'false' + // is returned it may be inferred that the EOF was reached first. + private boolean seekEOL() { + // Set maximum and current bit index into the compressed data. + int bitIndexMax = this.data.length * 8 - 1; + int bitIndex = this.bytePointer * 8 + this.bitPointer; + + // Loop while at least 12 bits are available. + while (bitIndex <= bitIndexMax - 12) { + // Get the next 12 bits. + int next12Bits = nextNBits(12); + bitIndex += 12; + + // Loop while the 12 bits are not unity, i.e., while the EOL + // has not been reached, and there is at least one bit left. + while (next12Bits != 1 && bitIndex < bitIndexMax) { + next12Bits = ((next12Bits & 0x000007ff) << 1) + | (nextLesserThan8Bits(1) & 0x00000001); + bitIndex++; + } + + // If EOL reached, rewind the pointers and return 'true'. + if (next12Bits == 1) { + updatePointer(12); + return true; + } + } + + // EOL not found: return 'false'. + return false; + } + + public void setAlign(boolean align) { + this.align = align; + } + + public void setFillBits(boolean fillBits) { + this.fillBits = fillBits; + } + + private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, + int numBits) { + int bitNum = (8 * lineOffset) + bitOffset; + int lastBit = bitNum + numBits; + + int byteNum = bitNum >> 3; + + // Handle bits in first byte + int shift = bitNum & 0x7; + if (shift > 0) { + int maskVal = 1 << (7 - shift); + byte val = buffer[byteNum]; + while ((maskVal > 0) && (bitNum < lastBit)) { + val |= maskVal; + maskVal >>= 1; + ++bitNum; + } + buffer[byteNum] = val; + } + + // Fill in 8 bits at a time + byteNum = bitNum >> 3; + while (bitNum < (lastBit - 7)) { + buffer[byteNum++] = (byte) 255; + bitNum += 8; + } + + // Fill in remaining bits + while (bitNum < lastBit) { + byteNum = bitNum >> 3; + buffer[byteNum] |= (1 << (7 - (bitNum & 0x7))); + ++bitNum; + } + } + + // Move pointer backwards by given amount of bits + private void updatePointer(int bitsToMoveBack) { + if (bitsToMoveBack > 8) { + this.bytePointer -= bitsToMoveBack / 8; + bitsToMoveBack %= 8; + } + + int i = this.bitPointer - bitsToMoveBack; + + if (i < 0) { + this.bytePointer--; + this.bitPointer = 8 + i; + } else { + this.bitPointer = i; + } + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/FlateDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/FlateDecode.java index dd1eeb419..43d724d12 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/FlateDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/FlateDecode.java @@ -63,15 +63,15 @@ public static ByteBuffer decode(PDFObject dict, ByteBuffer buf, byte[] decomp = new byte[bufSize]; int read = 0; - try { + try { while (!inf.finished()) { read = inf.inflate(decomp); if (read <= 0) { - if (inf.needsDictionary()) { + if (inf.needsDictionary()) { throw new PDFParseException("Don't know how to ask for a dictionary in FlateDecode"); } else { - // just return the data which is already read - break; + // just return the data which is already read + break; } } baos.write(decomp, 0, read); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ImageDataDecoder.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ImageDataDecoder.java index 8b2d20eb9..eeaf570d9 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ImageDataDecoder.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/ImageDataDecoder.java @@ -12,69 +12,69 @@ ****************************************************************************/ public class ImageDataDecoder { - - /************************************************************************* - * @param bimg - * @return - ************************************************************************/ - static byte[] decodeImageData(BufferedImage bimg) { - byte[] output = null; - - int type = bimg.getType(); + /************************************************************************* + * @param bimg + * @return + ************************************************************************/ + + static byte[] decodeImageData(BufferedImage bimg) { + byte[] output = null; + + int type = bimg.getType(); - if (type == BufferedImage.TYPE_INT_RGB) { - // read back the data - DataBufferInt db = (DataBufferInt) bimg.getData() - .getDataBuffer(); - int[] data = db.getData(); + if (type == BufferedImage.TYPE_INT_RGB) { + // read back the data + DataBufferInt db = (DataBufferInt) bimg.getData() + .getDataBuffer(); + int[] data = db.getData(); - output = new byte[data.length * 3]; - for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { - output[offset] = (byte) (data[i] >> 16); - output[offset + 1] = (byte) (data[i] >> 8); - output[offset + 2] = (byte) (data[i]); - } - } else if (type == BufferedImage.TYPE_BYTE_GRAY) { - DataBufferByte db = (DataBufferByte) bimg.getData() - .getDataBuffer(); - output = db.getData(); - } else if (type == BufferedImage.TYPE_INT_ARGB) { - // read back the data - DataBufferInt db = (DataBufferInt) bimg.getData() - .getDataBuffer(); - int[] data = db.getData(); + output = new byte[data.length * 3]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { + output[offset] = (byte) (data[i] >> 16); + output[offset + 1] = (byte) (data[i] >> 8); + output[offset + 2] = (byte) (data[i]); + } + } else if (type == BufferedImage.TYPE_BYTE_GRAY) { + DataBufferByte db = (DataBufferByte) bimg.getData() + .getDataBuffer(); + output = db.getData(); + } else if (type == BufferedImage.TYPE_INT_ARGB) { + // read back the data + DataBufferInt db = (DataBufferInt) bimg.getData() + .getDataBuffer(); + int[] data = db.getData(); - output = new byte[data.length * 4]; - for (int i = 0, offset = 0; i < data.length; i++, offset += 4) { - output[offset] = (byte) (data[i] >> 24); - output[offset + 1] = (byte) (data[i] >> 16); - output[offset + 2] = (byte) (data[i] >> 8); - output[offset + 3] = (byte) (data[i]); - } - } else { - // The raster is in some other format. - // We have to convert it into TYPE_INT_RGB before we can use it. - BufferedImage tmp = new BufferedImage(bimg.getWidth(), - bimg.getHeight(), BufferedImage.TYPE_INT_RGB); - Graphics g = tmp.createGraphics(); - g.drawImage(bimg, 0, 0, null); - g.dispose(); - // read back the data - DataBufferInt db = (DataBufferInt) tmp.getData() - .getDataBuffer(); - int[] data = db.getData(); + output = new byte[data.length * 4]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 4) { + output[offset] = (byte) (data[i] >> 24); + output[offset + 1] = (byte) (data[i] >> 16); + output[offset + 2] = (byte) (data[i] >> 8); + output[offset + 3] = (byte) (data[i]); + } + } else { + // The raster is in some other format. + // We have to convert it into TYPE_INT_RGB before we can use it. + BufferedImage tmp = new BufferedImage(bimg.getWidth(), + bimg.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics g = tmp.createGraphics(); + g.drawImage(bimg, 0, 0, null); + g.dispose(); + // read back the data + DataBufferInt db = (DataBufferInt) tmp.getData() + .getDataBuffer(); + int[] data = db.getData(); - output = new byte[data.length * 3]; - for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { - output[offset] = (byte) (data[i] >> 16); - output[offset + 1] = (byte) (data[i] >> 8); - output[offset + 2] = (byte) (data[i]); - } - tmp.flush(); - } - return output; - } + output = new byte[data.length * 3]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { + output[offset] = (byte) (data[i] >> 16); + output[offset + 1] = (byte) (data[i] >> 8); + output[offset + 2] = (byte) (data[i]); + } + tmp.flush(); + } + return output; + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/JPXDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/JPXDecode.java index 723a05026..e4a3d3778 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/JPXDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/JPXDecode.java @@ -39,7 +39,7 @@ */ public class JPXDecode { - + /************************************************************************* * @param dict * @param buf @@ -47,40 +47,40 @@ public class JPXDecode { * @return * @throws PDFParseException ************************************************************************/ - + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException { BufferedImage bimg = loadImageData(buf); byte[] output = ImageDataDecoder.decodeImageData(bimg); - return ByteBuffer.wrap(output); + return ByteBuffer.wrap(output); } - /************************************************************************* - * @param buf - * @return - * @throws PDFParseException - * @throws IOException - ************************************************************************/ + /************************************************************************* + * @param buf + * @return + * @throws PDFParseException + * @throws IOException + ************************************************************************/ - private static BufferedImage loadImageData(ByteBuffer buf) throws PDFParseException { + private static BufferedImage loadImageData(ByteBuffer buf) throws PDFParseException { ImageReader reader = null; - try { - byte[] input = new byte[buf.remaining()]; - buf.get(input); - Iterator readers = ImageIO.getImageReadersByMIMEType("image/jpeg2000"); - if (readers.hasNext() == false) { - throw new PDFParseException("JPXDecode failed. No reader available"); - } - reader = readers.next(); - reader.setInput(new MemoryCacheImageInputStream(new ByteArrayInputStream(input))); - BufferedImage bimg = reader.read(0); - return bimg; - } catch (IOException e) { + try { + byte[] input = new byte[buf.remaining()]; + buf.get(input); + Iterator readers = ImageIO.getImageReadersByMIMEType("image/jpeg2000"); + if (readers.hasNext() == false) { + throw new PDFParseException("JPXDecode failed. No reader available"); + } + reader = readers.next(); + reader.setInput(new MemoryCacheImageInputStream(new ByteArrayInputStream(input))); + BufferedImage bimg = reader.read(0); + return bimg; + } catch (IOException e) { throw new PDFParseException("JPXDecode failed", e); } finally { if (reader != null) { reader.dispose(); } - } + } - } + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/LZWDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/LZWDecode.java index 7075b5fcb..ec2deaee3 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/LZWDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/LZWDecode.java @@ -147,7 +147,7 @@ private ByteBuffer decode() throws PDFParseException { break; } else if (cW == CLEARDICT) { resetDict(); - // pW= -1; + // pW= -1; } else if (pW == CLEARDICT) { baos.write(this.dict[cW], 0, this.dict[cW].length); } else { @@ -158,9 +158,9 @@ private ByteBuffer decode() throws PDFParseException { p[this.dict[pW].length] = this.dict[cW][0]; this.dict[this.dictlen++] = p; } else { // not in the dictionary (should==dictlen) - // if (cW!=dictlen) { - // System.out.println("Got a bouncy code: "+cW+" (dictlen="+dictlen+")"); - // } + // if (cW!=dictlen) { + // System.out.println("Got a bouncy code: "+cW+" (dictlen="+dictlen+")"); + // } byte[] p = new byte[this.dict[pW].length + 1]; System.arraycopy(this.dict[pW], 0, p, 0, this.dict[pW].length); p[this.dict[pW].length] = p[0]; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/PNGPredictor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/PNGPredictor.java index 5c973d844..6afce754a 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/PNGPredictor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/PNGPredictor.java @@ -40,7 +40,7 @@ public PNGPredictor() { * Undo data based on the png algorithm */ @Override - public ByteBuffer unpredict(ByteBuffer imageData) + public ByteBuffer unpredict(ByteBuffer imageData) throws IOException { List rows = new ArrayList(); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/Predictor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/Predictor.java index 3b265cd19..e952f957d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/Predictor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/Predictor.java @@ -84,7 +84,7 @@ public static Predictor getPredictor(PDFObject params) // no predictor return null; case 2: - predictor = new TIFFPredictor(); + predictor = new TIFFPredictor(); break; case 10: case 11: diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/RunLengthDecode.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/RunLengthDecode.java index 8e4bb1853..f8a6d625e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/RunLengthDecode.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decode/RunLengthDecode.java @@ -30,65 +30,65 @@ * @author Mike Wessler */ public class RunLengthDecode { - /** the end of data in the RunLength encoding. */ - private static final int RUN_LENGTH_EOD = 128; + /** the end of data in the RunLength encoding. */ + private static final int RUN_LENGTH_EOD = 128; - private ByteBuffer buf; + private ByteBuffer buf; - /** - * initialize the decoder with an array of bytes in RunLength format - */ - private RunLengthDecode(ByteBuffer buf) { - this.buf = buf; - } + /** + * initialize the decoder with an array of bytes in RunLength format + */ + private RunLengthDecode(ByteBuffer buf) { + this.buf = buf; + } - /** - * decode the array - * - * @return the decoded bytes - */ - private ByteBuffer decode() { - // start at the beginning of the buffer - this.buf.rewind(); + /** + * decode the array + * + * @return the decoded bytes + */ + private ByteBuffer decode() { + // start at the beginning of the buffer + this.buf.rewind(); - // allocate the output buffer - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int dupAmount; - byte[] buffer = new byte[128]; - while ((dupAmount = this.buf.get()&0xFF) != RUN_LENGTH_EOD) { - if (dupAmount >= 0 && dupAmount <= 127) { - int amountToCopy = dupAmount + 1; - this.buf.get(buffer, 0, amountToCopy); - baos.write(buffer, 0, amountToCopy); - } else { - byte dupByte = this.buf.get(); - for (int i = 0; i < 257 - dupAmount; i++) { - baos.write(dupByte); - } - } - } - return ByteBuffer.wrap(baos.toByteArray()); - } + // allocate the output buffer + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int dupAmount; + byte[] buffer = new byte[128]; + while ((dupAmount = this.buf.get()&0xFF) != RUN_LENGTH_EOD) { + if (dupAmount >= 0 && dupAmount <= 127) { + int amountToCopy = dupAmount + 1; + this.buf.get(buffer, 0, amountToCopy); + baos.write(buffer, 0, amountToCopy); + } else { + byte dupByte = this.buf.get(); + for (int i = 0; i < 257 - dupAmount; i++) { + baos.write(dupByte); + } + } + } + return ByteBuffer.wrap(baos.toByteArray()); + } - /** - * decode an array of bytes in RunLength format. - *

    - * RunLength format consists of a sequence of a byte-oriented format based - * on run length. There are a series of "runs", where a run is a length byte - * followed by 1 to 128 bytes of data. If the length is 0-127, the following - * length+1 (1 to 128) bytes are to be copied. If the length is 129 through - * 255, the following single byte is copied 257-length (2 to 128) times. A - * length value of 128 means and End of Data (EOD). - * - * @param buf - * the RUnLEngth encoded bytes in a byte buffer - * - * @param params - * parameters to the decoder (ignored) - * @return the decoded bytes - */ - public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { - RunLengthDecode me = new RunLengthDecode(buf); - return me.decode(); - } + /** + * decode an array of bytes in RunLength format. + *

    + * RunLength format consists of a sequence of a byte-oriented format based + * on run length. There are a series of "runs", where a run is a length byte + * followed by 1 to 128 bytes of data. If the length is 0-127, the following + * length+1 (1 to 128) bytes are to be copied. If the length is 129 through + * 255, the following single byte is copied 257-length (2 to 128) times. A + * length value of 128 means and End of Data (EOD). + * + * @param buf + * the RUnLEngth encoded bytes in a byte buffer + * + * @param params + * parameters to the decoder (ignored) + * @return the decoded bytes + */ + public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { + RunLengthDecode me = new RunLengthDecode(buf); + return me.decode(); + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/IdentityDecrypter.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/IdentityDecrypter.java index 64f4a8926..d47527699 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/IdentityDecrypter.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/IdentityDecrypter.java @@ -35,7 +35,7 @@ public class IdentityDecrypter implements PDFDecrypter { private static IdentityDecrypter INSTANCE = new IdentityDecrypter(); @Override - public ByteBuffer decryptBuffer(String cryptFilterName, + public ByteBuffer decryptBuffer(String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException { @@ -47,7 +47,7 @@ public ByteBuffer decryptBuffer(String cryptFilterName, } @Override - public String decryptString(int objNum, int objGen, String inputBasicString) { + public String decryptString(int objNum, int objGen, String inputBasicString) { return inputBasicString; } @@ -56,17 +56,17 @@ public static IdentityDecrypter getInstance() { } @Override - public boolean isEncryptionPresent() { + public boolean isEncryptionPresent() { return false; } @Override - public boolean isEncryptionPresent(String cryptFilterName) { + public boolean isEncryptionPresent(String cryptFilterName) { return false; } @Override - public boolean isOwnerAuthorised() { + public boolean isOwnerAuthorised() { return false; } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/PDFPassword.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/PDFPassword.java index fb5272bb2..9c1e170af 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/PDFPassword.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/decrypt/PDFPassword.java @@ -141,7 +141,7 @@ List getPasswordBytes(boolean unicodeConversion) { // just strip the higher 8 bits! new PasswordByteGenerator() { @Override - public byte[] generateBytes(String password) { + public byte[] generateBytes(String password) { return PDFStringUtil.asBytes(password); } }, @@ -219,7 +219,7 @@ protected CharsetEncoderGenerator(Byte replacementByte) { @Override - public byte[] generateBytes(String password) { + public byte[] generateBytes(String password) { final CharsetEncoder encoder = createCharsetEncoder(); if (this.replacementByte != null) { encoder.replaceWith(new byte[]{this.replacementByte}); @@ -254,7 +254,7 @@ private PDFDocEncodingByteGenerator(Byte replacementByte) { } @Override - protected CharsetEncoder createCharsetEncoder() { + protected CharsetEncoder createCharsetEncoder() { return new PDFDocCharsetEncoder(); } } @@ -271,7 +271,7 @@ private IdentityEncodingByteGenerator(Byte replacementByte) { } @Override - protected CharsetEncoder createCharsetEncoder() { + protected CharsetEncoder createCharsetEncoder() { return new Identity8BitCharsetEncoder(); } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/BuiltinFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/BuiltinFont.java index a3546f5d7..54fcb865e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/BuiltinFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/BuiltinFont.java @@ -130,8 +130,8 @@ public BuiltinFont(String baseFont, PDFObject fontObj, style |= Font.BOLD; } if ((descriptor.getItalicAngle() != 0) || - ((flags & (PDFFontDescriptor.SCRIPT | PDFFontDescriptor.ITALIC)) != 0)) { - style |= Font.ITALIC; + ((flags & (PDFFontDescriptor.SCRIPT | PDFFontDescriptor.ITALIC)) != 0)) { + style |= Font.ITALIC; } String name = null; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType0.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType0.java index 7c5690443..1d897c878 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType0.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType0.java @@ -19,50 +19,50 @@ public class CIDFontType0 extends BuiltinFont { - private PDFCMap glyphLookupMap; + private PDFCMap glyphLookupMap; - /************************************************************************* - * Constructor - * @param baseFont - * @param fontObj - * @param descriptor - * @throws IOException - ************************************************************************/ - - public CIDFontType0(String baseFont, PDFObject fontObj, - PDFFontDescriptor descriptor) throws IOException { - super(baseFont, fontObj, descriptor); - } - - /************************************************************************* - * @param fontObj - * @throws IOException - ************************************************************************/ - - public void parseToUnicodeMap(PDFObject fontObj) throws IOException { - PDFObject toUnicode = fontObj.getDictRef("ToUnicode"); - if (toUnicode != null) { - PDFCMap cmap = PDFCMap.getCMap(toUnicode); - this.glyphLookupMap = cmap; - } - } - - /** + /************************************************************************* + * Constructor + * @param baseFont + * @param fontObj + * @param descriptor + * @throws IOException + ************************************************************************/ + + public CIDFontType0(String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + super(baseFont, fontObj, descriptor); + } + + /************************************************************************* + * @param fontObj + * @throws IOException + ************************************************************************/ + + public void parseToUnicodeMap(PDFObject fontObj) throws IOException { + PDFObject toUnicode = fontObj.getDictRef("ToUnicode"); + if (toUnicode != null) { + PDFCMap cmap = PDFCMap.getCMap(toUnicode); + this.glyphLookupMap = cmap; + } + } + + /** * Get a character from the first font in the descendant fonts array */ @Override - protected PDFGlyph getGlyph(char src, String name) { + protected PDFGlyph getGlyph(char src, String name) { //TODO BROS 03.08.2011 Hack for unsupported Type0 CID based fonts - // If we have a toUnicodeMap then try to use that one when mapping to our build in font. - // See "9.10 Extraction of Text Content" in the PDF spec. + // If we have a toUnicodeMap then try to use that one when mapping to our build in font. + // See "9.10 Extraction of Text Content" in the PDF spec. if (this.glyphLookupMap != null) { - src = this.glyphLookupMap.map(src); + src = this.glyphLookupMap.map(src); //The preferred method of getting the glyph should be by name. if (name == null && src != 160){//unless it NBSP - //so, try to find the name by the char - name = AdobeGlyphList.getGlyphName(src); + //so, try to find the name by the char + name = AdobeGlyphList.getGlyphName(src); } } - return super.getGlyph(src, name); + return super.getGlyph(src, name); } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType2.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType2.java index 3ca49a5e5..da026a5f1 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType2.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/CIDFontType2.java @@ -86,8 +86,8 @@ private void parseWidths(PDFObject fontObj) // read the default width (otpional) PDFObject defaultWidthObj = fontObj.getDictRef("DW"); if (defaultWidthObj != null && defaultWidthObj.getIntValue() != 0) { - // XOND: commented out the setting of new default width, as several - // PDFs are displayed in a wrong format due to this: + // XOND: commented out the setting of new default width, as several + // PDFs are displayed in a wrong format due to this: // this.defaultWidth = defaultWidthObj.getIntValue(); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/FlPoint.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/FlPoint.java index db4ea56a6..5482ca7fe 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/FlPoint.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/FlPoint.java @@ -41,8 +41,8 @@ public class FlPoint { /** reset the values to (0,0) and closed */ public final void reset() { - this.x= 0; - this.y= 0; - this.open= false; + this.x= 0; + this.y= 0; + this.open= false; } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/NativeFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/NativeFont.java index 5d42fc3dd..0920f4e26 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/NativeFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/NativeFont.java @@ -131,7 +131,7 @@ public NativeFont (String baseFont, PDFObject fontObj, * @return the glyph outline, or null if unavailable */ @Override - protected GeneralPath getOutline (String name, float width) { + protected GeneralPath getOutline (String name, float width) { if (this.postTable != null && this.cmapTable != null) { // map this character name to a glyph ID short glyphID = this.postTable.getGlyphNameIndex (name); @@ -172,7 +172,7 @@ protected GeneralPath getOutline (String name, float width) { * @return the glyph outline */ @Override - protected GeneralPath getOutline (char src, float width) { + protected GeneralPath getOutline (char src, float width) { // some true type fonts put characters in the undefined // region of Unicode instead of as normal characters. if (!this.f.canDisplay (src) && this.f.canDisplay ((char) (src + 0xf000))) { diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/OutlineFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/OutlineFont.java index 61daca0ef..7a80b0f25 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/OutlineFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/OutlineFont.java @@ -115,7 +115,7 @@ public float getWidth(char code, String name) { * @return a glyph for this character */ @Override - protected PDFGlyph getGlyph(char src, String name) { + protected PDFGlyph getGlyph(char src, String name) { GeneralPath outline = null; float width = getWidth(src, name); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFont.java index 31a74063d..ecd79177e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFont.java @@ -44,7 +44,7 @@ public abstract class PDFFont { private static final FilenameFilter TTF_FILTER = new FilenameFilter() { @Override - public boolean accept(File dir, String name) { + public boolean accept(File dir, String name) { return name.toLowerCase().endsWith(".ttf"); } }; @@ -161,12 +161,12 @@ public synchronized static PDFFont getFont(PDFObject obj, font = new Type0Font(baseFont, obj, descriptor); } else if (subType.equals("Type1")) { // load a type1 font - if (descriptor.getFontFile() != null) { + if (descriptor.getFontFile() != null) { // it's a Type1 font, included. font = new Type1Font(baseFont, obj, descriptor); if(!((Type1Font)font).isName2OutlineFilled()){ - PDFDebugger.debug("Type1Font can't be parsed completelly, character mapping missing. Use a basefont instead."); - font = new BuiltinFont(baseFont, obj, descriptor); + PDFDebugger.debug("Type1Font can't be parsed completelly, character mapping missing. Use a basefont instead."); + font = new BuiltinFont(baseFont, obj, descriptor); } } else if (descriptor.getFontFile3() != null) { // it's a CFF (Type1C) font @@ -181,22 +181,22 @@ public synchronized static PDFFont getFont(PDFObject obj, try { font = new TTFFont(baseFont, obj, descriptor); }catch (Exception e) { -// PDFRenderer.getErrorHandler().publishException(e); - PDFDebugger.debug("Error parsing font : " + baseFont); +// PDFRenderer.getErrorHandler().publishException(e); + PDFDebugger.debug("Error parsing font : " + baseFont); // fake it with a built-in font font = new BuiltinFont(baseFont, obj, descriptor); } } else { final File extFontFile = findExternalTtf(baseFont); if (extFontFile != null) { - try { + try { font = new TTFFont(baseFont, obj, descriptor, extFontFile); - }catch (Exception e) { -// PDFRenderer.getErrorHandler().publishException(e); - PDFDebugger.debug("Error parsing font : " + baseFont); - // fake it with a built-in font - font = new BuiltinFont(baseFont, obj, descriptor); - } + }catch (Exception e) { +// PDFRenderer.getErrorHandler().publishException(e); + PDFDebugger.debug("Error parsing font : " + baseFont); + // fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); + } } else { // fake it with a built-in font font = new BuiltinFont(baseFont, obj, descriptor); @@ -206,22 +206,22 @@ public synchronized static PDFFont getFont(PDFObject obj, // load a type 3 font font = new Type3Font(baseFont, obj, resources, descriptor); } else if (subType.equals("CIDFontType2")) { - if(descriptor.getFontFile2() != null) { + if(descriptor.getFontFile2() != null) { font = new CIDFontType2(baseFont, obj, descriptor); - }else { + }else { // fake it with a built-in font - //but it prefer to use the CIDFontType0 that have the extra handling of ToUnicode, if found in the fontObj - font = new CIDFontType0(baseFont, obj, descriptor); - } + //but it prefer to use the CIDFontType0 that have the extra handling of ToUnicode, if found in the fontObj + font = new CIDFontType0(baseFont, obj, descriptor); + } } else if (subType.equals("CIDFontType0")) { - if(descriptor.getFontFile2() !=null){ + if(descriptor.getFontFile2() !=null){ font = new CIDFontType2(baseFont, obj, descriptor); - }else { + }else { font = new CIDFontType0(baseFont, obj, descriptor); - } - } else if (subType.equals("MMType1")) { - // not yet implemented, fake it with a built-in font - font = new BuiltinFont(baseFont, obj, descriptor); + } + } else if (subType.equals("MMType1")) { + // not yet implemented, fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); } else { throw new PDFParseException("Don't know how to handle a '" + subType + "' font"); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontDescriptor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontDescriptor.java index 8625cfde1..1e237b45d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontDescriptor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontDescriptor.java @@ -104,8 +104,8 @@ public PDFFontDescriptor(PDFObject obj, String fontSubType) throws IOException { setFlags(obj.getDictRef("Flags").getIntValue()); PDFObject fontNameObj = obj.getDictRef("FontName"); if (fontNameObj == null){ - // fallback to avoid NPE try to use the BaseFont - fontNameObj = obj.getDictRef("BaseFont"); + // fallback to avoid NPE try to use the BaseFont + fontNameObj = obj.getDictRef("BaseFont"); } setFontName(fontNameObj.getStringValue()); setItalicAngle(obj.getDictRef("ItalicAngle").getIntValue()); @@ -114,32 +114,32 @@ public PDFFontDescriptor(PDFObject obj, String fontSubType) throws IOException { boolean areConditionalParametersRequired = !"Type3".equals(fontSubType) && !Boolean.getBoolean("PDFRenderer.lenientFontDescriptorParsing"); - // these values are declared as Required except for Type 3 fonts - // however a value might not be available for some fonts and - // therefore some predefined value is set, so that we have a fallback + // these values are declared as Required except for Type 3 fonts + // however a value might not be available for some fonts and + // therefore some predefined value is set, so that we have a fallback if ( obj.getDictionary().containsKey("Ascent")) { setAscent(obj.getDictRef("Ascent").getIntValue()); } else if (areConditionalParametersRequired) { - setAscent(728); // value of ArialMT as used with Report Label + setAscent(728); // value of ArialMT as used with Report Label } if ( obj.getDictionary().containsKey("CapHeight")) { setCapHeight(obj.getDictRef("CapHeight").getIntValue()); } else if (areConditionalParametersRequired) { - setCapHeight(716); // value of ArialMT as used with Report Label + setCapHeight(716); // value of ArialMT as used with Report Label } if ( obj.getDictionary().containsKey("Descent")) { setDescent(obj.getDictRef("Descent").getIntValue()); } else if (areConditionalParametersRequired) { - setDescent(-210); // value of ArialMT as used with Report Label + setDescent(-210); // value of ArialMT as used with Report Label } if ( obj.getDictionary().containsKey("StemV")) { setStemV(obj.getDictRef("StemV").getIntValue()); } else if (areConditionalParametersRequired) { - setStemV(109); // "normal" value for vertical stem width (PDFlib) + setStemV(109); // "normal" value for vertical stem width (PDFlib) } // font bounding box (non-optional but a NPE won't help) diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontEncoding.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontEncoding.java index d444329cb..92a61811f 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontEncoding.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/PDFFontEncoding.java @@ -61,12 +61,12 @@ public class PDFFontEncoding { * the type of this encoding (encoding or CMap) */ private int type; - private PDFObject mapName; + private PDFObject mapName; public PDFFontEncoding(PDFCMap cmap) { - super(); - this.type = TYPE_CMAP; - this.cmap = cmap; + super(); + this.type = TYPE_CMAP; + this.cmap = cmap; } /** Creates a new instance of PDFFontEncoding */ @@ -204,7 +204,7 @@ private int[] getBaseEncoding(String encodingName) { } else if (encodingName.equals("WinAnsiEncoding")) { return FontSupport.winAnsiEncoding; } else if (encodingName.equals("StandardEncoding")) { - return FontSupport.standardEncoding; + return FontSupport.standardEncoding; } else if(encodingName.equals("SymbolSetEncoding")) { return FontSupport.symbolSetEncoding; } else { @@ -213,14 +213,14 @@ private int[] getBaseEncoding(String encodingName) { } public boolean isOneByteIdentity() { - if(this.mapName != null) { - try { - return "OneByteIdentityH".equals(this.mapName.getStringValue()); - } catch (IOException e) { - PDFRenderer.getErrorHandler().publishException(e); - } - } - - return false; + if(this.mapName != null) { + try { + return "OneByteIdentityH".equals(this.mapName.getStringValue()); + } catch (IOException e) { + PDFRenderer.getErrorHandler().publishException(e); + } + } + + return false; } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/TTFFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/TTFFont.java index c370edf16..9d69db252 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/TTFFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/TTFFont.java @@ -109,7 +109,7 @@ public Collection getNames() * Get the outline of a character given the character code */ @Override - protected synchronized GeneralPath getOutline (char src, float width) { + protected synchronized GeneralPath getOutline (char src, float width) { // find the cmaps CmapTable cmap = (CmapTable) this.font.getTable ("cmap"); @@ -131,15 +131,15 @@ protected synchronized GeneralPath getOutline (char src, float width) { // windows symbol font CMap may use one of the following code ranges if (src >= 0 && src <= 0xFF) { - int[] symbolPages = new int[]{0xF000, 0xF100, 0xF200}; - for (int codePage : symbolPages) { + int[] symbolPages = new int[]{0xF000, 0xF100, 0xF200}; + for (int codePage : symbolPages) { for (int i = 0; i < maps.length; i++) { int idx = maps[i].map ( (char)(src | codePage)); if (idx != 0) { return getOutline (idx, width); } - } - } + } + } } // not found, return the empty glyph @@ -166,7 +166,7 @@ protected synchronized GeneralPath getOutlineFrom31CMap (char val, // find the (3, 1) cmap subtable (Microsoft Unicode) CMap map = cmap.getCMap ((short) 3, (short) 1); if (map == null) { - return null; + return null; } int idx = map.map (val); if (idx != 0) { @@ -180,7 +180,7 @@ protected synchronized GeneralPath getOutlineFrom31CMap (char val, * Get the outline of a character given the character name */ @Override - protected synchronized GeneralPath getOutline (String name, float width) { + protected synchronized GeneralPath getOutline (String name, float width) { int idx; PostTable post = (PostTable) this.font.getTable ("post"); if (post != null) { @@ -222,11 +222,11 @@ protected synchronized GeneralPath getOutline (int glyphId, float width) { // scale the glyph to match the desired advance float widthfactor = width / advance; - // the base transform scales the glyph to 1x1 - AffineTransform at = AffineTransform.getScaleInstance(1 / this.unitsPerEm, 1 / this.unitsPerEm); - if (advance != 0) { - at.concatenate(AffineTransform.getScaleInstance(widthfactor, 1)); - } + // the base transform scales the glyph to 1x1 + AffineTransform at = AffineTransform.getScaleInstance(1 / this.unitsPerEm, 1 / this.unitsPerEm); + if (advance != 0) { + at.concatenate(AffineTransform.getScaleInstance(widthfactor, 1)); + } gp.transform (at); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type0Font.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type0Font.java index 0f70fcb80..9375ea57c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type0Font.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type0Font.java @@ -48,9 +48,9 @@ public Type0Font(String baseFont, PDFObject fontObj, for (int i = 0; i < descendantFonts.length; i++) { PDFFont descFont = getFont(descendantFonts[i], null); if (descFont instanceof CIDFontType0) { - ((CIDFontType0)descFont).parseToUnicodeMap(fontObj); + ((CIDFontType0)descFont).parseToUnicodeMap(fontObj); } - this.fonts[i] = descFont; + this.fonts[i] = descFont; } } @@ -65,7 +65,7 @@ public PDFFont getDescendantFont(int fontID) { * Get a character from the first font in the descendant fonts array */ @Override - protected PDFGlyph getGlyph(char src, String name) { + protected PDFGlyph getGlyph(char src, String name) { return (getDescendantFont(0).getGlyph(src, name)); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1CFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1CFont.java index 60d10e0ea..1e75aa8b5 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1CFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1CFont.java @@ -162,7 +162,7 @@ private int readNext (boolean charstring) { printData (); throw new RuntimeException ("Got a 255 code while reading dict"); } else { // num was 255 - this.fnum = (((this.data[this.pos] & 0xff) << 24) | + this.fnum = (((this.data[this.pos] & 0xff) << 24) | ((this.data[this.pos + 1] & 0xff) << 16) | ((this.data[this.pos + 2] & 0xff) << 8) | ((this.data[this.pos + 3] & 0xff))) / 65536f; @@ -314,7 +314,7 @@ public final int getEnd () { } @Override - public String toString () { + public String toString () { return "Range: start: " + this.start + ", len: " + this.len; } } @@ -522,7 +522,7 @@ private void readNames (int base) { this.pos = base; int nextra = readInt (2); this.names = new String[nextra]; - // safenames= new String[nextra]; + // safenames= new String[nextra]; for (int i = 0; i < nextra; i++) { Range r = getIndexEntry (base, i); this.names[i] = new String (this.data, r.getStart (), r.getLen ()); @@ -814,7 +814,7 @@ void parseGlyph (Range r, GeneralPath gp, FlPoint pt) { break; case 19: // hintmask case 20: // cntrmask - stemhints += (this.stackptr) / 2; + stemhints += (this.stackptr) / 2; this.pos += (stemhints - 1) / 8 + 1; this.stackptr = 0; break; @@ -1144,7 +1144,7 @@ void parseGlyph (Range r, GeneralPath gp, FlPoint pt) { * @return the glyph outline, or null if unavailable */ @Override - protected GeneralPath getOutline (String name, float width) { + protected GeneralPath getOutline (String name, float width) { // first find the index of this name int index = getNameIndex (name); @@ -1168,7 +1168,7 @@ protected GeneralPath getOutline (String name, float width) { * @return the glyph outline */ @Override - protected GeneralPath getOutline (char src, float width) { + protected GeneralPath getOutline (char src, float width) { // ignore high bits int index = (src & 0xff); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1Font.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1Font.java index 6d71bf580..97e7d5f1b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1Font.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type1Font.java @@ -521,14 +521,14 @@ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { this.sloc = 0; break; case 4: // y vmoveto - pt.y += pop(); - if (flexMode) { - flexArray[flexPt++] = pt.x; - flexArray[flexPt++] = pt.y; - } - else{ - gp.moveTo(pt.x, pt.y); - } + pt.y += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else{ + gp.moveTo(pt.x, pt.y); + } this.sloc = 0; break; case 5: // x y rlineto @@ -538,13 +538,13 @@ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { this.sloc = 0; break; case 6: // x hlineto - pt.x += pop(); + pt.x += pop(); gp.lineTo(pt.x, pt.y); this.sloc = 0; break; case 7: // y vlineto - pt.y += pop(); - gp.lineTo(pt.x, pt.y); + pt.y += pop(); + gp.lineTo(pt.x, pt.y); this.sloc = 0; break; case 8: // x1 y1 x2 y2 x3 y3 rcurveto @@ -568,36 +568,36 @@ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { case 10: // n callsubr int n = (int) pop(); if (n == 1) { - flexMode = true; - flexPt = 0; - this.sloc = 0; - break; + flexMode = true; + flexPt = 0; + this.sloc = 0; + break; } if (n == 0) { - if (flexPt != 14) { - PDFDebugger.debug("There must be 14 flex entries!"); - } - else { - gp.curveTo(flexArray[2], flexArray[3], flexArray[4], - flexArray[5], - flexArray[6], flexArray[7]); - gp.curveTo(flexArray[8], flexArray[9], flexArray[10], - flexArray[11], - flexArray[12], flexArray[13]); - flexMode = false; - this.sloc = 0; - //System.out.println("End Flex " + flexPt); - break; - } + if (flexPt != 14) { + PDFDebugger.debug("There must be 14 flex entries!"); + } + else { + gp.curveTo(flexArray[2], flexArray[3], flexArray[4], + flexArray[5], + flexArray[6], flexArray[7]); + gp.curveTo(flexArray[8], flexArray[9], flexArray[10], + flexArray[11], + flexArray[12], flexArray[13]); + flexMode = false; + this.sloc = 0; + //System.out.println("End Flex " + flexPt); + break; + } } if (n == 2) { - if (flexMode == false) { - PDFDebugger.debug("Flex mode assumed"); - } - else { - this.sloc = 0; - break; - } + if (flexMode == false) { + PDFDebugger.debug("Flex mode assumed"); + } + else { + this.sloc = 0; + break; + } } if (this.subrs[n] == null) { PDFDebugger.debug("No subroutine #" + n); @@ -678,11 +678,11 @@ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { wid.y = 0; pt.x = pop(); pt.y = 0; - // gp.moveTo(pt.x, pt.y); + // gp.moveTo(pt.x, pt.y); this.sloc = 0; break; case 14: // endchar - // return; + // return; break; case 15: // x case 16: // x @@ -692,26 +692,26 @@ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { case 20: // x throw new RuntimeException("Bad command (" + v + ")"); case 21: // x y rmoveto - pt.y += pop(); - pt.x += pop(); - if (flexMode) { - flexArray[flexPt++] = pt.x; - flexArray[flexPt++] = pt.y; - } - else{ - gp.moveTo(pt.x, pt.y); - } - this.sloc = 0; + pt.y += pop(); + pt.x += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else{ + gp.moveTo(pt.x, pt.y); + } + this.sloc = 0; break; case 22: // x hmoveto - pt.x += pop(); - if (flexMode) { - flexArray[flexPt++] = pt.x; - flexArray[flexPt++] = pt.y; - } - else { - gp.moveTo(pt.x, pt.y); - } + pt.x += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else { + gp.moveTo(pt.x, pt.y); + } this.sloc = 0; break; case 23: // x @@ -853,7 +853,7 @@ private synchronized GeneralPath parseGlyph(byte[] cs, FlPoint advance, * @return the glyph outline, or null if unavailable */ @Override - protected GeneralPath getOutline(String name, float width) { + protected GeneralPath getOutline(String name, float width) { // make sure we have a valid name if (name == null || !this.name2outline.containsKey(name)) { name = ".notdef"; @@ -898,11 +898,11 @@ protected GeneralPath getOutline(String name, float width) { * @return the glyph outline */ @Override - protected GeneralPath getOutline(char src, float width) { + protected GeneralPath getOutline(char src, float width) { return getOutline(this.chr2name[src & 0xff], width); } public boolean isName2OutlineFilled() { - return (name2outline!=null) && !name2outline.isEmpty(); + return (name2outline!=null) && !name2outline.isEmpty(); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type3Font.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type3Font.java index 542f83ba6..ff8aec979 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type3Font.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/Type3Font.java @@ -141,7 +141,7 @@ public int getLastChar() { * @return a glyph for this character */ @Override - protected PDFGlyph getGlyph(char src, String name) { + protected PDFGlyph getGlyph(char src, String name) { if (name == null) { throw new IllegalArgumentException("Glyph name required for Type3 font!" + "Source character: " + (int) src); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/PDFCMap.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/PDFCMap.java index cdfff5571..6600f4c68 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/PDFCMap.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/PDFCMap.java @@ -64,8 +64,8 @@ public static PDFCMap getCMap(String mapName) throws IOException { if (!cache.containsKey(mapName)) { //throw new IOException("Unknown CMap: " + mapName); - PDFDebugger.debug("Unknown CMap: '" + mapName + "' procced with 'Identity-H'"); - return cache.get("Identity-H"); + PDFDebugger.debug("Unknown CMap: '" + mapName + "' procced with 'Identity-H'"); + return cache.get("Identity-H"); } return cache.get(mapName); @@ -80,7 +80,7 @@ protected static void populateCache() { // add the Identity-H map cache.put("Identity-H", new PDFCMap() { @Override - public char map(char src) { + public char map(char src) { return src; } }); @@ -90,7 +90,7 @@ public char map(char src) { * Parse a CMap from a CMap stream */ protected static PDFCMap parseCMap(PDFObject map) throws IOException { - return new ToUnicodeMap(map); + return new ToUnicodeMap(map); } /** diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/ToUnicodeMap.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/ToUnicodeMap.java index cf6e76617..6656b1939 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/ToUnicodeMap.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/cid/ToUnicodeMap.java @@ -22,289 +22,289 @@ ****************************************************************************/ public class ToUnicodeMap extends PDFCMap { - - /***************************************************************************** - * Small helper class to define a code range. - ****************************************************************************/ + + /***************************************************************************** + * Small helper class to define a code range. + ****************************************************************************/ - private static class CodeRangeMapping { - char srcStart; - char srcEnd; - - CodeRangeMapping(char srcStart, char srcEnd) { - this.srcStart = srcStart; - this.srcEnd = srcEnd; - } - - boolean contains(char c) { - return this.srcStart <= c - && c <= this.srcEnd; - } - - } - - /***************************************************************************** - * Small helper class to define a char range. - ****************************************************************************/ + private static class CodeRangeMapping { + char srcStart; + char srcEnd; + + CodeRangeMapping(char srcStart, char srcEnd) { + this.srcStart = srcStart; + this.srcEnd = srcEnd; + } + + boolean contains(char c) { + return this.srcStart <= c + && c <= this.srcEnd; + } + + } + + /***************************************************************************** + * Small helper class to define a char range. + ****************************************************************************/ - private static class CharRangeMapping { - char srcStart; - char srcEnd; - char destStart; - - CharRangeMapping(char srcStart, char srcEnd, char destStart) { - this.srcStart = srcStart; - this.srcEnd = srcEnd; - this.destStart = destStart; - } - - boolean contains(char c) { - return this.srcStart <= c - && c <= this.srcEnd; - } - - char map(char src) { - return (char) (this.destStart + (src-this.srcStart)); - } - - } - - private final Map singleCharMappings; - private final List charRangeMappings; - private final List codeRangeMappings; + private static class CharRangeMapping { + char srcStart; + char srcEnd; + char destStart; + + CharRangeMapping(char srcStart, char srcEnd, char destStart) { + this.srcStart = srcStart; + this.srcEnd = srcEnd; + this.destStart = destStart; + } + + boolean contains(char c) { + return this.srcStart <= c + && c <= this.srcEnd; + } + + char map(char src) { + return (char) (this.destStart + (src-this.srcStart)); + } + + } + + private final Map singleCharMappings; + private final List charRangeMappings; + private final List codeRangeMappings; - /************************************************************************* - * Constructor - * @param map - * @throws IOException - ************************************************************************/ - - public ToUnicodeMap(PDFObject map) throws IOException { - super(); - this.singleCharMappings = new HashMap(); - this.charRangeMappings = new ArrayList(); - this.codeRangeMappings = new ArrayList(); - parseMappings(map); - } - - /************************************************************************* - * @param map - * @throws IOException - ************************************************************************/ - - private void parseMappings(PDFObject map) throws IOException { - try { - StringReader reader = new StringReader(new String(map.getStream(), "ASCII")); - BufferedReader bf = new BufferedReader(reader); - String line = bf.readLine(); - while (line != null) { - if (line.contains("beginbfchar") || line.contains("begincidchar")) { - parseSingleCharMappingSection(bf, line.contains("begincidchar")); - } - if (line.contains("beginbfrange") || line.contains("begincidrange")) { - parseCharRangeMappingSection(bf, line.contains("begincidrange")); - } - if (line.contains("begincodespacerange")) { - parseCodeRangeMappingSection(bf, line); - } - line = bf.readLine(); - } - } catch (UnsupportedEncodingException e) { - throw new IOException(e); - } - } + /************************************************************************* + * Constructor + * @param map + * @throws IOException + ************************************************************************/ + + public ToUnicodeMap(PDFObject map) throws IOException { + super(); + this.singleCharMappings = new HashMap(); + this.charRangeMappings = new ArrayList(); + this.codeRangeMappings = new ArrayList(); + parseMappings(map); + } + + /************************************************************************* + * @param map + * @throws IOException + ************************************************************************/ + + private void parseMappings(PDFObject map) throws IOException { + try { + StringReader reader = new StringReader(new String(map.getStream(), "ASCII")); + BufferedReader bf = new BufferedReader(reader); + String line = bf.readLine(); + while (line != null) { + if (line.contains("beginbfchar") || line.contains("begincidchar")) { + parseSingleCharMappingSection(bf, line.contains("begincidchar")); + } + if (line.contains("beginbfrange") || line.contains("begincidrange")) { + parseCharRangeMappingSection(bf, line.contains("begincidrange")); + } + if (line.contains("begincodespacerange")) { + parseCodeRangeMappingSection(bf, line); + } + line = bf.readLine(); + } + } catch (UnsupportedEncodingException e) { + throw new IOException(e); + } + } - /************************************************************************* - * @param bf - * @throws IOException - ************************************************************************/ - - private void parseCharRangeMappingSection(BufferedReader bf, boolean isCid) throws IOException { - String line = bf.readLine(); - while (line != null) { - if (line.contains("endbfrange") || line.contains("endcidrange")) { - break; - } - parseRangeLine(line, isCid); - line = bf.readLine(); - } - } + /************************************************************************* + * @param bf + * @throws IOException + ************************************************************************/ + + private void parseCharRangeMappingSection(BufferedReader bf, boolean isCid) throws IOException { + String line = bf.readLine(); + while (line != null) { + if (line.contains("endbfrange") || line.contains("endcidrange")) { + break; + } + parseRangeLine(line, isCid); + line = bf.readLine(); + } + } - private void parseCodeRangeMappingSection(BufferedReader bf, String line) throws IOException { - //check if the prev line contains "endcodespacerange" - if(line.contains("endcodespacerange")) { - int indexOf = line.indexOf("endcodespacerange"); - line = line.substring(0, indexOf); - indexOf = line.indexOf("begincodespacerange"); - line = line.substring(indexOf+"begincodespacerange".length(), line.length()); - line = line.trim(); - - parseCodeRangeLine(line); - } - else { - String rline = bf.readLine(); - while (rline != null) { - if (rline.contains("endcodespacerange")) { - break; - } - parseCodeRangeLine(rline); - rline = bf.readLine(); - } - } - } + private void parseCodeRangeMappingSection(BufferedReader bf, String line) throws IOException { + //check if the prev line contains "endcodespacerange" + if(line.contains("endcodespacerange")) { + int indexOf = line.indexOf("endcodespacerange"); + line = line.substring(0, indexOf); + indexOf = line.indexOf("begincodespacerange"); + line = line.substring(indexOf+"begincodespacerange".length(), line.length()); + line = line.trim(); + + parseCodeRangeLine(line); + } + else { + String rline = bf.readLine(); + while (rline != null) { + if (rline.contains("endcodespacerange")) { + break; + } + parseCodeRangeLine(rline); + rline = bf.readLine(); + } + } + } - /************************************************************************* - * @param line - * @return - ************************************************************************/ - - private void parseRangeLine(String line, boolean isCid) { - String[] mapping = line.split(" "); - if (mapping.length == 3) { - Character srcStart = parseChar(mapping[0]); - Character srcEnd = parseChar(mapping[1]); - Character destStart; - if(isCid) { - destStart = (char)Integer.parseInt(mapping[2]); - } - else { - destStart = parseChar(mapping[2]); - } - this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); - } - else { - int indexOf1 = line.indexOf(">"); - String substring1 = line.substring(0, indexOf1+1); - - int indexOf2 = line.indexOf("<", indexOf1); - int indexOf3 = line.indexOf(">", indexOf2); - String substring2 = line.substring(indexOf2, indexOf3+1); - - int indexOf4 = line.indexOf("<", indexOf3); - String substring3 = line.substring(indexOf4, line.length()); - - if(!substring1.isEmpty() && !substring2.isEmpty() && !substring3.isEmpty()) { - Character srcStart = parseChar(substring1); - Character srcEnd = parseChar(substring2); - Character destStart = parseChar(substring3); - this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); - } - } - } + /************************************************************************* + * @param line + * @return + ************************************************************************/ + + private void parseRangeLine(String line, boolean isCid) { + String[] mapping = line.split(" "); + if (mapping.length == 3) { + Character srcStart = parseChar(mapping[0]); + Character srcEnd = parseChar(mapping[1]); + Character destStart; + if(isCid) { + destStart = (char)Integer.parseInt(mapping[2]); + } + else { + destStart = parseChar(mapping[2]); + } + this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); + } + else { + int indexOf1 = line.indexOf(">"); + String substring1 = line.substring(0, indexOf1+1); + + int indexOf2 = line.indexOf("<", indexOf1); + int indexOf3 = line.indexOf(">", indexOf2); + String substring2 = line.substring(indexOf2, indexOf3+1); + + int indexOf4 = line.indexOf("<", indexOf3); + String substring3 = line.substring(indexOf4, line.length()); + + if(!substring1.isEmpty() && !substring2.isEmpty() && !substring3.isEmpty()) { + Character srcStart = parseChar(substring1); + Character srcEnd = parseChar(substring2); + Character destStart = parseChar(substring3); + this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); + } + } + } - private void parseCodeRangeLine(String line) { - String[] mapping = line.split(" "); - if (mapping.length == 2) { - Character srcStart = parseChar(mapping[0]); - Character srcEnd = parseChar(mapping[1]); - this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); - } - else { - int indexOf1 = line.indexOf(">"); - String substring1 = line.substring(0, indexOf1+1); - - int indexOf2 = line.indexOf("<", indexOf1); - String substring2 = line.substring(indexOf2, line.length()); - - if(!substring1.isEmpty() && !substring2.isEmpty()) { - Character srcStart = parseChar(substring1); - Character srcEnd = parseChar(substring2); - this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); - } - } - } + private void parseCodeRangeLine(String line) { + String[] mapping = line.split(" "); + if (mapping.length == 2) { + Character srcStart = parseChar(mapping[0]); + Character srcEnd = parseChar(mapping[1]); + this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); + } + else { + int indexOf1 = line.indexOf(">"); + String substring1 = line.substring(0, indexOf1+1); + + int indexOf2 = line.indexOf("<", indexOf1); + String substring2 = line.substring(indexOf2, line.length()); + + if(!substring1.isEmpty() && !substring2.isEmpty()) { + Character srcStart = parseChar(substring1); + Character srcEnd = parseChar(substring2); + this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); + } + } + } - /************************************************************************* - * @param bf - * @throws IOException - ************************************************************************/ - - private void parseSingleCharMappingSection(BufferedReader bf, boolean isCID) throws IOException { - String line = bf.readLine(); - while (line != null) { - if (line.contains("endbfchar") || line.contains("endcidchar")) { - break; - } - parseSingleCharMappingLine(line, isCID); - line = bf.readLine(); - } - } + /************************************************************************* + * @param bf + * @throws IOException + ************************************************************************/ + + private void parseSingleCharMappingSection(BufferedReader bf, boolean isCID) throws IOException { + String line = bf.readLine(); + while (line != null) { + if (line.contains("endbfchar") || line.contains("endcidchar")) { + break; + } + parseSingleCharMappingLine(line, isCID); + line = bf.readLine(); + } + } - /************************************************************************* - * @param line - * @return - ************************************************************************/ - - private void parseSingleCharMappingLine(String line, boolean isCID) { - String[] mapping = line.split(" "); - if (mapping.length == 2) { - if(isCID) { - this.singleCharMappings.put(parseChar(mapping[0]), (char)Integer.parseInt(mapping[1])); - } - else { - this.singleCharMappings.put(parseChar(mapping[0]), parseChar(mapping[1])); - } - } - } + /************************************************************************* + * @param line + * @return + ************************************************************************/ + + private void parseSingleCharMappingLine(String line, boolean isCID) { + String[] mapping = line.split(" "); + if (mapping.length == 2) { + if(isCID) { + this.singleCharMappings.put(parseChar(mapping[0]), (char)Integer.parseInt(mapping[1])); + } + else { + this.singleCharMappings.put(parseChar(mapping[0]), parseChar(mapping[1])); + } + } + } - /************************************************************************* - * Parse a string of the format <0F3A> to a char. - * @param charDef - * @return - ************************************************************************/ - - private Character parseChar(String charDef) { - if (charDef.startsWith("<")) { - charDef = charDef.substring(1); - } - if (charDef.endsWith(">")) { - charDef = charDef.substring(0, charDef.length()-1); - } - try { - long result = Long.decode("0x" + charDef); - return (char) result; - } catch (NumberFormatException e) { - return (char) ' '; - } - } + /************************************************************************* + * Parse a string of the format <0F3A> to a char. + * @param charDef + * @return + ************************************************************************/ + + private Character parseChar(String charDef) { + if (charDef.startsWith("<")) { + charDef = charDef.substring(1); + } + if (charDef.endsWith(">")) { + charDef = charDef.substring(0, charDef.length()-1); + } + try { + long result = Long.decode("0x" + charDef); + return (char) result; + } catch (NumberFormatException e) { + return (char) ' '; + } + } - /************************************************************************* - * map - * @see PDFCMap#map(char) - ************************************************************************/ - @Override - public char map(char src) { - Character mappedChar = null; - for (CodeRangeMapping codeRange : this.codeRangeMappings) { - if(codeRange.contains(src)) { - mappedChar = this.singleCharMappings.get(src); - if (mappedChar == null) { - mappedChar = lookupInRanges(src); - } - break; - } - } - if (mappedChar == null) { - // TODO XOND 27.03.2012: PDF Spec. "9.7.6.3Handling Undefined Characters" - mappedChar = 0; - } - return mappedChar; - } + /************************************************************************* + * map + * @see PDFCMap#map(char) + ************************************************************************/ + @Override + public char map(char src) { + Character mappedChar = null; + for (CodeRangeMapping codeRange : this.codeRangeMappings) { + if(codeRange.contains(src)) { + mappedChar = this.singleCharMappings.get(src); + if (mappedChar == null) { + mappedChar = lookupInRanges(src); + } + break; + } + } + if (mappedChar == null) { + // TODO XOND 27.03.2012: PDF Spec. "9.7.6.3Handling Undefined Characters" + mappedChar = 0; + } + return mappedChar; + } - /************************************************************************* - * @param src - * @return - ************************************************************************/ - - private Character lookupInRanges(char src) { - Character mappedChar = null; - for (CharRangeMapping rangeMapping : this.charRangeMappings) { - if (rangeMapping.contains(src)) { - mappedChar = rangeMapping.map(src); - break; - } - } - return mappedChar; - } + /************************************************************************* + * @param src + * @return + ************************************************************************/ + + private Character lookupInRanges(char src) { + Character mappedChar = null; + for (CharRangeMapping rangeMapping : this.charRangeMappings) { + if (rangeMapping.contains(src)) { + mappedChar = rangeMapping.map(src); + break; + } + } + return mappedChar; + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/AdobeGlyphList.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/AdobeGlyphList.java index 203e9aea3..95d23e727 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/AdobeGlyphList.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/AdobeGlyphList.java @@ -77,7 +77,7 @@ private AdobeGlyphList() { glyphLoaderThread = new Thread(new Runnable() { @Override - public void run() { + public void run() { int[] codes; StringTokenizer codeTokens; String glyphName; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat0.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat0.java index ec7a4198b..2d95aaeb3 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat0.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat0.java @@ -49,7 +49,7 @@ protected CMapFormat0(short language) { * Get the length of this table */ @Override - public short getLength() { + public short getLength() { return (short) 262; } @@ -57,7 +57,7 @@ public short getLength() { * Map from a byte */ @Override - public byte map(byte src) { + public byte map(byte src) { int i = 0xff & src; return this.glyphIndex[i]; @@ -67,7 +67,7 @@ public byte map(byte src) { * Cannot map from short */ @Override - public char map(char src) { + public char map(char src) { if (src < 0 || src > 255) { // out of range return (char) 0; @@ -81,7 +81,7 @@ public char map(char src) { * Get the src code which maps to the given glyphID */ @Override - public char reverseMap(short glyphID) { + public char reverseMap(short glyphID) { for (int i = 0; i < this.glyphIndex.length; i++) { if ((this.glyphIndex[i] & 0xff) == glyphID) { return (char) i; @@ -122,7 +122,7 @@ protected byte[] getMap() { * Get the data in this map as a ByteBuffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(262); buf.putShort(getFormat()); @@ -140,7 +140,7 @@ public ByteBuffer getData() { * Read the map in from a byte buffer */ @Override - public void setData(int length, ByteBuffer data) { + public void setData(int length, ByteBuffer data) { if (length != 262) { throw new IllegalArgumentException("Bad length for CMap format 0"); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat4.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat4.java index b4fd29ce9..d0d57049b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat4.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat4.java @@ -110,7 +110,7 @@ public short getLength() { * Cannot map from a byte */ @Override - public byte map(byte src) { + public byte map(byte src) { char c = map((char) src); if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { // out of range @@ -124,7 +124,7 @@ public byte map(byte src) { * Map from char */ @Override - public char map(char src) { + public char map(char src) { // find first segment with endcode > src for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); @@ -157,7 +157,7 @@ public char map(char src) { * Get the src code which maps to the given glyphID */ @Override - public char reverseMap(short glyphID) { + public char reverseMap(short glyphID) { // look at each segment for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); @@ -195,7 +195,7 @@ public char reverseMap(short glyphID) { * Get the data in this map as a ByteBuffer */ @Override - public void setData(int length, ByteBuffer data) { + public void setData(int length, ByteBuffer data) { // read the table size values short segCount = (short) (data.getShort() / 2); short searchRange = data.getShort(); @@ -268,7 +268,7 @@ public void setData(int length, ByteBuffer data) { * Get the data in the map as a byte buffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the header @@ -439,7 +439,7 @@ public Segment(short startCode, short endCode, boolean hasMap) { /** Segments sort by increasing endCode */ @Override - public int compareTo(Object o) { + public int compareTo(Object o) { if (!(o instanceof Segment)) { return -1; } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat6.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat6.java index b4d20b4c6..395efc52a 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat6.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CMapFormat6.java @@ -60,7 +60,7 @@ public short getLength() { * Cannot map from a byte */ @Override - public byte map(byte src) { + public byte map(byte src) { char c = map((char) src); if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { // out of range @@ -73,7 +73,7 @@ public byte map(byte src) { * Map from char */ @Override - public char map(char src) { + public char map(char src) { // find first segment with endcode > src if (src < this.firstCode || src > (this.firstCode + this.entryCount)) { @@ -88,7 +88,7 @@ public char map(char src) { * Get the src code which maps to the given glyphID */ @Override - public char reverseMap(short glyphID) { + public char reverseMap(short glyphID) { Short result = this.glyphLookup.get(Short.valueOf(glyphID)); if (result == null) { return '\000'; @@ -101,7 +101,7 @@ public char reverseMap(short glyphID) { * Get the data in this map as a ByteBuffer */ @Override - public void setData(int length, ByteBuffer data) { + public void setData(int length, ByteBuffer data) { // read the table size values this.firstCode = data.getShort(); this.entryCount = data.getShort(); @@ -118,7 +118,7 @@ public void setData(int length, ByteBuffer data) { * Get the data in the map as a byte buffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the header diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CmapTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CmapTable.java index 82e79724a..2f346072b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CmapTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/CmapTable.java @@ -77,17 +77,17 @@ public CMap[] getCMaps() { CMap cmap_3_1 = this.getCMap((short)3, (short)1); if (cmap_3_1 != null) { - c.add(cmap_3_1); + c.add(cmap_3_1); } CMap cmap_1_0 = this.getCMap((short)1, (short)0); if (cmap_1_0 != null) { - c.add(cmap_1_0); + c.add(cmap_1_0); } for (CMap cmap : this.subtables.values()) { - if (!c.contains(cmap)) { - c.add(cmap); - } + if (!c.contains(cmap)) { + c.add(cmap); + } } ; CMap[] maps = new CMap[c.size()]; @@ -269,7 +269,7 @@ protected CmapSubtable(short platformID, short platformSpecificID) { * Sort ascending by platform ID and then specific ID */ @Override - public int compareTo(Object obj) { + public int compareTo(Object obj) { if (!(obj instanceof CmapSubtable)) { return -1; } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfCompound.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfCompound.java index 199c4632d..403292702 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfCompound.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfCompound.java @@ -36,7 +36,7 @@ public class GlyfCompound extends Glyf { private static final int WE_HAVE_AN_X_AND_Y_SCALE = 0x40; private static final int WE_HAVE_A_TWO_BY_TWO = 0x80; private static final int WE_HAVE_INSTRUCTIONS = 0x100; - private static final int USE_MY_METRICS = 0x200; + private static final int USE_MY_METRICS = 0x200; private static final int OVERLAP_COMPOUND = 0x400; /** the flags for each compound glyph */ @@ -104,7 +104,7 @@ protected GlyfCompound() { } if ((cur.flags & WE_HAVE_INSTRUCTIONS) != 0) { - hasInstructions = true; + hasInstructions = true; } comps.add(cur); @@ -181,7 +181,7 @@ public double[] getTransform(int index) { m *= 2; } - float n = Math.max(Math.abs(gc.c), Math.abs(gc.d)); + float n = Math.max(Math.abs(gc.c), Math.abs(gc.d)); if (Math.abs(Math.abs(gc.c) - Math.abs(gc.d)) < (33 / 65536)) { n *= 2; } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfSimple.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfSimple.java index 5f7587881..ea52a1a7f 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfSimple.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfSimple.java @@ -133,7 +133,7 @@ public void setData(ByteBuffer data) { * buffer. */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = super.getData(); // write the contour end points diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfTable.java index 7f3e7d776..caa6d42ce 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/GlyfTable.java @@ -68,7 +68,7 @@ public Glyf getGlyph(int index) { /** get the data in this map as a ByteBuffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); @@ -77,7 +77,7 @@ public ByteBuffer getData() { for (int i = 0; i < this.glyphs.length; i++) { Object o = this.glyphs[i]; if (o == null) { - continue; + continue; } ByteBuffer glyfData = null; @@ -100,7 +100,7 @@ public ByteBuffer getData() { /** Initialize this structure from a ByteBuffer */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { for (int i = 0; i < this.glyphs.length; i++) { int location = this.loca.getOffset(i); int length = this.loca.getSize(i); @@ -122,7 +122,7 @@ public void setData(ByteBuffer data) { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { int length = 0; for (int i = 0; i < this.glyphs.length; i++) { @@ -145,7 +145,7 @@ public int getLength() { * Create a pretty String */ @Override - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HeadTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HeadTable.java index 9ed7b636d..db027ccb9 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HeadTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HeadTable.java @@ -108,7 +108,7 @@ protected HeadTable() { * Parse the data before it is set */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { if (data.remaining() < 54) { throw new IllegalArgumentException("Bad Head table size " + data.remaining()); } @@ -135,7 +135,7 @@ public void setData(ByteBuffer data) { * Get the data we have stored */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); @@ -166,7 +166,7 @@ public ByteBuffer getData() { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { return 54; } @@ -446,7 +446,7 @@ public void setVersion(int version) { * Create a pretty string */ @Override - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HheaTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HheaTable.java index f6b0ab657..bc733d0ee 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HheaTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HheaTable.java @@ -79,7 +79,7 @@ protected HheaTable() { * Parse the data before it is set */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { if (data.remaining() != 36) { throw new IllegalArgumentException("Bad Head table size"); } @@ -109,7 +109,7 @@ public void setData(ByteBuffer data) { * Get the data we have stored */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); @@ -143,7 +143,7 @@ public ByteBuffer getData() { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { return 36; } @@ -167,7 +167,7 @@ public void setVersion(int version) { * Create a pretty string */ @Override - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HmtxTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HmtxTable.java index 5c28b121c..3b9da0b03 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HmtxTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/HmtxTable.java @@ -65,7 +65,7 @@ public short getLeftSideBearing(int glyphID) { /** get the data in this map as a ByteBuffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); @@ -87,7 +87,7 @@ public ByteBuffer getData() { /** Initialize this structure from a ByteBuffer */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { // some PDF writers subset the font but don't update the number of glyphs in the maxp table, // this would appear to break the TTF spec. // A better solution might be to try and override the numGlyphs in the maxp table based @@ -116,7 +116,7 @@ public void setData(ByteBuffer data) { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { return (this.advanceWidths.length * 2) + (this.leftSideBearings.length * 2); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/LocaTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/LocaTable.java index 5fd05dde4..6b7c6c426 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/LocaTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/LocaTable.java @@ -71,7 +71,7 @@ public boolean isLongFormat() { /** get the data in this map as a ByteBuffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); @@ -93,7 +93,7 @@ public ByteBuffer getData() { /** Initialize this structure from a ByteBuffer */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { for (int i = 0; i < this.offsets.length; i++) { if (isLongFormat()) { this.offsets[i] = data.getInt(); @@ -107,7 +107,7 @@ public void setData(ByteBuffer data) { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { if (isLongFormat()) { return this.offsets.length * 4; } else { diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/MaxpTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/MaxpTable.java index f4b37c6f0..d9aa56fa9 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/MaxpTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/MaxpTable.java @@ -98,7 +98,7 @@ protected MaxpTable() { * Set the values from data */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { if (data.remaining() != 32) { throw new IllegalArgumentException("Bad size for Maxp table"); } @@ -124,7 +124,7 @@ public void setData(ByteBuffer data) { * Get a buffer from the data */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); @@ -153,7 +153,7 @@ public ByteBuffer getData() { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { return 32; } @@ -401,7 +401,7 @@ public void setMaxComponentDepth(int maxComponentDepth) { * Create a pretty String */ @Override - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/NameTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/NameTable.java index 6189f73fb..a27ca1d06 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/NameTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/NameTable.java @@ -153,7 +153,7 @@ public boolean hasRecords(short platformID, short platformSpecificID) { * Read the table from data */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { //read table header setFormat(data.getShort()); int count = data.getShort(); @@ -194,7 +194,7 @@ public void setData(ByteBuffer data) { * Get the data in this table as a buffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { // alocate the output buffer ByteBuffer buf = ByteBuffer.allocate(getLength()); @@ -258,7 +258,7 @@ public ByteBuffer getData() { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { // start with the size of the fixed header plus the size of the // records int length = 6 + (12 * getCount()); @@ -324,7 +324,7 @@ public static String getCharsetName(int platformID, int encodingID) { /** Get a pretty string */ @Override - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; @@ -346,7 +346,7 @@ public String toString() { public Collection getNames() { - return Collections.unmodifiableCollection(records.values()); + return Collections.unmodifiableCollection(records.values()); } /** @@ -389,7 +389,7 @@ static class NameRecord implements Comparable { * Compare two records */ @Override - public boolean equals(Object o) { + public boolean equals(Object o) { return (compareTo(o) == 0); } @@ -397,7 +397,7 @@ public boolean equals(Object o) { * Compare two records */ @Override - public int compareTo(Object obj) { + public int compareTo(Object obj) { if (!(obj instanceof NameRecord)) { return -1; } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/PostTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/PostTable.java index 391acf81f..454698812 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/PostTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/PostTable.java @@ -84,7 +84,7 @@ public String getGlyphName(char c) { /** get the data in this map as a ByteBuffer */ @Override - public ByteBuffer getData() { + public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); @@ -112,7 +112,7 @@ public ByteBuffer getData() { /** Initialize this structure from a ByteBuffer */ @Override - public void setData(ByteBuffer data) { + public void setData(ByteBuffer data) { setFormat(data.getInt()); setItalicAngle(data.getInt()); setUnderlinePosition(data.getShort()); @@ -151,7 +151,7 @@ public void setData(ByteBuffer data) { * Get the length of this table */ @Override - public int getLength() { + public int getLength() { int size = 32; if (this.nameMap != null) { size += this.nameMap.getLength(); @@ -373,7 +373,7 @@ class PostMapFormat0 extends PostMap { }; @Override - /** map a name to a character index */ + /** map a name to a character index */ short getCharIndex(String charName) { for (int i = 0; i < this.stdNames.length; i++) { if (charName.equals(this.stdNames[i])) { @@ -385,25 +385,25 @@ short getCharIndex(String charName) { } @Override - /** name a character index to a name */ + /** name a character index to a name */ String getCharName(char charIndex) { return this.stdNames[charIndex]; } @Override - /** get the length of the data in this map */ + /** get the length of the data in this map */ int getLength() { return 0; } @Override - /** get the data in this map as a ByteBuffer */ + /** get the data in this map as a ByteBuffer */ ByteBuffer getData() { return ByteBuffer.allocate(0); } @Override - /** set the data in this map from a ByteBuffer */ + /** set the data in this map from a ByteBuffer */ void setData(ByteBuffer data) { // do nothing return; @@ -419,7 +419,7 @@ class PostMapFormat2 extends PostMapFormat0 { String[] glyphNames; @Override - /** Map a character name to an index */ + /** Map a character name to an index */ short getCharIndex(String charName) { // find the index of this character name short idx = -1; @@ -450,7 +450,7 @@ short getCharIndex(String charName) { } @Override - /** Map an index to a character name */ + /** Map an index to a character name */ String getCharName(char charIndex) { if (charIndex >= this.stdNames.length) { return this.glyphNames[charIndex - this.stdNames.length]; @@ -460,7 +460,7 @@ String getCharName(char charIndex) { } @Override - /** get the length of this class's data */ + /** get the length of this class's data */ int getLength() { // the size of the header plus the table of mappings int size = 2 + (2 * this.glyphNameIndex.length); @@ -475,7 +475,7 @@ int getLength() { } @Override - /** get the data in this map as a byte array */ + /** get the data in this map as a byte array */ ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); @@ -500,7 +500,7 @@ ByteBuffer getData() { } @Override - /** set the contents of this map from a ByteBuffer */ + /** set the contents of this map from a ByteBuffer */ void setData(ByteBuffer data) { short numGlyphs = data.getShort(); this.glyphNameIndex = new short[numGlyphs]; @@ -529,7 +529,7 @@ void setData(ByteBuffer data) { // the length is stored in the first byte, followed by // the data for (int i = 0; i < maxGlyph; i++) { - if(data.hasRemaining()) { + if(data.hasRemaining()) { // size in the first byte byte size = data.get(); @@ -538,7 +538,7 @@ void setData(ByteBuffer data) { data.get(stringData); this.glyphNames[i] = new String(stringData); - } + } } } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeFont.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeFont.java index 8ed09329b..ef98a230b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeFont.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeFont.java @@ -266,13 +266,13 @@ private static int calculateChecksum (String tagString, ByteBuffer data) { // starting at byte 8 as 0x0000. This the checkSumAdjustment so // must be ignored here (see the TTF spec) if (tagString.equals ("head")) { - if(!data.isReadOnly()) { - data.putInt (8, 0); - } - sum += data.getInt(); - sum += data.getInt(); - // consume the uncounted checkSumAdjustment int - data.getInt(); + if(!data.isReadOnly()) { + data.putInt (8, 0); + } + sum += data.getInt(); + sum += data.getInt(); + // consume the uncounted checkSumAdjustment int + data.getInt(); } int nlongs = (data.remaining () + 3) / 4; @@ -400,7 +400,7 @@ private void updateChecksumAdj (ByteBuffer fontData) { * Write the font to a pretty string */ @Override - public String toString () { + public String toString () { StringBuffer buf = new StringBuffer (); buf.append("Type : ").append(getType()).append("\n"); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeTable.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeTable.java index 358847661..bee1c6c47 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeTable.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/font/ttf/TrueTypeTable.java @@ -182,7 +182,7 @@ public static int stringToTag(String tag) { * Put into a nice string */ @Override - public String toString() { + public String toString() { String out = " " + tagToString(getTag()) + " Table. Data is: "; if (getData() == null) { out += "not set"; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType0.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType0.java index 505241b3f..90c967075 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType0.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType0.java @@ -64,7 +64,7 @@ protected FunctionType0() { /** Read the function information from a PDF Object */ @Override - protected void parse(PDFObject obj) throws IOException { + protected void parse(PDFObject obj) throws IOException { // read the size array (required) PDFObject sizeObj = obj.getDictRef("Size"); if (sizeObj == null) { @@ -127,7 +127,7 @@ protected void parse(PDFObject obj) throws IOException { * with the output values, or null to return a new array */ @Override - protected void doFunction(float[] inputs, int inputOffset, + protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // calculate the encoded values for each input @@ -147,7 +147,7 @@ protected void doFunction(float[] inputs, int inputOffset, } // do some magic - for (int i = 0; i < getNumOutputs(); i++) { + for (int i = 0; i < getNumOutputs(); i++) { if (getOrder() == 1) { outputs[i + outputOffset] = multilinearInterpolate(encoded, i); } else { diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType2.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType2.java index b037fe3fb..0470f9919 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType2.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType2.java @@ -48,7 +48,7 @@ public FunctionType2() { * Read the zeros, ones and exponent */ @Override - protected void parse(PDFObject obj) throws IOException + protected void parse(PDFObject obj) throws IOException { // read the exponent (required) PDFObject nObj = obj.getDictRef("N"); @@ -86,7 +86,7 @@ protected void parse(PDFObject obj) throws IOException * C0(j) + x^N * (C1(j) - C0(j)) */ @Override - protected void doFunction(float[] inputs, int inputOffset, + protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // read the input value diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType3.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType3.java index 1dd7b2be2..4057488e4 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType3.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType3.java @@ -105,7 +105,7 @@ protected FunctionType3() { *

    */ @Override - protected void parse(PDFObject obj) throws IOException { + protected void parse(PDFObject obj) throws IOException { // read the Functions array (required) PDFObject functionsObj = obj.getDictRef("Functions"); if (functionsObj == null) { @@ -114,7 +114,7 @@ protected void parse(PDFObject obj) throws IOException { PDFObject[] functionsAry = functionsObj.getArray(); functions = new PDFFunction[functionsAry.length]; for (int i = 0; i < functionsAry.length; i++) { - functions[i] = PDFFunction.getFunction(functionsAry[i]); + functions[i] = PDFFunction.getFunction(functionsAry[i]); } // read the Bounds array (required) @@ -125,7 +125,7 @@ protected void parse(PDFObject obj) throws IOException { PDFObject[] boundsAry = boundsObj.getArray(); bounds = new float[boundsAry.length + 2]; if (bounds.length - 2 != functions.length - 1) { - throw new PDFParseException("Bounds array must be of length " + (functions.length - 1)); + throw new PDFParseException("Bounds array must be of length " + (functions.length - 1)); } for (int i = 0; i < boundsAry.length; i++) { @@ -142,7 +142,7 @@ protected void parse(PDFObject obj) throws IOException { PDFObject[] encodeAry = encodeObj.getArray(); encode = new float[encodeAry.length]; if (encode.length != 2*functions.length) { - throw new PDFParseException("Encode array must be of length " + 2*functions.length); + throw new PDFParseException("Encode array must be of length " + 2*functions.length); } for (int i = 0; i < encodeAry.length; i++) { encode[i] = encodeAry[i].getFloatValue(); @@ -156,28 +156,28 @@ protected void parse(PDFObject obj) throws IOException { * with the output values, or null to return a new array */ @Override - protected void doFunction(float[] inputs, int inputOffset, - float[] outputs, int outputOffset) { - - float x = inputs[inputOffset]; + protected void doFunction(float[] inputs, int inputOffset, + float[] outputs, int outputOffset) { + + float x = inputs[inputOffset]; - // calculate the output values - int p = bounds.length - 2; - while (x < bounds[p]) p--; - x = interpolate(x, bounds[p], bounds[p+1], encode[2*p], encode[2*p + 1]); - float[] out = functions[p].calculate(new float[]{x}); - for (int i = 0; i < out.length; i++) { - outputs[i + outputOffset] = out[i]; - } + // calculate the output values + int p = bounds.length - 2; + while (x < bounds[p]) p--; + x = interpolate(x, bounds[p], bounds[p+1], encode[2*p], encode[2*p + 1]); + float[] out = functions[p].calculate(new float[]{x}); + for (int i = 0; i < out.length; i++) { + outputs[i + outputOffset] = out[i]; + } } @Override public int getNumInputs() { - return 1; + return 1; } @Override public int getNumOutputs() { - return functions[0].getNumOutputs(); + return functions[0].getNumOutputs(); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType4.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType4.java index 686d430b7..902f82420 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType4.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/FunctionType4.java @@ -50,13 +50,13 @@ protected FunctionType4() { /** Read the function information from a PDF Object */ @Override - protected void parse(PDFObject obj) throws IOException { - ByteBuffer buf = obj.getStreamBuffer(); - - byte[] byteA = new byte[buf.remaining()]; - buf.get(byteA); - String scriptContent = new String(byteA, "UTF-8"); - this.tokens = new PostScriptParser().parse(scriptContent); + protected void parse(PDFObject obj) throws IOException { + ByteBuffer buf = obj.getStreamBuffer(); + + byte[] byteA = new byte[buf.remaining()]; + buf.get(byteA); + String scriptContent = new String(byteA, "UTF-8"); + this.tokens = new PostScriptParser().parse(scriptContent); } /** @@ -72,50 +72,50 @@ protected void parse(PDFObject obj) throws IOException { * @param outputOffset the offset into the output array to write to */ @Override - protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { - prepareInitialStack(inputs, inputOffset); - for (Iterator iterator = this.tokens.iterator(); iterator.hasNext(); ) { - String token = iterator.next(); - PostScriptOperation op = OperationSet.getInstance().getOperation(token); - op.eval(this.stack); - } - assertResultIsCorrect(outputs, outputOffset); - prepareResult(outputs, outputOffset); + protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { + prepareInitialStack(inputs, inputOffset); + for (Iterator iterator = this.tokens.iterator(); iterator.hasNext(); ) { + String token = iterator.next(); + PostScriptOperation op = OperationSet.getInstance().getOperation(token); + op.eval(this.stack); + } + assertResultIsCorrect(outputs, outputOffset); + prepareResult(outputs, outputOffset); } - /************************************************************************* - * @param outputs - * @param outputOffset - ************************************************************************/ - private void prepareResult(float[] outputs, int outputOffset) { - for (int i = outputOffset; i < outputs.length; i++) { - outputs[outputs.length-i-1] = ((Double)this.stack.pop()).floatValue(); - } - } + /************************************************************************* + * @param outputs + * @param outputOffset + ************************************************************************/ + private void prepareResult(float[] outputs, int outputOffset) { + for (int i = outputOffset; i < outputs.length; i++) { + outputs[outputs.length-i-1] = ((Double)this.stack.pop()).floatValue(); + } + } - /************************************************************************* - * Put all input values on the initial stack. - * All values are pushed as Double because we calculate internally with double. - * @param inputs - * @param inputOffset - ************************************************************************/ - - private void prepareInitialStack(float[] inputs, int inputOffset) { - this.stack = new Stack<>(); - for (int i = inputOffset; i < inputs.length; i++) { - this.stack.push(inputs[i]); - } - } + /************************************************************************* + * Put all input values on the initial stack. + * All values are pushed as Double because we calculate internally with double. + * @param inputs + * @param inputOffset + ************************************************************************/ + + private void prepareInitialStack(float[] inputs, int inputOffset) { + this.stack = new Stack<>(); + for (int i = inputOffset; i < inputs.length; i++) { + this.stack.push(inputs[i]); + } + } - /************************************************************************* - * @param outputs - * @param outputOffset - ************************************************************************/ - - private void assertResultIsCorrect(float[] outputs, int outputOffset) { - int expectedResults = outputs.length-outputOffset; - if (this.stack.size() != expectedResults) { - throw new IllegalStateException("Output does not match result "+expectedResults+"/"+this.stack); - } - } + /************************************************************************* + * @param outputs + * @param outputOffset + ************************************************************************/ + + private void assertResultIsCorrect(float[] outputs, int outputOffset) { + int expectedResults = outputs.length-outputOffset; + if (this.stack.size() != expectedResults) { + throw new IllegalStateException("Output does not match result "+expectedResults+"/"+this.stack); + } + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/PDFFunction.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/PDFFunction.java index 2814b8e1b..9285fac9f 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/PDFFunction.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/PDFFunction.java @@ -169,27 +169,27 @@ public static PDFFunction getFunction (PDFObject obj) } /** - * Perform a linear interpolation. Given a value x, and two points, - * (xmin, ymin), (xmax, ymax), where xmin <= x <= xmax, calculate a value - * y on the line from (xmin, ymin) to (xmax, ymax). - * - * @param x the x value of the input - * @param xmin the minimum x value - * @param ymin the minimum y value - * @param xmax the maximum x value - * @param ymax the maximum y value - * @return the y value interpolated from the given x - */ - public static float interpolate(float x, float xmin, float xmax, - float ymin, float ymax) { - float value = (ymax - ymin) / (xmax - xmin); - value *= x - xmin; - value += ymin; - - return value; - } - - /** + * Perform a linear interpolation. Given a value x, and two points, + * (xmin, ymin), (xmax, ymax), where xmin <= x <= xmax, calculate a value + * y on the line from (xmin, ymin) to (xmax, ymax). + * + * @param x the x value of the input + * @param xmin the minimum x value + * @param ymin the minimum y value + * @param xmax the maximum x value + * @param ymax the maximum y value + * @return the y value interpolated from the given x + */ + public static float interpolate(float x, float xmin, float xmax, + float ymin, float ymax) { + float value = (ymax - ymin) / (xmax - xmin); + value *= x - xmin; + value += ymin; + + return value; + } + + /** * Get the type of this function * * @return one of the types of function (0-4) diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/PostScriptParser.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/PostScriptParser.java index 7d0fae9b7..2627fd090 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/PostScriptParser.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/PostScriptParser.java @@ -12,58 +12,58 @@ ****************************************************************************/ public class PostScriptParser { - - /************************************************************************* - * Constructor - ************************************************************************/ - - public PostScriptParser() { - super(); - } - - /************************************************************************* - * Parses the given script and returns a list of tokens. - * @param scriptContent to parse. - * @return the list of tokens. - ************************************************************************/ - - public List parse(String scriptContent) { - List tokens = new LinkedList(); - StringTokenizer tok = new StringTokenizer(scriptContent, " \t\n\r"); - while (tok.hasMoreTokens()) { - String t = tok.nextToken(); - t = filterBlockStart(t); - t = filterBlockEnd(t); - if (t.length() > 0) { - tokens.add(t.trim()); - } - } - return tokens; - } + + /************************************************************************* + * Constructor + ************************************************************************/ + + public PostScriptParser() { + super(); + } + + /************************************************************************* + * Parses the given script and returns a list of tokens. + * @param scriptContent to parse. + * @return the list of tokens. + ************************************************************************/ + + public List parse(String scriptContent) { + List tokens = new LinkedList(); + StringTokenizer tok = new StringTokenizer(scriptContent, " \t\n\r"); + while (tok.hasMoreTokens()) { + String t = tok.nextToken(); + t = filterBlockStart(t); + t = filterBlockEnd(t); + if (t.length() > 0) { + tokens.add(t.trim()); + } + } + return tokens; + } - /************************************************************************* - * @param t - * @return - ************************************************************************/ - private String filterBlockEnd(String t) { - if (t.endsWith("}")) { - t = t.substring(0, t.length()-1); - } - return t; - } + /************************************************************************* + * @param t + * @return + ************************************************************************/ + private String filterBlockEnd(String t) { + if (t.endsWith("}")) { + t = t.substring(0, t.length()-1); + } + return t; + } - /************************************************************************* - * @param t - * @return - ************************************************************************/ - private String filterBlockStart(String t) { - if (t.startsWith("{")) { - t = t.substring(1); - } - return t; - } - - + /************************************************************************* + * @param t + * @return + ************************************************************************/ + private String filterBlockStart(String t) { + if (t.startsWith("{")) { + t = t.substring(1); + } + return t; + } + + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Abs.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Abs.java index 51ec7fbb7..22addbfa4 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Abs.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Abs.java @@ -3,17 +3,17 @@ import java.util.Stack; final class Abs implements PostScriptOperation { - @Override - /** - * num1 abs num2

    - * - * The type of the result is the same as the type of num1, - * unless num1 is the smallest (most negative) integer, - * in which case the result is a real number.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.abs((Double)environment.pop())); - } + @Override + /** + * num1 abs num2

    + * + * The type of the result is the same as the type of num1, + * unless num1 is the smallest (most negative) integer, + * in which case the result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.abs((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Add.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Add.java index f5d232311..9b028793b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Add.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Add.java @@ -3,17 +3,17 @@ import java.util.Stack; final class Add implements PostScriptOperation { - @Override - /** - * num1 num2 add sum

    - * - * If both operands are integers and the result is - * within integer range, the result is an integer; - * otherwise, the result is a real number.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - environment.push((Double)environment.pop() + (Double)environment.pop()); - } + @Override + /** + * num1 num2 add sum

    + * + * If both operands are integers and the result is + * within integer range, the result is an integer; + * otherwise, the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + environment.push((Double)environment.pop() + (Double)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/And.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/And.java index e9a0b578e..f2eaeacb4 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/And.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/And.java @@ -3,18 +3,18 @@ import java.util.Stack; final class And implements PostScriptOperation { - @Override - /** - * bool1|int1 bool2|int2 and bool3|int3

    - * - * returns the logical conjunction of the operands - * if they are boolean. If the operands are integers, - * and returns the bitwise "and" of their binary - * representations.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push((Long)environment.pop() & (Long)environment.pop()); - } + @Override + /** + * bool1|int1 bool2|int2 and bool3|int3

    + * + * returns the logical conjunction of the operands + * if they are boolean. If the operands are integers, + * and returns the bitwise "and" of their binary + * representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() & (Long)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Atan.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Atan.java index 4b3dba33c..3caacf025 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Atan.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Atan.java @@ -4,27 +4,27 @@ final class Atan implements PostScriptOperation { - @Override - /** - * num den atan angle

    - * - * returns the angle (in degress between - * 0 and 360) whose tangent is num divided by den. - * Either num or den may be 0, but not both. The signs - * of num and den determine the quadrant in which the - * result will lie: positive num yeilds a result in the - * positive y plane, while a positive den yeilds a result in - * the positive x plane. The result is a real number.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - double den = (Double)environment.pop(); - double num = (Double)environment.pop(); - if (den == 0.0) { - environment.push(90.0); - } else { - environment.push(Math.toDegrees(Math.atan(num / den))); - } - } + @Override + /** + * num den atan angle

    + * + * returns the angle (in degress between + * 0 and 360) whose tangent is num divided by den. + * Either num or den may be 0, but not both. The signs + * of num and den determine the quadrant in which the + * result will lie: positive num yeilds a result in the + * positive y plane, while a positive den yeilds a result in + * the positive x plane. The result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double den = (Double)environment.pop(); + double num = (Double)environment.pop(); + if (den == 0.0) { + environment.push(90.0); + } else { + environment.push(Math.toDegrees(Math.atan(num / den))); + } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Bitshift.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Bitshift.java index f9c826487..0da168d0c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Bitshift.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Bitshift.java @@ -3,23 +3,23 @@ import java.util.Stack; final class Bitshift implements PostScriptOperation { - @Override - /** - * int1 shift bitshift int2

    - * - * shifts the binary representation of int1 left by - * shift bits and returns the result. Bits shifted out - * are lost; bits shifted in are 0. If shift is negative, - * a right shift by –shift bits is performed. - * This PostScriptOperation produces an arithmetically correct - * result only for positive values of int1. - * Both int1 and shift must be integers.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - long shift = (Long)environment.pop(); - long int1 = (Long)environment.pop(); - environment.push(int1 << shift); - } + @Override + /** + * int1 shift bitshift int2

    + * + * shifts the binary representation of int1 left by + * shift bits and returns the result. Bits shifted out + * are lost; bits shifted in are 0. If shift is negative, + * a right shift by –shift bits is performed. + * This PostScriptOperation produces an arithmetically correct + * result only for positive values of int1. + * Both int1 and shift must be integers.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + long shift = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 << shift); + } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ceiling.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ceiling.java index 1520bdf68..12afdbc7e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ceiling.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ceiling.java @@ -3,17 +3,17 @@ import java.util.Stack; final class Ceiling implements PostScriptOperation { - @Override - /** - * num1 ceiling num2

    - * - * returns the least integer value greater than or equal - * to num1. The type of the result is the same as the type - * of the operand.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.ceil((Double)environment.pop())); - } + @Override + /** + * num1 ceiling num2

    + * + * returns the least integer value greater than or equal + * to num1. The type of the result is the same as the type + * of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.ceil((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Copy.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Copy.java index 5f6c03710..bc208d8ce 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Copy.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Copy.java @@ -1,64 +1,64 @@ package org.openpdf.renderer.function.postscript.operation; import java.util.Stack; - final class Copy implements PostScriptOperation { - @Override - /** - * any1 ... anyn n copy any1 ... anyn any1 ... anyn - * array1 array2 copy subarray2
    - * string1 string2 copy substring2

    - * - * performs two entirely different functions, depending on the - * type of the topmost operand. - * In the first form, where the top element on the operand - * stack is a nonnegative integer n, copy pops n from the - * stack and duplicates the top n elements on the stack - * as shown above. This form of copy operates only on the - * objects themselves, not on the values of composite objects.

    - * - * Examples
    - * (a) (b) (c) 2 copy Þ (a) (b) (c) (b) (c)
    - * (a) (b) (c) 0 copy Þ (a) (b) (c)

    - * - * In the other forms, copy copies all the elements of the - * first composite object into the second. The composite - * object operands must be of the same type, except that - * a packed array can be copied into an array (and only into - * an array—copy cannot copy into packed arrays, because - * they are read-only). This form of copy copies the value of - * a composite object. This is quite different from dup and - * other operators that copy only the objects themselves - * (see Section 3.3.1, "Simple and Composite Objects"). - * However, copy performs only one level of copying. - * It does not apply recursively to elements that are - * themselves composite objects; instead, the values - * of those elements become shared. In the case of arrays or - * strings, the length of the second object must be at least as - * great as the first; copy returns the initial subarray or - * substring of the second operand into which the elements - * were copied. Any remaining elements of array2 or - * string2 are unaffected.

    - * - * Example:
    - * /a1 [1 2 3] def
    - * a1 dup length array copy Þ [1 2 3]

    - * - * errors: invalidaccess, rangecheck, stackoverflow, - * stackunderflow, typecheck - */ - public void eval(Stack environment) { - Number count = (Number) environment.pop(); + final class Copy implements PostScriptOperation { + @Override + /** + * any1 ... anyn n copy any1 ... anyn any1 ... anyn + * array1 array2 copy subarray2
    + * string1 string2 copy substring2

    + * + * performs two entirely different functions, depending on the + * type of the topmost operand. + * In the first form, where the top element on the operand + * stack is a nonnegative integer n, copy pops n from the + * stack and duplicates the top n elements on the stack + * as shown above. This form of copy operates only on the + * objects themselves, not on the values of composite objects.

    + * + * Examples
    + * (a) (b) (c) 2 copy Þ (a) (b) (c) (b) (c)
    + * (a) (b) (c) 0 copy Þ (a) (b) (c)

    + * + * In the other forms, copy copies all the elements of the + * first composite object into the second. The composite + * object operands must be of the same type, except that + * a packed array can be copied into an array (and only into + * an array—copy cannot copy into packed arrays, because + * they are read-only). This form of copy copies the value of + * a composite object. This is quite different from dup and + * other operators that copy only the objects themselves + * (see Section 3.3.1, "Simple and Composite Objects"). + * However, copy performs only one level of copying. + * It does not apply recursively to elements that are + * themselves composite objects; instead, the values + * of those elements become shared. In the case of arrays or + * strings, the length of the second object must be at least as + * great as the first; copy returns the initial subarray or + * substring of the second operand into which the elements + * were copied. Any remaining elements of array2 or + * string2 are unaffected.

    + * + * Example:
    + * /a1 [1 2 3] def
    + * a1 dup length array copy Þ [1 2 3]

    + * + * errors: invalidaccess, rangecheck, stackoverflow, + * stackunderflow, typecheck + */ + public void eval(Stack environment) { + Number count = (Number) environment.pop(); // ???? - Object[] buffer = new Object[count.intValue()]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = environment.pop(); - } - for (int i = 0; i < buffer.length; i++) { - environment.push(buffer[buffer.length-i-1]); - } - for (int i = 0; i < buffer.length; i++) { - environment.push(buffer[buffer.length-i-1]); - } - } - } - \ No newline at end of file + Object[] buffer = new Object[count.intValue()]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = environment.pop(); + } + for (int i = 0; i < buffer.length; i++) { + environment.push(buffer[buffer.length-i-1]); + } + for (int i = 0; i < buffer.length; i++) { + environment.push(buffer[buffer.length-i-1]); + } + } + } + \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvi.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvi.java index 805b8bf4f..01b24072b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvi.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvi.java @@ -2,27 +2,27 @@ import java.util.Stack; final class Cvi implements PostScriptOperation { - @Override - /** - * num cvi int or string cvi int

    - * - * takes an integer, real, or string and produces an - * integer result. If the operand is an integer, cvi - * simply returns it. If the operand is a real number, - * it truncates any fractional part (that is, rounds - * it toward 0) and converts it to an integer. - * If the operand is a string, cvi invokes the equivalent - * of the token operator to interpret the characters - * of the string as a number according to the PostScript - * syntax rules. If that number is a real number, cvi converts - * it to an integer. - * A rangecheck error occurs if a real number is too - * large to convert to an integer.

    - * - * errors: invalidaccess, rangecheck, stackunderflow, - * syntaxError, typecheck, - */ - public void eval(Stack environment) { - environment.push(environment.pop()); - } + @Override + /** + * num cvi int or string cvi int

    + * + * takes an integer, real, or string and produces an + * integer result. If the operand is an integer, cvi + * simply returns it. If the operand is a real number, + * it truncates any fractional part (that is, rounds + * it toward 0) and converts it to an integer. + * If the operand is a string, cvi invokes the equivalent + * of the token operator to interpret the characters + * of the string as a number according to the PostScript + * syntax rules. If that number is a real number, cvi converts + * it to an integer. + * A rangecheck error occurs if a real number is too + * large to convert to an integer.

    + * + * errors: invalidaccess, rangecheck, stackunderflow, + * syntaxError, typecheck, + */ + public void eval(Stack environment) { + environment.push(environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvr.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvr.java index ff27f728e..d5fbbba64 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvr.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Cvr.java @@ -3,24 +3,24 @@ import java.util.Stack; final class Cvr implements PostScriptOperation { - @Override - /** - * num cvr real or string cvr real

    - * - * (convert to real) takes an integer, real, or string - * object and produces a real result. If the operand - * is an integer, cvr converts it to a real number. - * If the operand is a real number, cvr simply returns it. - * If the operand is a string, cvr invokes the equivalent - * of the token operator to interpret the characters of - * the string as a number according to the PostScript - * syntax rules. If that number is an integer, cvr converts - * it to a real number.

    - * - * errors: invalidaccess, limitcheck, stackunderflow, - * syntaxerror, typecheck, undefinedresult - */ - public void eval(Stack environment) { - // YOUR CODE IN THIS SPACE - } + @Override + /** + * num cvr real or string cvr real

    + * + * (convert to real) takes an integer, real, or string + * object and produces a real result. If the operand + * is an integer, cvr converts it to a real number. + * If the operand is a real number, cvr simply returns it. + * If the operand is a string, cvr invokes the equivalent + * of the token operator to interpret the characters of + * the string as a number according to the PostScript + * syntax rules. If that number is an integer, cvr converts + * it to a real number.

    + * + * errors: invalidaccess, limitcheck, stackunderflow, + * syntaxerror, typecheck, undefinedresult + */ + public void eval(Stack environment) { + // YOUR CODE IN THIS SPACE + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Div.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Div.java index 898f34bed..99ea394f2 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Div.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Div.java @@ -3,20 +3,20 @@ import java.util.Stack; final class Div implements PostScriptOperation { - @Override - /** - * num1 num2 div quotient

    - * - * divides num1 by num2, producing a result that is - * always a real number even if both operands are integers. - * Use idiv instead if the operands are integers and an - * integer result is desired.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 / num2); - } + @Override + /** + * num1 num2 div quotient

    + * + * divides num1 by num2, producing a result that is + * always a real number even if both operands are integers. + * Use idiv instead if the operands are integers and an + * integer result is desired.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 / num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Dup.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Dup.java index f1b3b038e..fcbdab2c8 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Dup.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Dup.java @@ -3,20 +3,20 @@ import java.util.Stack; final class Dup implements PostScriptOperation { - @Override - /** - * any dup any any

    - * - * duplicates the top element on the operand stack. - * dup copies only the object; the value of a composite - * object is not copied but is shared. - * See Section 3.3, "Data Types and Objects."

    - * - * errors: stackoverflow, stackunderflow - */ - public void eval(Stack environment) { - Object obj = environment.pop(); - environment.push(obj); - environment.push(obj); - } + @Override + /** + * any dup any any

    + * + * duplicates the top element on the operand stack. + * dup copies only the object; the value of a composite + * object is not copied but is shared. + * See Section 3.3, "Data Types and Objects."

    + * + * errors: stackoverflow, stackunderflow + */ + public void eval(Stack environment) { + Object obj = environment.pop(); + environment.push(obj); + environment.push(obj); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Eq.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Eq.java index 4c19e05d5..7d2a44913 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Eq.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Eq.java @@ -4,36 +4,36 @@ final class Eq implements PostScriptOperation { - @Override - /** - * any1 any2 eq bool

    - * - * pops two objects from the operand stack and pushes\ - * true if they are equal, or false if not. - * The definition of equality depends on the types of - * the objects being compared. - * Simple objects are equal if their types and values - * are the same. Strings are equal if their lengths and - * individual elements are equal. - * Other composite objects - * (arrays and dictionaries) are equal only if they share - * the same value. Separate values are considered unequal, - * even if all the components of those values are the - * same. - * This operator performs some type conversions. - * Integers and real numbers can be compared freely: - * an integer and a real number representing the same - * mathematical value are considered equal by eq. - * Strings and names can likewise be compared freely: - * a name defined by some sequence of characters is equal - * to a string whose elements are the same sequence of - * characters. - * The literal/executable and access attributes of - * objects are not considered in comparisons - * between objects.

    - * - * errors: invalidaccess, stackunderflow - */ + @Override + /** + * any1 any2 eq bool

    + * + * pops two objects from the operand stack and pushes\ + * true if they are equal, or false if not. + * The definition of equality depends on the types of + * the objects being compared. + * Simple objects are equal if their types and values + * are the same. Strings are equal if their lengths and + * individual elements are equal. + * Other composite objects + * (arrays and dictionaries) are equal only if they share + * the same value. Separate values are considered unequal, + * even if all the components of those values are the + * same. + * This operator performs some type conversions. + * Integers and real numbers can be compared freely: + * an integer and a real number representing the same + * mathematical value are considered equal by eq. + * Strings and names can likewise be compared freely: + * a name defined by some sequence of characters is equal + * to a string whose elements are the same sequence of + * characters. + * The literal/executable and access attributes of + * objects are not considered in comparisons + * between objects.

    + * + * errors: invalidaccess, stackunderflow + */ public void eval(Stack environment) { Object b = environment.pop(); Object a = environment.pop(); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exch.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exch.java index f4dfcd1ae..0a2921d00 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exch.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exch.java @@ -3,11 +3,11 @@ import java.util.Stack; final class Exch implements PostScriptOperation { - @Override - public void eval(Stack environment) { // any1 any2 exch any2 any1 - exchange top of stack - Object any1 = environment.pop(); - Object any2 = environment.pop(); - environment.push(any1); - environment.push(any2); - } + @Override + public void eval(Stack environment) { // any1 any2 exch any2 any1 - exchange top of stack + Object any1 = environment.pop(); + Object any2 = environment.pop(); + environment.push(any1); + environment.push(any2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exp.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exp.java index 2a8908b12..5a4343d4b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exp.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Exp.java @@ -3,21 +3,21 @@ import java.util.Stack; final class Exp implements PostScriptOperation { - @Override - /** - * base exponent exp real

    - * - * raises base to the exponent power. The operands may be - * either integers or real numbers. If the exponent has a - * fractional part, the result is meaningful only if the - * base is nonnegative. The result is always a real number.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - double exponent = (Double)environment.pop(); - double base = (Double)environment.pop(); - environment.push(Math.pow(exponent, base)); - } - + @Override + /** + * base exponent exp real

    + * + * raises base to the exponent power. The operands may be + * either integers or real numbers. If the exponent has a + * fractional part, the result is meaningful only if the + * base is nonnegative. The result is always a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double exponent = (Double)environment.pop(); + double base = (Double)environment.pop(); + environment.push(Math.pow(exponent, base)); + } + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Expression.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Expression.java index c886bd8df..13568d9af 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Expression.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Expression.java @@ -7,7 +7,7 @@ public class Expression extends LinkedList { @Override - public boolean equals(Object obj) { + public boolean equals(Object obj) { if (obj instanceof Expression) { // actually validate the list contents are the same expressions return true; diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/False.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/False.java index 723615abb..b646d9fdc 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/False.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/False.java @@ -4,17 +4,17 @@ final class False implements PostScriptOperation { - @Override - /** - * false false

    - * - * pushes a boolean object whose value is false on the - * operand stack. false is not an operator; it is a name in - * systemdict associated with the boolean value false.

    - * - * errors: stackoverflow - */ - public void eval(Stack environment) { - environment.push(false); - } + @Override + /** + * false false

    + * + * pushes a boolean object whose value is false on the + * operand stack. false is not an operator; it is a name in + * systemdict associated with the boolean value false.

    + * + * errors: stackoverflow + */ + public void eval(Stack environment) { + environment.push(false); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Floor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Floor.java index db9175c8d..9495d0aae 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Floor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Floor.java @@ -3,17 +3,17 @@ import java.util.Stack; final class Floor implements PostScriptOperation { - @Override - /** - * num1 floor num2

    - * - * returns the greatest integer value less than or equal - * to num1. The type of the result is the same as the type - * of the operand.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.floor((Double)environment.pop())); - } + @Override + /** + * num1 floor num2

    + * + * returns the greatest integer value less than or equal + * to num1. The type of the result is the same as the type + * of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.floor((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ge.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ge.java index 5548095c8..a08dc57cb 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ge.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ge.java @@ -4,27 +4,27 @@ final class Ge implements PostScriptOperation { - @Override - /** - * num1 num2 ge bool

    - * - * pops two objects from the operand stack and pushes true - * if the first operand is greater than or equal to the second, - * or false otherwise. If both operands are numbers, - * ge compares their mathematical values. If both operands - * are strings, ge compares them element by element, treating - * the elements as integers in the range 0 to 255, to determine - * whether the first string is lexically greater than or equal - * to the second. If the operands are of other types or one - * is a string and the other is a number, a typecheck - * error occurs.

    - * - * errors: invalidaccess, stackunderflow, typecheck - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 >= num2); - } + @Override + /** + * num1 num2 ge bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is greater than or equal to the second, + * or false otherwise. If both operands are numbers, + * ge compares their mathematical values. If both operands + * are strings, ge compares them element by element, treating + * the elements as integers in the range 0 to 255, to determine + * whether the first string is lexically greater than or equal + * to the second. If the operands are of other types or one + * is a string and the other is a number, a typecheck + * error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 >= num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Gt.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Gt.java index 260c2519c..c662a3c59 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Gt.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Gt.java @@ -4,25 +4,25 @@ final class Gt implements PostScriptOperation { - @Override - /** - * num1 num2 gt bool

    - * - * pops two objects from the operand stack and pushes true - * if the first operand is greater than the second, or - * false otherwise. If both operands are numbers, gt compares - * their mathematical values. If both operands are strings, - * gt compares them element by element, treating the elements - * as integers in the range 0 to 255, to determine whether - * the first string is lexically greater than the second. - * If the operands are of other types or one is a string - * and the other is a number, a typecheck error occurs.

    - * - * errors: invalidaccess, stackunderflow, typecheck - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 > num2); - } + @Override + /** + * num1 num2 gt bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is greater than the second, or + * false otherwise. If both operands are numbers, gt compares + * their mathematical values. If both operands are strings, + * gt compares them element by element, treating the elements + * as integers in the range 0 to 255, to determine whether + * the first string is lexically greater than the second. + * If the operands are of other types or one is a string + * and the other is a number, a typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 > num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Idiv.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Idiv.java index 916272438..5ecf3c697 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Idiv.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Idiv.java @@ -3,20 +3,20 @@ import java.util.Stack; final class Idiv implements PostScriptOperation { - @Override - /** - * int1 int2 idiv quotient

    - * - * divides int1 by int2 and returns the integer part - * of the quotient, with any fractional part discarded. - * Both operands of idiv must be integers and the result - * is an integer.

    - * - * stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - long int2 = (Long)environment.pop(); - long int1 = (Long)environment.pop(); - environment.push(int1 / int2); - } + @Override + /** + * int1 int2 idiv quotient

    + * + * divides int1 by int2 and returns the integer part + * of the quotient, with any fractional part discarded. + * Both operands of idiv must be integers and the result + * is an integer.

    + * + * stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + long int2 = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 / int2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/If.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/If.java index 9a8673e38..72a84220b 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/If.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/If.java @@ -4,25 +4,25 @@ final class If implements PostScriptOperation { - @Override - /** - * bool {proc} if -

    - * - * removes both operands from the stack, then executes proc - * if bool is true. The if operator pushes no results of - * its own on the operand stack, but proc may do so (see - * Section 3.5, "Execution").

    - * - * Examples

    - * 3 4 lt {(3 is less than 4)} if

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - if ((Boolean)environment.pop()) { - environment.push(environment.pop()); - } else { - environment.pop(); - } - } + @Override + /** + * bool {proc} if -

    + * + * removes both operands from the stack, then executes proc + * if bool is true. The if operator pushes no results of + * its own on the operand stack, but proc may do so (see + * Section 3.5, "Execution").

    + * + * Examples

    + * 3 4 lt {(3 is less than 4)} if

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + if ((Boolean)environment.pop()) { + environment.push(environment.pop()); + } else { + environment.pop(); + } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/IfElse.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/IfElse.java index 0824d8744..ebd3135cc 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/IfElse.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/IfElse.java @@ -3,22 +3,22 @@ import java.util.Stack; final class IfElse implements PostScriptOperation { - @Override - /** - * bool {expr1} {expr2} ifelse -

    - * - * removes all three operands from the stack, then - * executes proc1 if bool is true or proc2 if bool is false. - * The ifelse operator pushes no results of its own on the - * operand stack, but the procedure it executes may do so - * (see Section 3.5, "Execution").

    - * - * Examples

    - * 4 3 lt {(TruePart)} {(FalsePart)} ifelse
    - * results in FalsePart, since 4 is not less than 3

    - * - * errors: stackunderflow, typecheck - */ + @Override + /** + * bool {expr1} {expr2} ifelse -

    + * + * removes all three operands from the stack, then + * executes proc1 if bool is true or proc2 if bool is false. + * The ifelse operator pushes no results of its own on the + * operand stack, but the procedure it executes may do so + * (see Section 3.5, "Execution").

    + * + * Examples

    + * 4 3 lt {(TruePart)} {(FalsePart)} ifelse
    + * results in FalsePart, since 4 is not less than 3

    + * + * errors: stackunderflow, typecheck + */ public void eval(Stack environment) { // Pop boolean condition, discard it environment.pop(); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Index.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Index.java index 66d5e8dad..a8fcf5d5d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Index.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Index.java @@ -3,9 +3,9 @@ import java.util.Stack; final class Index implements PostScriptOperation { - @Override - public void eval(Stack environment) { // anyn ... any0 n index anyn ... any0 anyn - long n = Math.round((Double)environment.pop()); - environment.push(environment.get((int)(environment.size() - n - 1))); - } + @Override + public void eval(Stack environment) { // anyn ... any0 n index anyn ... any0 anyn + long n = Math.round((Double)environment.pop()); + environment.push(environment.get((int)(environment.size() - n - 1))); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Le.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Le.java index c47270d1b..329e5ba9e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Le.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Le.java @@ -3,27 +3,27 @@ import java.util.Stack; final class Le implements PostScriptOperation { - @Override - /** - * num1 num2 le bool

    - * - * pops two objects from the operand stack and pushes true - * if the first operand is less than or equal to the second, - * or false otherwise. If both operands are numbers, le - * compares their mathematical values. If both operands are - * strings, le compares them element by element, treating - * the elements as integers in the range 0 to 255, - * to determine whether the first string is lexically less - * than or equal to the second. If the operands are of other - * types or one is a string and the other is a number, a - * typecheck error occurs.

    - * - * errors: invalidaccess, stackunderflow, typecheck - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 <= num2); - } + @Override + /** + * num1 num2 le bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is less than or equal to the second, + * or false otherwise. If both operands are numbers, le + * compares their mathematical values. If both operands are + * strings, le compares them element by element, treating + * the elements as integers in the range 0 to 255, + * to determine whether the first string is lexically less + * than or equal to the second. If the operands are of other + * types or one is a string and the other is a number, a + * typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 <= num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ln.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ln.java index dc3a9b35c..433b86122 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ln.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ln.java @@ -4,16 +4,16 @@ final class Ln implements PostScriptOperation { - @Override - /** - * num ln real

    - * - * returns the natural logarithm (base e) of num. - * The result is a real number.

    - * - * errors: rangecheck, stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.log((Double)environment.pop())); - } + @Override + /** + * num ln real

    + * + * returns the natural logarithm (base e) of num. + * The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.log((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Log.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Log.java index d79cc41d0..6e431829d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Log.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Log.java @@ -4,16 +4,16 @@ final class Log implements PostScriptOperation { - @Override - /** - * num log real

    - * - * returns the common logarithm (base 10) of num. - * The result is a real number.

    - * - * errors: rangecheck, stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.log10((Double)environment.pop())); - } + @Override + /** + * num log real

    + * + * returns the common logarithm (base 10) of num. + * The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.log10((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Lt.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Lt.java index 8c1b02dcb..912d5d93d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Lt.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Lt.java @@ -3,25 +3,25 @@ import java.util.Stack; final class Lt implements PostScriptOperation { - @Override - /** - * num1 num2 lt bool

    - * - * pops two objects from the operand stack and pushes true - * if the first operand is less than the second, or false - * otherwise. If both operands are numbers, lt compares - * their mathematical values. If both operands are strings, - * lt compares them element by element, treating the elements - * as integers in the range 0 to 255, to determine whether - * the first string is lexically less than the second. - * If the operands are of other types or one is a string - * and the other is a number, a typecheck error occurs.

    - * - * errors: invalidaccess, stackunderflow, typecheck - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 < num2); - } + @Override + /** + * num1 num2 lt bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is less than the second, or false + * otherwise. If both operands are numbers, lt compares + * their mathematical values. If both operands are strings, + * lt compares them element by element, treating the elements + * as integers in the range 0 to 255, to determine whether + * the first string is lexically less than the second. + * If the operands are of other types or one is a string + * and the other is a number, a typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 < num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mod.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mod.java index 80b0389bb..ab5cae7bb 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mod.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mod.java @@ -4,21 +4,21 @@ final class Mod implements PostScriptOperation { - @Override - /** - * int1 int2 mod remainder

    - * - * returns the remainder that results from - * dividing int1 by int2. The sign of the result - * is the same as the sign of the dividend int1. - * Both operands must be integers and the result - * is an integer.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - long int2 = (Long)environment.pop(); - long int1 = (Long)environment.pop(); - environment.push(int1 % int2); - } + @Override + /** + * int1 int2 mod remainder

    + * + * returns the remainder that results from + * dividing int1 by int2. The sign of the result + * is the same as the sign of the dividend int1. + * Both operands must be integers and the result + * is an integer.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + long int2 = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 % int2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mul.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mul.java index d9355bedc..1dabe66f3 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mul.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Mul.java @@ -4,18 +4,18 @@ final class Mul implements PostScriptOperation { - @Override - /** - * num1 num2 mul product

    - * - * returns the product of num1 and num2. - * If both operands are integers and the result - * is within integer range, the result is an integer; - * otherwise, the result is a real number.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - environment.push((Double)environment.pop() * (Double)environment.pop()); - } + @Override + /** + * num1 num2 mul product

    + * + * returns the product of num1 and num2. + * If both operands are integers and the result + * is within integer range, the result is an integer; + * otherwise, the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + environment.push((Double)environment.pop() * (Double)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ne.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ne.java index add00d4e4..500d10276 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ne.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Ne.java @@ -4,17 +4,17 @@ final class Ne implements PostScriptOperation { - @Override - /** - * any1 any2 ne bool

    - * - * pops two objects from the operand stack and pushes false - * if they are equal, or true if not. What it means for objects - * to be equal is presented in the description of the - * eq operator.

    - * - * errors: invalidaccess, stackunderflow - */ + @Override + /** + * any1 any2 ne bool

    + * + * pops two objects from the operand stack and pushes false + * if they are equal, or true if not. What it means for objects + * to be equal is presented in the description of the + * eq operator.

    + * + * errors: invalidaccess, stackunderflow + */ public void eval(Stack environment) { Object b = environment.pop(); Object a = environment.pop(); diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Neg.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Neg.java index cfefa20ae..05c36aac6 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Neg.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Neg.java @@ -4,18 +4,18 @@ final class Neg implements PostScriptOperation { - @Override - /** - * num1 neg num2

    - * - * returns the negative of num1. The type of the result - * is the same as the type of num1 unless num1 is the - * smallest (most negative) integer, in which case the - * result is a real number.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(-(Double)environment.pop()); - } + @Override + /** + * num1 neg num2

    + * + * returns the negative of num1. The type of the result + * is the same as the type of num1 unless num1 is the + * smallest (most negative) integer, in which case the + * result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(-(Double)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Not.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Not.java index 18f09185e..0efc0d1d9 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Not.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Not.java @@ -4,18 +4,18 @@ final class Not implements PostScriptOperation { - @Override - /** - * bool1|int1 not bool2|int2

    - * - * returns the logical negation of the operand if it is - * boolean. If the operand is an integer, not returns the - * bitwise complement (ones complement) of its binary - * representation.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(~(Long)environment.pop()); - } + @Override + /** + * bool1|int1 not bool2|int2

    + * + * returns the logical negation of the operand if it is + * boolean. If the operand is an integer, not returns the + * bitwise complement (ones complement) of its binary + * representation.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(~(Long)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/OperationSet.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/OperationSet.java index b04e6bb4b..5764086cc 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/OperationSet.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/OperationSet.java @@ -4,7 +4,7 @@ import java.util.Map; public class OperationSet { - + /** the set of all Operations we support. These operations are defined * in Appendix B - Operators.*/ private Map operationSet = null; @@ -16,8 +16,8 @@ public class OperationSet { ************************************************************************/ private OperationSet() { - super(); - initOperations(); + super(); + initOperations(); } /************************************************************************* @@ -25,10 +25,10 @@ private OperationSet() { ************************************************************************/ public static synchronized OperationSet getInstance() { - if (instance == null) { - instance = new OperationSet(); - } - return instance; + if (instance == null) { + instance = new OperationSet(); + } + return instance; } /************************************************************************* @@ -37,12 +37,12 @@ public static synchronized OperationSet getInstance() { ************************************************************************/ public PostScriptOperation getOperation(String token) { - PostScriptOperation result = this.operationSet.get(token.trim().toLowerCase()); - if (result == null) { - result = new PushAsNumber(token); - } - return result; - + PostScriptOperation result = this.operationSet.get(token.trim().toLowerCase()); + if (result == null) { + result = new PushAsNumber(token); + } + return result; + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Or.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Or.java index 94c81ae84..3972e6161 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Or.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Or.java @@ -4,17 +4,17 @@ final class Or implements PostScriptOperation { - @Override - /** - * bool1|int1 bool2|int2 or bool3|int3

    - * - * returns the logical disjunction of the operands if they - * are boolean. If the operands are integers, or returns - * the bitwise "inclusive or" of their binary representations.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push((Long)environment.pop() | (Long)environment.pop()); - } + @Override + /** + * bool1|int1 bool2|int2 or bool3|int3

    + * + * returns the logical disjunction of the operands if they + * are boolean. If the operands are integers, or returns + * the bitwise "inclusive or" of their binary representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() | (Long)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Pop.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Pop.java index 2c074cd73..2fa956e25 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Pop.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Pop.java @@ -4,9 +4,9 @@ final class Pop implements PostScriptOperation { - @Override - public void eval(Stack environment) { // discard top element - environment.pop(); - } + @Override + public void eval(Stack environment) { // discard top element + environment.pop(); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/PushAsNumber.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/PushAsNumber.java index 94242fe9e..684bccdc8 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/PushAsNumber.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/PushAsNumber.java @@ -6,30 +6,30 @@ final class PushAsNumber implements PostScriptOperation { - private String token; - - /************************************************************************* - * Constructor - * @param numberToken - ************************************************************************/ - - public PushAsNumber(String numberToken) { - super(); - this.token = numberToken; - } - - /************************************************************************* - * eval - * @see PostScriptOperation#eval(java.util.Stack) - ************************************************************************/ - @Override - public void eval(Stack environment) { - try { - double number = Double.parseDouble(this.token); - environment.push(number); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("PS token is not supported "+this.token); - } } + private String token; + + /************************************************************************* + * Constructor + * @param numberToken + ************************************************************************/ + + public PushAsNumber(String numberToken) { + super(); + this.token = numberToken; + } + + /************************************************************************* + * eval + * @see PostScriptOperation#eval(java.util.Stack) + ************************************************************************/ + @Override + public void eval(Stack environment) { + try { + double number = Double.parseDouble(this.token); + environment.push(number); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("PS token is not supported "+this.token); + } } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Roll.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Roll.java index ecb001aae..223724f40 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Roll.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Roll.java @@ -3,48 +3,48 @@ import java.util.Stack; final class Roll implements PostScriptOperation { - - public static int popAsInteger(Stack st) { - Object e = st.pop(); - if (e instanceof Double) { - double doubleVal = (Double) e; - return (int) doubleVal; - } else { - // error - return 0; - } - } + + public static int popAsInteger(Stack st) { + Object e = st.pop(); + if (e instanceof Double) { + double doubleVal = (Double) e; + return (int) doubleVal; + } else { + // error + return 0; + } + } - @Override - public void eval(Stack environment) { - // anyn-1 ... any0 n j roll any(j-1)mod n ... anyn-1 ... any - // Roll n elements up j times - int j = popAsInteger(environment); - int n = popAsInteger(environment); - Object[] temp = new Object[n]; - - if (environment.size() < n) { - // error, cause by non-standard PS cmd, do nothing for compatibility - return; - } - - if (j >= 0) { - j %= n; - } else { - j = -j % n; - if (j != 0) - j = n - j; - } - for (int i = 0; i < n; ++i) { - temp[i] = environment.pop(); - } + @Override + public void eval(Stack environment) { + // anyn-1 ... any0 n j roll any(j-1)mod n ... anyn-1 ... any + // Roll n elements up j times + int j = popAsInteger(environment); + int n = popAsInteger(environment); + Object[] temp = new Object[n]; + + if (environment.size() < n) { + // error, cause by non-standard PS cmd, do nothing for compatibility + return; + } + + if (j >= 0) { + j %= n; + } else { + j = -j % n; + if (j != 0) + j = n - j; + } + for (int i = 0; i < n; ++i) { + temp[i] = environment.pop(); + } - for (int i = j - 1; i > -1; --i) { - environment.push(temp[i]); - } - for (int i = n - 1; i > j - 1; --i) { - environment.push(temp[i]); - } - } + for (int i = j - 1; i > -1; --i) { + environment.push(temp[i]); + } + for (int i = n - 1; i > j - 1; --i) { + environment.push(temp[i]); + } + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Round.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Round.java index 732791c9a..e07d81c6e 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Round.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Round.java @@ -3,19 +3,19 @@ import java.util.Stack; final class Round implements PostScriptOperation { - @Override - /** - * num1 round num2

    - * - * returns the integer value nearest to num1. - * If num1 is equally close to its two nearest - * integers, round returns the greater of the two. - * The type of the result is the same as - * the type of the operand.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.round((Double)environment.pop())); - } + @Override + /** + * num1 round num2

    + * + * returns the integer value nearest to num1. + * If num1 is equally close to its two nearest + * integers, round returns the greater of the two. + * The type of the result is the same as + * the type of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.round((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sin.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sin.java index 69b0205f5..0dcf3dcdc 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sin.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sin.java @@ -4,17 +4,17 @@ final class Sin implements PostScriptOperation { - @Override - /** - * angle sin real

    - * - * returns the sine of angle, which is interpreted as an - * angle in degrees. The result is a real number.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - double radians = Math.toRadians((Double)environment.pop()); - environment.push(Math.toDegrees(Math.sin(radians))); - } + @Override + /** + * angle sin real

    + * + * returns the sine of angle, which is interpreted as an + * angle in degrees. The result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + double radians = Math.toRadians((Double)environment.pop()); + environment.push(Math.toDegrees(Math.sin(radians))); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sqrt.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sqrt.java index 9fbb495d0..90733bc46 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sqrt.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sqrt.java @@ -4,16 +4,16 @@ final class Sqrt implements PostScriptOperation { - @Override - /** - * num sqrt real

    - * - * returns the square root of num, which must be a - * nonnegative number. The result is a real number.

    - * - * errors: rangecheck, stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push(Math.sqrt((Double)environment.pop())); - } + @Override + /** + * num sqrt real

    + * + * returns the square root of num, which must be a + * nonnegative number. The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.sqrt((Double)environment.pop())); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sub.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sub.java index d1d427c85..9621deff2 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sub.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Sub.java @@ -4,20 +4,20 @@ final class Sub implements PostScriptOperation { - @Override - /** - * num1 num2 sub difference

    - * - * returns the result of subtracting num2 from num1. - * If both operands are integers and the result is within - * integer range, the result is an integer; otherwise, - * the result is a real number.

    - * - * errors: stackunderflow, typecheck, undefinedresult - */ - public void eval(Stack environment) { - double num2 = (Double)environment.pop(); - double num1 = (Double)environment.pop(); - environment.push(num1 - num2); - } + @Override + /** + * num1 num2 sub difference

    + * + * returns the result of subtracting num2 from num1. + * If both operands are integers and the result is within + * integer range, the result is an integer; otherwise, + * the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 - num2); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/True.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/True.java index e6f3a5875..0faa1c200 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/True.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/True.java @@ -4,17 +4,17 @@ final class True implements PostScriptOperation { - @Override - /** - * true true

    - * - * pushes a boolean object whose value is true on the operand - * stack. true is not an operator; it is a name in systemdict - * associated with the boolean value true.

    - * - * errors: stackoverflow - */ - public void eval(Stack environment) { - environment.push(true); - } + @Override + /** + * true true

    + * + * pushes a boolean object whose value is true on the operand + * stack. true is not an operator; it is a name in systemdict + * associated with the boolean value true.

    + * + * errors: stackoverflow + */ + public void eval(Stack environment) { + environment.push(true); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Truncate.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Truncate.java index 250fbccca..ac6f322ce 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Truncate.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Truncate.java @@ -4,18 +4,18 @@ final class Truncate implements PostScriptOperation { - @Override - /** - * num1 truncate num2

    - * - * truncates num1 toward 0 by removing its fractional part. - * The type of the result is the same as the type of the - * operand.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - double num1 = (Double)environment.pop(); - environment.push((((long) num1) - num1)); - } + @Override + /** + * num1 truncate num2

    + * + * truncates num1 toward 0 by removing its fractional part. + * The type of the result is the same as the type of the + * operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num1 = (Double)environment.pop(); + environment.push((((long) num1) - num1)); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Xor.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Xor.java index 6087d3caf..ab2c52770 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Xor.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/function/postscript/operation/Xor.java @@ -3,17 +3,17 @@ import java.util.Stack; final class Xor implements PostScriptOperation { - @Override - /** - * bool1|int1 bool2|int2 xor bool3|int3

    - * - * returns the logical "exclusive or" of the operands if they - * are boolean. If the operands are integers, xor returns the - * bitwise "exclusive or" of their binary representations.

    - * - * errors: stackunderflow, typecheck - */ - public void eval(Stack environment) { - environment.push((Long)environment.pop() ^ (Long)environment.pop()); - } + @Override + /** + * bool1|int1 bool2|int2 xor bool3|int3

    + * + * returns the logical "exclusive or" of the operands if they + * are boolean. If the operands are integers, xor returns the + * bitwise "exclusive or" of their binary representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() ^ (Long)environment.pop()); + } } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/DummyShader.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/DummyShader.java index de3704198..c6a279132 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/DummyShader.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/DummyShader.java @@ -8,18 +8,18 @@ public class DummyShader extends PDFShader { - protected DummyShader(int type) { - super(type); - } + protected DummyShader(int type) { + super(type); + } - @Override - public void parse(PDFObject shareObj) throws IOException { - - } + @Override + public void parse(PDFObject shareObj) throws IOException { + + } - @Override - public PDFPaint getPaint() { - return PDFPaint.getPaint(Color.PINK); - } - + @Override + public PDFPaint getPaint() { + return PDFPaint.getPaint(Color.PINK); + } + } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFPattern.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFPattern.java index f9ae66efb..588011a7d 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFPattern.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFPattern.java @@ -69,7 +69,7 @@ public static PDFPattern getPattern(PDFObject patternObj, Map resources) } else { float elts[]= new float[6]; for (int i = 0; i < elts.length; i++) { - elts[i] = matrix.getAt(i).getFloatValue(); + elts[i] = matrix.getAt(i).getFloatValue(); } xform = new AffineTransform(elts); @@ -80,8 +80,8 @@ public static PDFPattern getPattern(PDFObject patternObj, Map resources) pattern = new PatternType1(); break; case 2: - pattern = new PatternType2(); - break; + pattern = new PatternType2(); + break; default: throw new PDFParseException("Unknown pattern type " + type); } diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFShader.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFShader.java index d280b82f2..376a70f92 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFShader.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PDFShader.java @@ -132,7 +132,7 @@ public static PDFShader getShader(PDFObject shaderObj, Map resources) case COONS_PATCH_MESH_SHADING: case TENSOR_PRODUCTS_MESH_SHADING: default: - shader = new DummyShader(type); + shader = new DummyShader(type); } // read the color space (required) diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType1.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType1.java index d8b5aa345..5cb3f8b9c 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType1.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType1.java @@ -93,7 +93,7 @@ public PatternType1() { * Note the resources passed in are ignored... */ @Override - protected void parse(PDFObject patternObj, Map rsrc) throws IOException + protected void parse(PDFObject patternObj, Map rsrc) throws IOException { this.data = patternObj.getStream(); @@ -102,7 +102,7 @@ protected void parse(PDFObject patternObj, Map rsrc) throws IOException this.tilingType = patternObj.getDictRef("TilingType").getIntValue(); PDFObject bboxObj = patternObj.getDictRef("BBox"); - this.bbox= new Rectangle2D.Float(bboxObj.getAt(0).getFloatValue(), + this.bbox= new Rectangle2D.Float(bboxObj.getAt(0).getFloatValue(), bboxObj.getAt(1).getFloatValue(), bboxObj.getAt(2).getFloatValue(), bboxObj.getAt(3).getFloatValue()); @@ -120,7 +120,7 @@ protected void parse(PDFObject patternObj, Map rsrc) throws IOException * @param basePaint the base paint to use, or null if not needed */ @Override - public PDFPaint getPaint(PDFPaint basePaint) { + public PDFPaint getPaint(PDFPaint basePaint) { // create the outline of the pattern in user space by creating // a box with width xstep and height ystep. Transform that // box using the pattern's matrix to get the user space @@ -158,7 +158,7 @@ public PDFPaint getPaint(PDFPaint basePaint) { // get actual image Paint paint = new Paint() { @Override - public PaintContext createContext(ColorModel cm, + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, @@ -191,7 +191,7 @@ public PaintContext createContext(ColorModel cm, } @Override - public int getTransparency() { + public int getTransparency() { return Transparency.TRANSLUCENT; } }; @@ -253,7 +253,7 @@ public TilingPatternPaint(Paint paint, PatternType1 pattern) { * will be added. */ @Override - public Rectangle2D fill(PDFRenderer state, Graphics2D g, + public Rectangle2D fill(PDFRenderer state, Graphics2D g, GeneralPath s) { // first transform s into device space AffineTransform at = g.getTransform(); @@ -322,19 +322,19 @@ class Type1PaintContext implements PaintContext { } @Override - public void dispose() { + public void dispose() { this.colorModel = null; this.bbox = null; this.data = null; } @Override - public ColorModel getColorModel() { + public ColorModel getColorModel() { return this.colorModel; } @Override - public Raster getRaster(int x, int y, int w, int h) { + public Raster getRaster(int x, int y, int w, int h) { ColorSpace cs = getColorModel().getColorSpace(); int numComponents = cs.getNumComponents(); @@ -342,9 +342,9 @@ public Raster getRaster(int x, int y, int w, int h) { // all the data, plus alpha channel int[] imgData = new int[w * h * (numComponents + 1)]; - // the x and y step, as ints + // the x and y step, as ints int useXStep = (int) Math.abs(Math.ceil(this.xstep)); - int useYStep = (int) Math.abs(Math.ceil(this.ystep)); + int useYStep = (int) Math.abs(Math.ceil(this.ystep)); // a completely transparent pixel (alpha of 0) int[] emptyPixel = new int[numComponents + 1]; @@ -359,18 +359,18 @@ public Raster getRaster(int x, int y, int w, int h) { //if useXStep is 0, we would divide through 0 so instead xloc is set to 0 if(useXStep == 0) { - xloc = 0; + xloc = 0; } else { - xloc %= useXStep; + xloc %= useXStep; } //if useYStep is 0, we would divide through 0 so instead yloc is set to 0 if(useYStep == 0) { - yloc = 0; + yloc = 0; } else { - yloc %= useYStep; + yloc %= useYStep; } if (xloc < 0) { diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType2.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType2.java index 8d6b75041..576a99afd 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType2.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/PatternType2.java @@ -44,7 +44,7 @@ public PatternType2() { * Note the resources passed in are ignored... */ @Override - protected void parse(PDFObject patternObj, Map rsrc) throws IOException + protected void parse(PDFObject patternObj, Map rsrc) throws IOException { this.shader = PDFShader.getShader(patternObj.getDictRef("Shading"), rsrc); } @@ -58,7 +58,7 @@ protected void parse(PDFObject patternObj, Map rsrc) throws IOException * @param basePaint the base paint to use, or null if not needed */ @Override - public PDFPaint getPaint(PDFPaint basePaint) { - return shader.getPaint(); + public PDFPaint getPaint(PDFPaint basePaint) { + return shader.getPaint(); } } \ No newline at end of file diff --git a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/ShaderType2.java b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/ShaderType2.java index deca65188..26b38b577 100644 --- a/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/ShaderType2.java +++ b/openpdf-renderer/src/main/java/org/openpdf/renderer/pattern/ShaderType2.java @@ -75,7 +75,7 @@ public ShaderType2() { * Parse the shader-specific data */ @Override - public void parse(PDFObject shaderObj) throws IOException + public void parse(PDFObject shaderObj) throws IOException { // read the axis coordinates (required) PDFObject coordsObj = shaderObj.getDictRef("Coords"); @@ -124,7 +124,7 @@ public void parse(PDFObject shaderObj) throws IOException * Create a paint that paints this pattern */ @Override - public PDFPaint getPaint() { + public PDFPaint getPaint() { return PDFPaint.getPaint(new Type2Paint()); } @@ -235,7 +235,7 @@ public Type2Paint() { /** create a paint context */ @Override - public PaintContext createContext(ColorModel cm, + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, @@ -255,7 +255,7 @@ public PaintContext createContext(ColorModel cm, } @Override - public int getTransparency() { + public int getTransparency() { return Transparency.TRANSLUCENT; } } @@ -294,70 +294,70 @@ class Type2PaintContext implements PaintContext { } @Override - public void dispose() { + public void dispose() { this.colorModel = null; } @Override - public ColorModel getColorModel() { + public ColorModel getColorModel() { return this.colorModel; } @Override public Raster getRaster(int x, int y, int w, int h) { - ColorSpace cs = getColorModel().getColorSpace(); + ColorSpace cs = getColorModel().getColorSpace(); PDFColorSpace shadeCSpace = getColorSpace(); - PDFFunction functions[] = getFunctions(); - int numComponents = cs.getNumComponents(); + PDFFunction functions[] = getFunctions(); + int numComponents = cs.getNumComponents(); - float x0 = (float) this.start.getX(); - float y0 = (float) this.start.getY(); + float x0 = (float) this.start.getX(); + float y0 = (float) this.start.getY(); - float[] inputs = new float[1]; + float[] inputs = new float[1]; float[] outputs = new float[shadeCSpace.getNumComponents()]; float[] outputRBG = new float[numComponents]; - // all the data, plus alpha channel - int[] data = new int[w * h * (numComponents + 1)]; + // all the data, plus alpha channel + int[] data = new int[w * h * (numComponents + 1)]; - // for each device coordinate - for (int j = 0; j < h; j++) { - for (int i = 0; i < w; i += 1) { - boolean render = true; - // find t for that user coordinate + // for each device coordinate + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i += 1) { + boolean render = true; + // find t for that user coordinate float xp = getXPrime((float)(i + x), (float)(j + y), x0, y0); float t = 0; - if (xp >= 0 && xp <= 1) t = getMinT() + (dt1t0 * xp); - else if (xp < 0 && extendStart) t = getMinT(); - else if (xp > 1 && extendEnd) t = getMaxT(); - else render = false; + if (xp >= 0 && xp <= 1) t = getMinT() + (dt1t0 * xp); + else if (xp < 0 && extendStart) t = getMinT(); + else if (xp > 1 && extendEnd) t = getMaxT(); + else render = false; - if (render) { - // calculate the pixel values at t - inputs[0] = t; - if (functions.length == 1) { - functions[0].calculate(inputs, 0, outputs, 0); - } else { - for (int c = 0; c < functions.length; c++) { - functions[c].calculate(inputs, 0, outputs, c); - } - } - if (functions[0].getNumOutputs() != numComponents) { - //CMYK - outputRBG = shadeCSpace.getColorSpace().toRGB(outputs); - } - else outputRBG = outputs; + if (render) { + // calculate the pixel values at t + inputs[0] = t; + if (functions.length == 1) { + functions[0].calculate(inputs, 0, outputs, 0); + } else { + for (int c = 0; c < functions.length; c++) { + functions[c].calculate(inputs, 0, outputs, c); + } + } + if (functions[0].getNumOutputs() != numComponents) { + //CMYK + outputRBG = shadeCSpace.getColorSpace().toRGB(outputs); + } + else outputRBG = outputs; - int base = (j * w + i) * (numComponents + 1); - for (int c = 0; c < numComponents; c++) { - data[base + c] = (int) (outputRBG[c] * 255); - } - data[base + numComponents] = 255; - } - } - } + int base = (j * w + i) * (numComponents + 1); + for (int c = 0; c < numComponents; c++) { + data[base + c] = (int) (outputRBG[c] * 255); + } + data[base + numComponents] = 255; + } + } + } WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h); @@ -383,7 +383,7 @@ private float getXPrime(float x, float y, float x0, float y0) { * t = t0 + (t1 - t0) x x' */ private float getT(float xp) { - + if (xp < 0) { return getMinT(); } else if (xp > 1) { diff --git a/openpdf-renderer/src/test/java/openpdf/renderer/PDFDisplay.java b/openpdf-renderer/src/test/java/openpdf/renderer/PDFDisplay.java index 1a8da9933..193dc3889 100644 --- a/openpdf-renderer/src/test/java/openpdf/renderer/PDFDisplay.java +++ b/openpdf-renderer/src/test/java/openpdf/renderer/PDFDisplay.java @@ -18,63 +18,63 @@ import org.openpdf.renderer.PDFRenderer; public class PDFDisplay extends JComponent { - private static final long serialVersionUID = 1L; - // byte array containing the PDF file content - private byte[] bytes = null; - private String fileName; - private int pageIndex; - - public PDFDisplay(String fileName, int pageIndex) { - super(); - this.fileName = fileName; - this.pageIndex = pageIndex; - readFile(); - } + private static final long serialVersionUID = 1L; + // byte array containing the PDF file content + private byte[] bytes = null; + private String fileName; + private int pageIndex; + + public PDFDisplay(String fileName, int pageIndex) { + super(); + this.fileName = fileName; + this.pageIndex = pageIndex; + readFile(); + } - private void readFile() { - try(BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));){ - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - int b; - while ((b = inputStream.read()) != -1) { - outputStream.write(b); - } - this.bytes = outputStream.toByteArray(); - }catch (Exception e) { - e.printStackTrace(); - } - } + private void readFile() { + try(BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));){ + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int b; + while ((b = inputStream.read()) != -1) { + outputStream.write(b); + } + this.bytes = outputStream.toByteArray(); + }catch (Exception e) { + e.printStackTrace(); + } + } - @Override - public void paintComponent(Graphics g) { - try { - PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(this.bytes)); - PDFPage page = pdfFile.getPage(this.pageIndex); - Paper paper = new Paper(); - int formatOrientation = page.getAspectRatio() > 1 ? PageFormat.LANDSCAPE - : PageFormat.PORTRAIT; - if(formatOrientation == PageFormat.LANDSCAPE) { - paper.setSize(page.getHeight(), page.getWidth()); - }else { - paper.setSize(page.getWidth(), page.getHeight()); - } - PageFormat pageFormat = new PageFormat(); - pageFormat.setPaper(paper); - pageFormat.setOrientation(formatOrientation); + @Override + public void paintComponent(Graphics g) { + try { + PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(this.bytes)); + PDFPage page = pdfFile.getPage(this.pageIndex); + Paper paper = new Paper(); + int formatOrientation = page.getAspectRatio() > 1 ? PageFormat.LANDSCAPE + : PageFormat.PORTRAIT; + if(formatOrientation == PageFormat.LANDSCAPE) { + paper.setSize(page.getHeight(), page.getWidth()); + }else { + paper.setSize(page.getWidth(), page.getHeight()); + } + PageFormat pageFormat = new PageFormat(); + pageFormat.setPaper(paper); + pageFormat.setOrientation(formatOrientation); - Graphics2D g2d = (Graphics2D)g.create(); - Rectangle imgbounds = new Rectangle(0, 0, (int)pageFormat.getWidth(), - (int)pageFormat.getHeight()); - PDFRenderer renderer = new PDFRenderer(page, g2d, imgbounds, null, Color.WHITE); - try { - page.waitForFinish(); - } - catch (InterruptedException e) { - // some exception handling - } - renderer.run(); - }catch (Exception e) { - e.printStackTrace(); - } - - } + Graphics2D g2d = (Graphics2D)g.create(); + Rectangle imgbounds = new Rectangle(0, 0, (int)pageFormat.getWidth(), + (int)pageFormat.getHeight()); + PDFRenderer renderer = new PDFRenderer(page, g2d, imgbounds, null, Color.WHITE); + try { + page.waitForFinish(); + } + catch (InterruptedException e) { + // some exception handling + } + renderer.run(); + }catch (Exception e) { + e.printStackTrace(); + } + + } }