From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../pdfbox/pdmodel/graphics/xobject/PDCcitt.java | 598 +++++++++++++++++++++ .../pdmodel/graphics/xobject/PDInlinedImage.java | 201 +++++++ .../pdfbox/pdmodel/graphics/xobject/PDJpeg.java | 156 ++++++ .../pdmodel/graphics/xobject/PDPixelMap.java | 236 ++++++++ .../pdfbox/pdmodel/graphics/xobject/PDXObject.java | 207 +++++++ .../pdmodel/graphics/xobject/PDXObjectForm.java | 120 +++++ .../pdmodel/graphics/xobject/PDXObjectImage.java | 244 +++++++++ .../pdfbox/pdmodel/graphics/xobject/package.html | 9 + 8 files changed, 1771 insertions(+) create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDJpeg.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java create mode 100644 src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html (limited to 'src/main/java/org/pdfbox/pdmodel/graphics/xobject') diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java new file mode 100644 index 0000000..59387a0 --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java @@ -0,0 +1,598 @@ +/** + * Copyright (c) 2005, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.pdmodel.graphics.xobject; + +import java.awt.image.BufferedImage; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; + +import java.util.ArrayList; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.pdfbox.cos.COSDictionary; +import org.pdfbox.cos.COSName; + +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.common.PDStream; +import org.pdfbox.pdmodel.graphics.color.PDDeviceGray; + +/** + * An image class for CCITT Fax. + * + * @author paul king + * @version $Revision: 1.2 $ + */ +public class PDCcitt extends PDXObjectImage +{ + private static final List FAX_FILTERS = new ArrayList(); + + static + { + FAX_FILTERS.add( COSName.CCITTFAX_DECODE.getName() ); + FAX_FILTERS.add( COSName.CCITTFAX_DECODE_ABBREVIATION.getName() ); + } + + /** + * Standard constructor. + * + * @param ccitt The PDStream that already contains all ccitt information. + */ + public PDCcitt(PDStream ccitt) + { + super(ccitt, "tiff"); + + } + + /** + * Construct from a tiff file. + * + * @param doc The document to create the image as part of. + * @param raf The random access TIFF file which contains a suitable CCITT compressed image + * @throws IOException If there is an error reading the tiff data. + */ + + public PDCcitt( PDDocument doc, java.io.RandomAccessFile raf ) throws IOException + { + super( new PDStream(doc),"tiff"); + // super( new PDStream( doc, null, true ), "tiff" ); + + COSDictionary decodeParms = new COSDictionary(); + + COSDictionary dic = getCOSStream(); + + extractFromTiff(raf, getCOSStream().createFilteredStream(),decodeParms); + + dic.setItem( COSName.FILTER, COSName.CCITTFAX_DECODE); + dic.setItem( COSName.SUBTYPE, COSName.IMAGE); + dic.setItem( COSName.TYPE, COSName.getPDFName( "XObject" ) ); + dic.setItem( "DecodeParms", decodeParms); + + setBitsPerComponent( 1 ); + setColorSpace( new PDDeviceGray() ); + setWidth( decodeParms.getInt("Columns") ); + setHeight( decodeParms.getInt("Rows") ); + + } + + /** + * Returns an image of the CCITT Fax, or null if TIFFs are not supported. (Requires additional JAI Image filters ) + * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#getRGBImage() + */ + public BufferedImage getRGBImage() throws IOException + { + // ImageIO.scanForPlugins(); + return ImageIO.read(new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream())); + } + + /** + * This writes a tiff to out. + * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#write2OutputStream(java.io.OutputStream) + */ + public void write2OutputStream(OutputStream out) throws IOException + { + InputStream data = new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream()); + byte[] buf = new byte[1024]; + int amountRead = -1; + while( (amountRead = data.read( buf )) != -1 ) + { + out.write( buf, 0, amountRead ); + } + } + + /** + * Extract the ccitt stream from the tiff file. + * + * @param raf - TIFF File + * @param os - Stream to write raw ccitt data two + * @param parms - COSDictionary which the encoding parameters are added to + * @throws IOException If there is an error reading/writing to/from the stream + */ + private void extractFromTiff(RandomAccessFile raf, OutputStream os, COSDictionary parms) throws IOException + { + try + { + + // First check the basic tiff header + raf.seek(0); + char endianess = (char) raf.read(); + if ((char) raf.read() != endianess) + { + throw new IOException("Not a valid tiff file"); + } + //ensure that endianess is either M or I + if (endianess != 'M' && endianess != 'I') + { + throw new IOException("Not a valid tiff file"); + } + int magicNumber = readshort(endianess, raf); + if( magicNumber != 42) + { + throw new IOException("Not a valid tiff file"); + } + + // Relocate to the first set of tags + raf.seek(readlong(endianess, raf)); + + int numtags = readshort(endianess, raf); + + // The number 50 is somewhat arbitary, it just stops us load up junk from somewhere and tramping on + if (numtags > 50) + { + throw new IOException("Not a valid tiff file"); + } + + // Loop through the tags, some will convert to items in the parms dictionary + // Other point us to where to find the data stream + // The only parm which might change as a result of other options is K, so + // We'll deal with that as a special; + + int k=-1000; // Default Non CCITT compression + int dataoffset=0; + int datalength=0; + + for (int i=0; i < numtags; i++) + { + int tag = readshort(endianess, raf); + int type = readshort(endianess, raf); + int count = readlong(endianess, raf); + int val = readlong(endianess, raf); // See note + + // Note, we treated that value as a long. The value always occupies 4 bytes + // But it might only use the first byte or two. Depending on endianess we might need to correct + // Note we ignore all other types, they are of little interest for PDFs/CCITT Fax + if (endianess == 'M') + { + switch (type) + { + case 1: + { + val = val >> 24; + break; // byte value + } + case 3: + { + val = val >> 16; + break; // short value + } + case 4: + { + break; // long value + } + default: + { + //do nothing + } + } + } + switch (tag) + { + case 256: + { + parms.setInt("Columns",val); + break; + } + case 257: + { + parms.setInt("Rows",val); + break; + } + case 259: + { + if (val == 4) + { + k=-1; + } + if (val == 3) + { + k=0; + } + break; // T6/T4 Compression + } + case 262: + { + if (val == 1) + { + parms.setBoolean("BlackIs1", true); + } + break; + } + case 273: + { + if (count == 1) + { + dataoffset=val; + } + break; + } + case 279: + { + if (count == 1) + { + datalength=val; + } + break; + } + case 292: + { + if (val == 1) + { + k=50; // T4 2D - arbitary K value + } + break; + } + case 324: + { + if (count == 1) + { + dataoffset=val; + } + break; + } + case 325: + { + if (count == 1) + { + datalength=val; + } + break; + } + default: + { + //do nothing + } + } + } + + if (k == -1000) + { + throw new IOException("First image in tiff is not CCITT T4 or T6 compressed"); + } + if (dataoffset == 0) + { + throw new IOException("First image in tiff is not a single tile/strip"); + } + + parms.setInt("K",k); + + raf.seek(dataoffset); + + byte[] buf = new byte[8192]; + int amountRead = -1; + while( (amountRead = raf.read( buf,0, Math.min(8192,datalength) )) > 0 ) + { + datalength -= amountRead; + os.write( buf, 0, amountRead ); + } + + } + finally + { + os.close(); + } + } + + private int readshort(char endianess, RandomAccessFile raf) throws IOException + { + if (endianess == 'I') + { + return raf.read() | (raf.read() << 8); + } + return (raf.read() << 8) | raf.read(); + } + + private int readlong(char endianess, RandomAccessFile raf) throws IOException + { + if (endianess == 'I') + { + return raf.read() | (raf.read() << 8) | (raf.read() << 16) | (raf.read() << 24); + } + return (raf.read() << 24) | (raf.read() << 16) | (raf.read() << 8) | raf.read(); + } + + + /** + * Extends InputStream to wrap the data from the CCITT Fax with a suitable TIFF Header. + * For details see www.tiff.org, which contains useful information including pointers to the + * TIFF 6.0 Specification + * + */ + private class TiffWrapper extends InputStream + { + + private int currentOffset; // When reading, where in the tiffheader are we. + private byte[] tiffheader; // Byte array to store tiff header data + private InputStream datastream; // Original InputStream + + public TiffWrapper(InputStream rawstream, COSDictionary options) + { + buildHeader(options); + currentOffset=0; + datastream = rawstream; + } + + // Implement basic methods from InputStream + + public boolean markSupported() + { + return false; + } + + public void reset() throws IOException + { + throw new IOException("reset not supported"); + } + + // For simple read, take a byte from the tiffheader array or pass through. + public int read() throws IOException + { + if (currentOffset < tiffheader.length) + { + return tiffheader[currentOffset++]; + } + return datastream.read(); + } + + // For read methods only return as many bytes as we have left in the header + // if we've exhausted the header, pass through to the InputStream of the raw CCITT data + public int read(byte[] data) throws IOException + { + if (currentOffset < tiffheader.length) + { + int length = java.lang.Math.min(tiffheader.length - currentOffset, data.length); + if (length > 0) + { + System.arraycopy(tiffheader, currentOffset, data, 0, length); + } + currentOffset += length; + return length; + } + else + { + return datastream.read(data); + } + } + + // For read methods only return as many bytes as we have left in the header + // if we've exhausted the header, pass through to the InputStream of the raw CCITT data + public int read(byte[] data, int off, int len) throws IOException + { + if (currentOffset < tiffheader.length) + { + int length = java.lang.Math.min(tiffheader.length - currentOffset, len); + if (length > 0) + { + System.arraycopy(tiffheader, currentOffset, data, off, length); + } + currentOffset += length; + return length; + } + else + { + return datastream.read(data,off,len); + } + } + + // When skipping if any header data not yet read, only allow to skip what we've in the buffer + // Otherwise just pass through. + public long skip(long n) throws IOException + { + if (currentOffset < tiffheader.length) + { + long length = Math.min(tiffheader.length - currentOffset, n); + currentOffset += length; + return length; + } + else + { + return datastream.skip(n); + } + } + + // Static data for the beginning of the TIFF header + private final byte[] basicHeader = { + 'I','I',42,0,8,0,0,0, // File introducer and pointer to first IFD + 0,0}; // Number of tags start with two + + + private int additionalOffset; // Offset in header to additional data + + // Builds up the tiffheader based on the options passed through. + private void buildHeader(COSDictionary options) + { + + final int numOfTags = 10; // The maximum tags we'll fill + final int maxAdditionalData = 24; // The maximum amount of additional data + // outside the IFDs. (bytes) + + // The length of the header will be the length of the basic header (10) + // plus 12 bytes for each IFD, 4 bytes as a pointer to the next IFD (will be 0) + // plus the length of the additional data + + tiffheader = new byte[10 + (12 * numOfTags ) + 4 + maxAdditionalData]; + java.util.Arrays.fill(tiffheader,(byte)0); + System.arraycopy(basicHeader,0,tiffheader,0,basicHeader.length); + + // Additional data outside the IFD starts after the IFD's and pointer to the next IFD (0) + additionalOffset = 10 + (12 * numOfTags ) + 4; + + // Now work out the variable values from TIFF defaults, + // PDF Defaults and the Dictionary for this XObject + short cols = 1728; + short rows = 0; + short blackis1 = 0; + short comptype = 3; // T4 compression + long t4options = 0; // Will set if 1d or 2d T4 + + COSDictionary decodeParms = (COSDictionary) options.getDictionaryObject("DecodeParms"); + + if (decodeParms != null) + { + cols = (short) decodeParms.getInt("Columns", cols); + rows = (short) decodeParms.getInt("Rows", rows); + if (decodeParms.getBoolean("BlackIs1", false)) + { + blackis1 = 1; + } + int k = decodeParms.getInt("K"); // Mandatory parm + if (k < 0) + { + //T6 + comptype = 4; + } + if (k > 0) + { + //T4 2D + comptype = 3; + t4options = 1; + } + // else k = 0, leave as default T4 1D compression + } + + // If we couldn't get the number of rows, use the main item from XObject + if (rows == 0) + { + rows = (short) options.getInt("Height", rows); + } + + // Now put the tags into the tiffheader + // These musn't exceed the maximum set above, and by TIFF spec should be sorted into + // Numeric sequence. + + addTag(256, cols); // Columns + addTag(257, rows); // Rows + addTag(259, comptype); // T6 + addTag(262, blackis1); // Photometric Interpretation + addTag(273, (long) tiffheader.length); // Offset to start of image data - updated below + addTag(279, (long) options.getInt("Length")); // Length of image data + addTag(282, 300, 1); // X Resolution 300 (default unit Inches) This is arbitary + addTag(283, 300, 1); // Y Resolution 300 (default unit Inches) This is arbitary + if (comptype == 3) + { + addTag(292, t4options); + } + addTag(305, "PDFBOX"); // Software generating image + } + + /* Tiff types 1 = byte, 2=ascii, 3=short, 4=ulong 5=rational */ + + private void addTag(int tag,long value) + { + // Adds a tag of type 4 (ulong) + int count = ++tiffheader[8]; + int offset = (count-1)*12 + 10; + tiffheader[offset]=(byte)(tag & 0xff); + tiffheader[offset+1]=(byte)((tag>>8) & 0xff); + tiffheader[offset+2]=4; // Type Long + tiffheader[offset+4]=1; // One Value + tiffheader[offset+8]=(byte)(value & 0xff); + tiffheader[offset+9]=(byte)((value>>8) & 0xff); + tiffheader[offset+10]=(byte)((value>>16) & 0xff); + tiffheader[offset+11]=(byte)((value>>24) & 0xff); + } + + private void addTag(int tag, short value) + { + // Adds a tag of type 3 (short) + int count = ++tiffheader[8]; + int offset = (count-1)*12 + 10; + tiffheader[offset]=(byte)(tag & 0xff); + tiffheader[offset+1]=(byte)((tag>>8) & 0xff); + tiffheader[offset+2]=3; // Type Short + tiffheader[offset+4]=1; // One Value + tiffheader[offset+8]=(byte)(value & 0xff); + tiffheader[offset+9]=(byte)((value>>8) & 0xff); + } + + private void addTag(int tag, String value) + { + // Adds a tag of type 2 (ascii) + int count = ++tiffheader[8]; + int offset = (count-1)*12 + 10; + tiffheader[offset]=(byte)(tag & 0xff); + tiffheader[offset+1]=(byte)((tag>>8) & 0xff); + tiffheader[offset+2]=2; // Type Ascii + tiffheader[offset+4]=1; // One Value + tiffheader[offset+8]=(byte)(additionalOffset & 0xff); + tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff); + tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff); + tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff); + System.arraycopy(value.getBytes(), 0, tiffheader, additionalOffset, value.length()); + additionalOffset += value.length() + 1; + } + + private void addTag(int tag, long numerator, long denominator) + { + // Adds a tag of type 5 (rational) + int count = ++tiffheader[8]; + int offset = (count-1)*12 + 10; + tiffheader[offset]=(byte)(tag & 0xff); + tiffheader[offset+1]=(byte)((tag>>8) & 0xff); + tiffheader[offset+2]=5; // Type Rational + tiffheader[offset+4]=1; // One Value + tiffheader[offset+8]=(byte)(additionalOffset & 0xff); + tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff); + tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff); + tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff); + tiffheader[additionalOffset++]=(byte) ((numerator) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((numerator>>8) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((numerator>>16) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((numerator>>24) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((denominator) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((denominator>>8) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((denominator>>16) & 0xFF); + tiffheader[additionalOffset++]=(byte) ((denominator>>24) & 0xFF); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java new file mode 100644 index 0000000..009743f --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2003-2004, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.pdmodel.graphics.xobject; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.IndexColorModel; +import java.awt.image.WritableRaster; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +import org.pdfbox.filter.Filter; +import org.pdfbox.filter.FilterManager; +import org.pdfbox.pdmodel.graphics.color.PDColorSpace; +import org.pdfbox.util.ImageParameters; + +/** + * This class represents an inlined image. + * + * @author Ben Litchfield (ben@csh.rit.edu) + * @version $Revision: 1.4 $ + */ +public class PDInlinedImage +{ + private ImageParameters params; + private byte[] imageData; + + /** + * This will get the image parameters. + * + * @return The image parameters. + */ + public ImageParameters getImageParameters() + { + return params; + } + + /** + * This will set the image parameters for this image. + * + * @param imageParams The imageParams. + */ + public void setImageParameters( ImageParameters imageParams ) + { + params = imageParams; + } + + /** + * Get the bytes for the image. + * + * @return The image data. + */ + public byte[] getImageData() + { + return imageData; + } + + /** + * Set the bytes that make up the image. + * + * @param value The image data. + */ + public void setImageData(byte[] value) + { + imageData = value; + } + + /** + * This will take the inlined image information and create a java.awt.Image from + * it. + * + * @return The image that this object represents. + * + * @throws IOException If there is an error creating the image. + */ + public BufferedImage createImage() throws IOException + { + /* + * This was the previous implementation, not sure which is better right now. + * byte[] transparentColors = new byte[]{(byte)0xFF,(byte)0xFF}; + byte[] colors=new byte[]{0, (byte)0xFF}; + IndexColorModel colorModel = new IndexColorModel( 1, 2, colors, colors, colors, transparentColors ); + BufferedImage image = new BufferedImage( + params.getWidth(), + params.getHeight(), + BufferedImage.TYPE_BYTE_BINARY, + colorModel ); + DataBufferByte buffer = new DataBufferByte( getImageData(), 1 ); + WritableRaster raster = + Raster.createPackedRaster( + buffer, + params.getWidth(), + params.getHeight(), + params.getBitsPerComponent(), + new Point(0,0) ); + image.setData( raster ); + return image; + */ + + + //verify again pci32.pdf before changing below + PDColorSpace pcs = params.getColorSpace(); + ColorModel colorModel = null; + if(pcs != null) + { + colorModel = + params.getColorSpace().createColorModel( + params.getBitsPerComponent() ); + } + else + { + byte[] transparentColors = new + byte[]{(byte)0xFF,(byte)0xFF}; + byte[] colors=new byte[]{0, (byte)0xFF}; + colorModel = new IndexColorModel( 1, 2, + colors, colors, colors, transparentColors ); + } + List filters = params.getFilters(); + byte[] finalData = null; + if( filters == null ) + { + finalData = getImageData(); + } + else + { + ByteArrayInputStream in = new ByteArrayInputStream( getImageData() ); + ByteArrayOutputStream out = new ByteArrayOutputStream(getImageData().length); + FilterManager filterManager = new FilterManager(); + for( int i=0; filters != null && i + *
  • 1 No prediction (the default value) + *
  • 2 TIFF Predictor 2 + *
  • 10 PNG prediction (on encoding, PNG None on all rows) + *
  • 11 PNG prediction (on encoding, PNG Sub on all rows) + *
  • 12 PNG prediction (on encoding, PNG Up on all rows) + *
  • 13 PNG prediction (on encoding, PNG Average on all rows) + *
  • 14 PNG prediction (on encoding, PNG Paeth on all rows) + *
  • 15 PNG prediction (on encoding, PNG optimum) + * + * + * Default value: 1. + * + * @return predictor algorithm code + */ + public int getPredictor() + { + COSDictionary decodeParms = getDecodeParams(); + if (decodeParms != null) + { + int i = decodeParms.getInt("Predictor"); + if (i != -1) + { + return i; + } + } + return 1; + } +} \ No newline at end of file diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java new file mode 100644 index 0000000..99ac8a5 --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java @@ -0,0 +1,207 @@ +/** + * Copyright (c) 2005, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.pdmodel.graphics.xobject; + +import java.io.IOException; +import java.util.List; + +import org.pdfbox.cos.COSBase; +import org.pdfbox.cos.COSName; +import org.pdfbox.cos.COSStream; + +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.common.COSObjectable; +import org.pdfbox.pdmodel.common.PDMetadata; +import org.pdfbox.pdmodel.common.PDStream; + +/** + * The base class for all XObjects in the PDF document. + * + * @author Ben Litchfield (ben@benlitchfield.com) + * @author mathiak + * @author Marcel Kammer + * @version $Revision: 1.12 $ + */ +public abstract class PDXObject implements COSObjectable +{ + private PDStream xobject; + + /** + * Standard constuctor. + * + * @param xobj The XObject dictionary. + */ + public PDXObject(COSStream xobj) + { + xobject = new PDStream( xobj ); + } + + /** + * Standard constuctor. + * + * @param xobj The XObject dictionary. + */ + public PDXObject(PDStream xobj) + { + xobject = xobj; + } + + /** + * Standard constuctor. + * + * @param doc The doc to store the object contents. + */ + public PDXObject(PDDocument doc) + { + xobject = new PDStream(doc); + xobject.getStream().setName( COSName.TYPE, "XObject" ); + } + + /** + * Returns the stream. + * @see org.pdfbox.pdmodel.common.COSObjectable#getCOSObject() + */ + public COSBase getCOSObject() + { + return xobject.getCOSObject(); + } + + /** + * Returns the stream. + * @return The stream for this object. + */ + public COSStream getCOSStream() + { + return xobject.getStream(); + } + + /** + * Returns the stream. + * @return The stream for this object. + */ + public PDStream getPDStream() + { + return xobject; + } + + /** + * Create the correct xobject from the cos base. + * + * @param xobject The cos level xobject to create. + * + * @return a pdmodel xobject + * @throws IOException If there is an error creating the xobject. + */ + public static PDXObject createXObject( COSBase xobject ) throws IOException + { + PDXObject retval = null; + if( xobject == null ) + { + retval = null; + } + else if( xobject instanceof COSStream ) + { + COSStream xstream = (COSStream)xobject; + String subtype = xstream.getNameAsString( "Subtype" ); + if( subtype.equals( PDXObjectImage.SUB_TYPE ) ) + { + PDStream image = new PDStream( xstream ); + // See if filters are DCT or JPX otherwise treat as Bitmap-like + // There might be a problem with several filters, but that's ToDo until + // I find an example + List filters = image.getFilters(); + if( filters != null && filters.contains( COSName.DCT_DECODE.getName() ) ) + { + return new PDJpeg(image); + } + else if ( filters != null && filters.contains( COSName.CCITTFAX_DECODE.getName() ) ) + { + return new PDCcitt(image); + } + else if( filters != null && filters.contains(COSName.JPX_DECODE.getName())) + { + //throw new IOException( "JPXDecode has not been implemented for images" ); + //JPX Decode is not really supported right now, but if we are just doing + //text extraction then we don't want to throw an exception, so for now + //just return a PDPixelMap, which will break later on if it is + //actually used, but for text extraction it is not used. + return new PDPixelMap( image ); + + } + else + { + retval = new PDPixelMap(image); + } + } + else if( subtype.equals( PDXObjectForm.SUB_TYPE ) ) + { + retval = new PDXObjectForm( xstream ); + } + else + { + throw new IOException( "Unknown xobject subtype '" + subtype + "'" ); + } + } + else + { + throw new IOException( "Unknown xobject type:" + xobject.getClass().getName() ); + } + + return retval; + } + + /** + * Get the metadata that is part of the document catalog. This will + * return null if there is no meta data for this object. + * + * @return The metadata for this object. + */ + public PDMetadata getMetadata() + { + PDMetadata retval = null; + COSStream mdStream = (COSStream)xobject.getStream().getDictionaryObject( "Metadata" ); + if( mdStream != null ) + { + retval = new PDMetadata( mdStream ); + } + return retval; + } + + /** + * Set the metadata for this object. This can be null. + * + * @param meta The meta data for this object. + */ + public void setMetadata( PDMetadata meta ) + { + xobject.getStream().setItem( "Metadata", meta ); + } +} diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java new file mode 100644 index 0000000..08858ea --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2005, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.pdmodel.graphics.xobject; + +import org.pdfbox.cos.COSDictionary; +import org.pdfbox.cos.COSName; +import org.pdfbox.cos.COSStream; + +import org.pdfbox.pdmodel.PDResources; +import org.pdfbox.pdmodel.common.PDStream; + +/** + * A form xobject. + * + * @author Ben Litchfield (ben@benlitchfield.com) + * @version $Revision: 1.4 $ + */ +public class PDXObjectForm extends PDXObject +{ + /** + * The XObject subtype. + */ + public static final String SUB_TYPE = "Form"; + + /** + * Standard constuctor. + * + * @param formStream The XObject is passed as a COSStream. + */ + public PDXObjectForm(PDStream formStream) + { + super( formStream ); + } + + /** + * Standard constuctor. + * + * @param formStream The XObject is passed as a COSStream. + */ + public PDXObjectForm(COSStream formStream) + { + super( formStream ); + } + + /** + * This will get the form type, currently 1 is the only form type. + * + * @return The form type. + */ + public int getFormType() + { + return getCOSStream().getInt( "FormType",1 ); + } + + /** + * Set the form type. + * + * @param formType The new form type. + */ + public void setFormType( int formType ) + { + getCOSStream().setInt( "FormType", formType ); + } + + /** + * This will get the resources at this page and not look up the hierarchy. + * This attribute is inheritable, and findResources() should probably used. + * This will return null if no resources are available at this level. + * + * @return The resources at this level in the hierarchy. + */ + public PDResources getResources() + { + PDResources retval = null; + COSDictionary resources = (COSDictionary)getCOSStream().getDictionaryObject( COSName.RESOURCES ); + if( resources != null ) + { + retval = new PDResources( resources ); + } + return retval; + } + + /** + * This will set the resources for this page. + * + * @param resources The new resources for this page. + */ + public void setResources( PDResources resources ) + { + getCOSStream().setItem( COSName.RESOURCES, resources ); + } +} diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java new file mode 100644 index 0000000..6257113 --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java @@ -0,0 +1,244 @@ +/** + * Copyright (c) 2004-2005, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.pdmodel.graphics.xobject; + +import java.awt.image.BufferedImage; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.pdfbox.cos.COSBase; +import org.pdfbox.cos.COSName; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.common.PDStream; +import org.pdfbox.pdmodel.graphics.color.PDColorSpace; +import org.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; +import org.pdfbox.pdmodel.graphics.color.PDDeviceGray; + +/** + * The prototype for all PDImages. + * + * @author Ben Litchfield (ben@benlitchfield.com) + * @author mathiak + * @version $Revision: 1.8 $ + */ +public abstract class PDXObjectImage extends PDXObject +{ + /** + * The XObject subtype. + */ + public static final String SUB_TYPE = "Image"; + + /** + * This contains the suffix used when writing to file. + */ + private String suffix; + + /** + * Standard constuctor. + * + * @param imageStream The XObject is passed as a COSStream. + * @param fileSuffix The file suffix, jpg/png. + */ + public PDXObjectImage(PDStream imageStream, String fileSuffix) + { + super( imageStream ); + suffix = fileSuffix; + } + + /** + * Standard constuctor. + * + * @param doc The document to store the stream in. + * @param fileSuffix The file suffix, jpg/png. + */ + public PDXObjectImage(PDDocument doc, String fileSuffix) + { + super( doc ); + getCOSStream().setName( COSName.SUBTYPE, SUB_TYPE ); + suffix = fileSuffix; + } + + /** + * Returns an java.awt.Image, that can be used for display etc. + * + * @return This PDF object as an AWT image. + * + * @throws IOException If there is an error creating the image. + */ + public abstract BufferedImage getRGBImage() throws IOException; + + /** + * Writes the Image to out. + * @param out the OutputStream that the Image is written to. + * @throws IOException when somethings wrong with out + */ + public abstract void write2OutputStream(OutputStream out) throws IOException; + + /** + * Writes the image to a file with the filename + an appropriate suffix, like "Image.jpg". + * The suffix is automatically set by the + * @param filename the filename + * @throws IOException When somethings wrong with the corresponding file. + */ + public void write2file(String filename) throws IOException + { + FileOutputStream out = null; + try + { + out = new FileOutputStream(filename + "." + suffix); + write2OutputStream(out); + out.flush(); + } + finally + { + if( out != null ) + { + out.close(); + } + } + } + + /** + * Get the height of the image. + * + * @return The height of the image. + */ + public int getHeight() + { + return getCOSStream().getInt( "Height", -1 ); + } + + /** + * Set the height of the image. + * + * @param height The height of the image. + */ + public void setHeight( int height ) + { + getCOSStream().setInt( "Height", height ); + } + + /** + * Get the width of the image. + * + * @return The width of the image. + */ + public int getWidth() + { + return getCOSStream().getInt( "Width", -1 ); + } + + /** + * Set the width of the image. + * + * @param width The width of the image. + */ + public void setWidth( int width ) + { + getCOSStream().setInt( "Width", width ); + } + + /** + * The bits per component of this image. This will return -1 if one has not + * been set. + * + * @return The number of bits per component. + */ + public int getBitsPerComponent() + { + return getCOSStream().getInt( new String[] { "BPC", "BitsPerComponent"}, -1 ); + } + + /** + * Set the number of bits per component. + * + * @param bpc The number of bits per component. + */ + public void setBitsPerComponent( int bpc ) + { + getCOSStream().setInt( "BitsPerComponent", bpc ); + } + + /** + * This will get the color space or null if none exists. + * + * @return The color space for this image. + * + * @throws IOException If there is an error getting the colorspace. + */ + public PDColorSpace getColorSpace() throws IOException + { + COSBase cs = getCOSStream().getDictionaryObject( new String[]{ "CS", "ColorSpace" } ); + PDColorSpace retval = null; + if( cs != null ) + { + retval = PDColorSpaceFactory.createColorSpace( cs ); + } + else + { + //there are some cases where the 'required' CS value is not present + //but we know that it will be grayscale for a CCITT filter. + COSBase filter = getCOSStream().getDictionaryObject( "Filter" ); + if( COSName.CCITTFAX_DECODE.equals( filter ) || + COSName.CCITTFAX_DECODE_ABBREVIATION.equals( filter ) ) + { + retval = new PDDeviceGray(); + } + } + return retval; + } + + /** + * This will set the color space for this image. + * + * @param cs The color space for this image. + */ + public void setColorSpace( PDColorSpace cs ) + { + COSBase base = null; + if( cs != null ) + { + base = cs.getCOSObject(); + } + getCOSStream().setItem( COSName.getPDFName( "ColorSpace" ), base ); + } + + /** + * This will get the suffix for this image type, jpg/png. + * + * @return The image suffix. + */ + public String getSuffix() + { + return suffix; + } +} diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html new file mode 100644 index 0000000..60d3324 --- /dev/null +++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html @@ -0,0 +1,9 @@ + + + + + + +This package deals with images that are stored in a PDF document. + + -- cgit v1.2.3