Package org.apache.pdfbox.pdmodel.graphics.xobject

Source Code of org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel.graphics.xobject;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.IIOException;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;

import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;

/**
* An image class for JPegs.
*
* @author mathiak
* @version $Revision: 1.5 $
*/
public class PDJpeg extends PDXObjectImage
{

    private static final String JPG = "jpg";
   
    private static final List<String> DCT_FILTERS = new ArrayList<String>();

    private final static float defaultCompressionLevel = 0.75f;
   
    static
    {
        DCT_FILTERS.add( COSName.DCT_DECODE.getName() );
        DCT_FILTERS.add( COSName.DCT_DECODE_ABBREVIATION.getName() );
    }

    /**
     * Standard constructor.
     *
     * @param jpeg The COSStream from which to extract the JPeg
     */
    public PDJpeg(PDStream jpeg)
    {
        super(jpeg, JPG);
    }

    /**
     * Construct from a stream.
     *
     * @param doc The document to create the image as part of.
     * @param is The stream that contains the jpeg data.
     * @throws IOException If there is an error reading the jpeg data.
     */
    public PDJpeg( PDDocument doc, InputStream is ) throws IOException
    {
        super( new PDStream( doc, is, true ), JPG);
        COSDictionary dic = getCOSStream();
        dic.setItem( COSName.FILTER, COSName.DCT_DECODE );
        dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
        dic.setItem( COSName.TYPE, COSName.XOBJECT );

        BufferedImage image = getRGBImage();
        if (image != null)
        {
            setBitsPerComponent( 8 );
            setColorSpace( PDDeviceRGB.INSTANCE );
            setHeight( image.getHeight() );
            setWidth( image.getWidth() );
        }

    }

    /**
     * Construct from a buffered image.
     * The default compression level of 0.75 will be used.
     *
     * @param doc The document to create the image as part of.
     * @param bi The image to convert to a jpeg
     * @throws IOException If there is an error processing the jpeg data.
     */
    public PDJpeg( PDDocument doc, BufferedImage bi ) throws IOException
    {
        super( new PDStream( doc ) , JPG);
        createImageStream(doc, bi, defaultCompressionLevel);
    }
   
    /**
     * Construct from a buffered image.
     *
     * @param doc The document to create the image as part of.
     * @param bi The image to convert to a jpeg
     * @param compressionQuality The quality level which is used to compress the image
     * @throws IOException If there is an error processing the jpeg data.
     */
    public PDJpeg( PDDocument doc, BufferedImage bi, float compressionQuality ) throws IOException
    {
        super( new PDStream( doc ), JPG);
        createImageStream(doc, bi, compressionQuality);
    }
   
    private void createImageStream(PDDocument doc, BufferedImage bi, float compressionQuality) throws IOException
    {
        BufferedImage alpha = null;
        if (bi.getColorModel().hasAlpha())
        {
            alpha = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            Graphics2D g = alpha.createGraphics();
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, bi.getWidth(), bi.getHeight());
            g.setColor(Color.WHITE);
            g.drawImage(bi, 0, 0, null);
            int alphaHeight = alpha.getHeight();
            int alphaWidth = alpha.getWidth();
            int whiteRGB = (Color.WHITE).getRGB();
            for(int y = 0; y < alphaHeight; y++)
            {
                for(int x = 0; x < alphaWidth; x++)
                {
                    Color color = new Color(alpha.getRGB(x, y));
                    if(color.getRed() != 0 && color.getGreen() != 0 && color.getBlue() != 0)
                    {
                        alpha.setRGB(x, y, whiteRGB);
                    }
                }
            }
            BufferedImage image = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_USHORT_565_RGB);
            g = image.createGraphics();
            g.drawImage(bi, 0, 0, null);
            bi = image;
        }
       
        java.io.OutputStream os = getCOSStream().createFilteredStream();
        try
        {
            ImageWriter writer = null;
            Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(JPG);
            if (iter.hasNext())
            {
                writer = iter.next();
            }
            ImageOutputStream ios = ImageIO.createImageOutputStream(os);
            writer.setOutput(ios);
               
            // Set the compression quality
            JPEGImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
            iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            iwparam.setCompressionQuality(compressionQuality);
               
            // Write the image
            writer.write(null, new IIOImage(bi, null, null), iwparam);
               
            writer.dispose();
           
            COSDictionary dic = getCOSStream();
            dic.setItem( COSName.FILTER, COSName.DCT_DECODE );
            dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
            dic.setItem( COSName.TYPE, COSName.XOBJECT );
            PDXObjectImage alphaPdImage = null;
            if(alpha != null)
            {
                alphaPdImage = new PDJpeg(doc, alpha, compressionQuality);
                dic.setItem(COSName.SMASK, alphaPdImage);
            }
            setBitsPerComponent( 8 );
            if (bi.getColorModel().getNumComponents() == 3)
            {
                setColorSpace( PDDeviceRGB.INSTANCE );
            }
            else
            {
                if (bi.getColorModel().getNumComponents() == 1)
                {
                    setColorSpace( new PDDeviceGray() );
                }
                else
                {
                    throw new IllegalStateException();
                }
            }
            setHeight( bi.getHeight() );
            setWidth( bi.getWidth() );
        }
        finally
        {
            os.close();
        }
    }

    /**
     * Returns an image of the JPeg, or null if JPegs are not supported. (They should be. )
     * {@inheritDoc}
     */
    public BufferedImage getRGBImage() throws IOException
    {   //TODO PKOCH
        BufferedImage bi = null;
        boolean readError = false;
        try
        {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            write2OutputStream(os);
            os.close();
            byte[] img = os.toByteArray();

            // 1. try to read jpeg image
            try
            {
                bi = ImageIO.read(new ByteArrayInputStream(img));
            }
            catch (IIOException iioe)
            {
                // cannot read jpeg
                readError = true;
            }
            catch (Exception ignore)
            {
            }

            // 2. try to read jpeg again. some jpegs have some strange header containing
            //    "Adobe " at some place. so just replace the header with a valid jpeg header.
            // TODO : not sure if it works for all cases
            if (bi == null && readError)
            {
                byte[] newImage = replaceHeader(img);

                ByteArrayInputStream bai = new ByteArrayInputStream(newImage);

                bi = ImageIO.read(bai);
            }
        }
        finally
        {
        }
       
        // If there is a 'soft mask' image then we use that as a transparency mask.
        PDXObjectImage smask = getSMaskImage();
        if (smask != null)
        {
            BufferedImage smaskBI = smask.getRGBImage();
           
             COSArray decodeArray = smask.getDecode();
             CompositeImage compositeImage = new CompositeImage(bi, smaskBI);
             BufferedImage rgbImage = compositeImage.createMaskedImage(decodeArray);

            return rgbImage;
        }
        else
        {
          // But if there is no soft mask, use the unaltered image.
            return bi;
        }
    }
   
    /**
     * This writes the JPeg to out.
     * {@inheritDoc}
     */
    public void write2OutputStream(OutputStream out) throws IOException
    {
        InputStream data = getPDStream().getPartiallyFilteredStream( DCT_FILTERS );
        byte[] buf = new byte[1024];
        int amountRead = -1;
        while( (amountRead = data.read( buf )) != -1 )
        {
            out.write( buf, 0, amountRead );
        }
    }

    /**
     * Returns the given file as byte array.
     * @param file File to be read
     * @return given file as byte array
     * @throws IOException if somethin went wrong during reading the file
     */
    public static byte[] getBytesFromFile(File file) throws IOException
    {
        InputStream is = new FileInputStream(file);
        long length = file.length();

        if (length > Integer.MAX_VALUE)
        {
            // File is too large
            throw new IOException("File is tooo large");
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;

        while (offset < bytes.length
                && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)
        {
            offset += numRead;
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length)
        {
            throw new IOException("Could not completely read file "+file.getName());
        }
        is.close();
        return bytes;
    }

    private int getHeaderEndPos(byte[] image)
    {
        for (int i = 0; i < image.length; i++)
        {
            byte b = image[i];
            if (b == (byte) 0xDB)
            {       
                // TODO : check for ff db
                return i -2;
            }
        }
        return 0;
    }

    private byte[] replaceHeader(byte[] image)
    {
        // get end position of wrong header respectively startposition of "real jpeg data"
        int pos = getHeaderEndPos(image);

        // simple correct header
        byte[] header = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0, (byte) 0x00,
                (byte) 0x10, (byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46, (byte) 0x00, (byte) 0x01,
                (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x60, (byte) 0x00, (byte) 0x60, (byte) 0x00, (byte) 0x00};

        // concat
        byte[] newImage = new byte[image.length - pos + header.length - 1];
        System.arraycopy(header, 0, newImage, 0, header.length);
        System.arraycopy(image, pos + 1, newImage, header.length, image.length - pos - 1);

        return newImage;
    }
}
TOP

Related Classes of org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.