All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.color.GenericColorSpace Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * GenericColorSpace.java
 * ---------------
 */
package org.jpedal.color;

//standard java
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;

import org.jpedal.examples.handlers.DefaultImageHelper;
import org.jpedal.exception.PdfException;
import org.jpedal.io.ColorSpaceConvertor;
import org.jpedal.objects.GraphicsState;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.LogWriter;

import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import javax.imageio.metadata.IIOMetadataNode;
import org.jpedal.JDeliHelper;

import org.w3c.dom.NodeList;

/**
 * Provides Color functionality and conversion for pdf
 * decoding
 */
public class GenericColorSpace  implements Cloneable, Serializable {
    
    boolean isConverted;

    /** actual raw value*/
    float[] rawValues;
    
    Map patterns; //holds new PdfObjects
    
    /**for Patterns*/
    float[][] CTM;
    
    /**size for indexed colorspaces*/
    private int size;
    
    /**holds cmyk values if present*/
    float c=-1;
    float y=-1;
    float m=-1;
    float k=-1;
    
    /**matrices for calculating CIE XYZ colour*/
    float[] W;
    float[] G;
    float[] Ma;
    //private float[] B;
    float[] R;
    
    /**defines rgb colorspace*/
    static ColorSpace rgbCS;
    
    public static final String cb = "Convert DCT encoded image bytestream to sRGB

*

It uses the internal Java classes * and the Adobe icm to convert CMYK and YCbCr-Alpha - the data is still DCT encoded.

*

The Sun class JPEGDecodeParam.java is worth examining because it contains lots * of interesting comments

*

I tried just using the new IOImage.read() but on type 3 images, all my clipping code * stopped working so I am still using 1.3

*/ protected final BufferedImage nonRGBJPEGToRGBImage( final byte[] data, int w, int h, final float[] decodeArray, final int pX, final int pY) { boolean isProcessed=false; BufferedImage image = null; ByteArrayInputStream in = null; ImageReader iir=null; ImageInputStream iin=null; try { if(CSToRGB==null){ initCMYKColorspace(); } CSToRGB = new ColorConvertOp(cs, rgbCS, ColorSpaces.hints); in = new ByteArrayInputStream(data); final int cmykType=getJPEGTransform(data); //suggestion from Carol try{ final Iterator iterator = ImageIO.getImageReadersByFormatName("JPEG"); while (iterator.hasNext()) { final Object o = iterator.next(); iir = (ImageReader) o; if (iir.canReadRaster()) { break; } } }catch(final Exception e){ LogWriter.writeLog("Unable to find jars on classpath "+e); return null; } //iir = (ImageReader)ImageIO.getImageReadersByFormatName("JPEG").next(); ImageIO.setUseCache(false); iin = ImageIO.createImageInputStream((in)); iir.setInput(iin, true); //new MemoryCacheImageInputStream(in)); Raster ras=iir.readRaster(0,null); //invert if(decodeArray!=null){ //decodeArray=Strip.removeArrayDeleminators(decodeArray).trim(); if((decodeArray.length==6 && decodeArray[0]==1f && decodeArray[1]==0f && decodeArray[2]==1f && decodeArray[3]==0f && decodeArray[4]==1f && decodeArray[5]==0f )|| (decodeArray.length>2 && decodeArray[0]==1f && decodeArray[1]==0)){ final DataBuffer buf=ras.getDataBuffer(); final int count=buf.getSize(); for(int ii=0;ii0){ LogWriter.writeLog("CMYK decode array "+java.util.Arrays.toString(decodeArray)+" not implemented"); } } if(cs.getNumComponents()==1 && cmykType==0){ //it is actually gray image=JPEGDecoder.grayJPEGToRGBImage( data, pX, pY, false); if(image!=null){ isProcessed=true; } }else if(cs.getNumComponents()==4){ //if 4 col CMYK of ICC translate isProcessed=true; try{ if(cmykType==2){ hasYCCKimages=true; image = ColorSpaceConvertor.iccConvertCMYKImageToRGB(((DataBufferByte)ras.getDataBuffer()).getData(),w,h); }else{ ras=cleanupRaster(ras,pX,pY,4); w=ras.getWidth(); h=ras.getHeight(); image=CMYKtoRGB.convert(ras,w,h); } }catch(final Exception e){ LogWriter.writeLog("Problem with JPEG conversion "+e); } }else if(cmykType!=0){ image=iir.read(0); image=cleanupImage(image,pX,pY); isProcessed=true; } //test if(!isProcessed){ /**1.3 version or vanilla version*/ final WritableRaster rgbRaster; if (cmykType == 4) { //CMYK ras=cleanupRaster(ras,pX,pY,4); final int width = ras.getWidth(); final int height = ras.getHeight(); rgbRaster =rgbModel.createCompatibleWritableRaster(width, height); CSToRGB.filter(ras, rgbRaster); image =new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); image.setData(rgbRaster); } else { //type 7 - these seem to crash the new 1.4 IO routines as far as I can see boolean isYCC=false; try{ final IIOMetadata metadata = iir.getImageMetadata(0); final String metadataFormat = metadata.getNativeMetadataFormatName(); final IIOMetadataNode iioNode = (IIOMetadataNode) metadata.getAsTree(metadataFormat); final NodeList children = iioNode.getElementsByTagName("app14Adobe"); if (children.getLength() > 0) { isYCC=true; } }catch(final Exception ee){ LogWriter.writeLog("[PDF] Unable to read metadata on Jpeg "+ee); } LogWriter.writeLog("COLOR_ID_YCbCr image"); if(isYCC){ //sample file debug2/pdf4134.pdf suggests we need this change image=DefaultImageHelper.read(data); }else{ //try with iccConvertCMYKImageToRGB(final byte[] buffer,int w,int h) and delete if works image=ColorSpaceConvertor.algorithmicConvertYCbCrToRGB(((DataBufferByte)ras.getDataBuffer()).getData(),w,h); } image=cleanupImage(image,pX,pY); image = ColorSpaceConvertor.convertToRGB(image); } } } catch (final Exception ee) { image = null; LogWriter.writeLog("Couldn't read JPEG, not even raster: " + ee); }catch(final Error err ){ LogWriter.writeLog("JPeg error "+err); if(iir!=null) { iir.dispose(); } if(iin!=null){ try { iin.flush(); } catch (final IOException e) { LogWriter.writeLog("Exception: "+e.getMessage()); } } } try { if(in!=null){ in.close(); } if(iir!=null){ iir.dispose(); } if(iin!=null){ iin.close(); } } catch (final Exception ee) { LogWriter.writeLog("Problem closing " + ee); } return image; } protected static BufferedImage cleanupImage(BufferedImage image, final int pX, final int pY){ try{ final int imageType=image.getType(); if(getSampling(image.getWidth(), image.getHeight(), pX, pY)<=1 || imageType==BufferedImage.TYPE_CUSTOM){ return image; }else if(imageType==BufferedImage.TYPE_3BYTE_BGR){ return cleanupBGRImage(image, pX, pY); }else{ if(imageType==5) { image= ColorSpaceConvertor.convertToRGB(image); } final Raster ras=cleanupRaster(image.getData(),pX, pY, image.getColorModel().getNumColorComponents()); image =new BufferedImage(ras.getWidth(),ras.getHeight(),image.getType()); image.setData(ras); return image; } }catch(final Error err){ LogWriter.writeLog("[PDF] Error in cleanupImage "+err); } return image; } private static int getSampling(final int w, final int h, final int pX, final int pY){ int sampling=1; //keep as multiple of 2 int newW=w,newH=h; if(pX>0 && pY>0){ final int smallestH=pY<<2; //double so comparison works final int smallestW=pX<<2; //cannot be smaller than page while(newW>smallestW && newH>smallestH){ sampling <<= 1; newW >>= 1; newH >>= 1; } int scaleX=w/pX; if(scaleX<1) { scaleX=1; } int scaleY=h/pY; if(scaleY<1) { scaleY=1; } //choose smaller value so at least size of page sampling=scaleX; if(sampling>scaleY) { sampling=scaleY; } } return sampling; } protected static Raster cleanupRaster(Raster ras, final int pX, final int pY, final int comp) { /** * allow user to disable this function and just return raw data */ final String avoidCleanupRaster=System.getProperty("org.jpedal.avoidCleanupRaster"); if(avoidCleanupRaster!=null && avoidCleanupRaster.toLowerCase().contains("true")){ return ras; } byte[] buffer=null; int[] intBuffer=null; final int type; final DataBuffer data=ras.getDataBuffer(); if(data instanceof DataBufferInt) { type=1; } else { type=0; } if(type==1) { intBuffer=((DataBufferInt)data).getData(); } else{ final int layerCount=ras.getNumBands(); if(layerCount==comp){ buffer=((DataBufferByte)data).getData(); }else if(layerCount==1){ final byte[] rawBuffer=((DataBufferByte)ras.getDataBuffer()).getData(); final int size=rawBuffer.length; final int realSize=size*comp; int j=0,i=0; buffer=new byte[realSize]; while(true){ for(int a=0;a=size) { break; } } }else if(LogWriter.isRunningFromIDE){ throw new RuntimeException("Unknown case "+layerCount+" in GenericColorspace"); } } int sampling=1; //keep as multiple of 2 final int w=ras.getWidth(); final int h=ras.getHeight(); int newW=w,newH=h; if(pX>0 && pY>0){ final int smallestH=pY<<2; //double so comparison works final int smallestW=pX<<2; //cannot be smaller than page while(newW>smallestW && newH>smallestH){ sampling <<= 1; newW >>= 1; newH >>= 1; } int scaleX=w/pX; if(scaleX<1) { scaleX=1; } int scaleY=h/pY; if(scaleY<1) { scaleY=1; } //choose smaller value so at least size of page sampling=scaleX; if(sampling>scaleY) { sampling=scaleY; } } //switch to 8 bit and reduce bw image size by averaging if(sampling>1){ newW=w/sampling; newH=h/sampling; int x,y,xx,yy,jj,origLineLength=w; try{ final byte[] newData=new byte[newW*newH*comp]; if(type==0) { origLineLength= w*comp; } for(y=0;ywGapLeft) { wCount=wGapLeft; } if(hCount>hGapLeft) { hCount=hGapLeft; } for(jj=0;jj>(8*(2-jj))) & 255); } count++; } } //set value as white or average of pixels if(count>0) { newData[jj+(x*comp)+(newW*y*comp)]=(byte)((byteTotal)/count); } } } } final int[] bands=new int[comp]; for(int jj2=0;jj2=size) { break; } } }else if(LogWriter.isRunningFromIDE){ throw new RuntimeException("Unknown case in GenericColorspace"); } } int sampling=1; //keep as multiple of 2 final int w=ras.getWidth(); final int h=ras.getHeight(); int newW=w,newH=h; if(pX>0 && pY>0){ final int smallestH=pY<<2; //double so comparison works final int smallestW=pX<<2; //cannot be smaller than page while(newW>smallestW && newH>smallestH){ sampling <<= 1; newW >>= 1; newH >>= 1; } int scaleX=w/pX; if(scaleX<1) { scaleX=1; } int scaleY=h/pY; if(scaleY<1) { scaleY=1; } //choose smaller value so at least size of page sampling=scaleX; if(sampling>scaleY) { sampling=scaleY; } } //switch to 8 bit and reduce bw image size by averaging if(sampling>1){ final WritableRaster newRas=((WritableRaster)ras); newW=w/sampling; newH=h/sampling; int x,y,xx,yy,jj,origLineLength=w; try{ final int[] newData=new int[comp]; if(type==0) { origLineLength= w*comp; } for(y=0;ywGapLeft) { wCount=wGapLeft; } if(hCount>hGapLeft) { hCount=hGapLeft; } for(jj=0;jj>(8*(2-jj))) & 255); } count++; } } //set value as white or average of pixels if (count > 0) { switch (jj) { case 0: newData[2] = ((byteTotal) / count); break; case 2: newData[0] = ((byteTotal) / count); break; default: newData[jj] = ((byteTotal) / count); break; } } } //write back into ras newRas.setPixels(x, y,1,1, newData);//changed to setPixels from setPixel for JAVA ME //System.out.println(x+"/"+newW+" "+y+"/"+newH+" "+newData[0]+" "+newData[1]); } } //put back data and trim img=new BufferedImage(newW,newH,img.getType()); img.setData(newRas); //img=img.getSubimage(0,0,newW,newH); slower so replaced }catch(final Exception e){ LogWriter.writeLog("Problem with Image "+e); } } return img; } /**Toms routine to read the image type - you can also use * int colorType = decoder.getJPEGDecodeParam().getEncodedColorID(); */ private static int getJPEGTransform(final byte[] data) { int xform = 0; final int dataLength=data.length; for (int i=0,imax=dataLength-2; i>16) & 0xFF); rgb[j2+1]=(byte) ((foreground>>8) & 0xFF); rgb[j2+2]=(byte) ((foreground) & 0xFF); j2 += 3; if(len-4-ii<4) { ii=len; } } return rgb; } try { /**turn it into a BufferedImage so we can convert then extract the data*/ final int width = data.length / compCount; final int height = 1; final DataBuffer db = new DataBufferByte(data, data.length); final WritableRaster raster = Raster.createInterleavedRaster(db, width, height, width * compCount, compCount, bands4, null); if (CSToRGB == null) { initCMYKColorspace(); CSToRGB = new ColorConvertOp(cs, rgbCS, ColorSpaces.hints); } final WritableRaster rgbRaster = rgbModel.createCompatibleWritableRaster(width, height); CSToRGB.filter(raster, rgbRaster); final DataBuffer convertedData = rgbRaster.getDataBuffer(); /**put into byte array*/ final int size = width * height * 3; data = new byte[size]; for (int ii = 0; ii < size; ii++){ data[ii] = (byte) convertedData.getElem(ii); } } catch (final Exception ee) { LogWriter.writeLog("Exception " + ee + " converting colorspace"); } return data; } /** * convert Index to RGB */ public byte[] convertIndexToRGB(final byte[] index){ return index; } /** * get an xml string with the color info */ public String getXMLColorToken(){ final String colorToken; //only cal if not set if(c==-1){ //approximate if(currentColor instanceof Color){ final Color col=(Color)currentColor; final float c=(255-col.getRed())/255f; final float m=(255-col.getGreen())/255f; final float y=(255-col.getBlue())/255f; float k=c; if(k"; } else { colorToken=GenericColorSpace.cb+"C='"+c+"' M='"+m+"' Y='"+y+"' K='"+k+"' pantoneName='"+pantoneName+"' >"; } }else{ colorToken=GenericColorSpace.cb+"type='shading'>"; } }else{ if(pantoneName==null) { colorToken=GenericColorSpace.cb+"C='"+c+"' M='"+m+"' Y='"+y+"' K='"+k+"' >"; } else { colorToken=GenericColorSpace.cb+"C='"+c+"' M='"+m+"' Y='"+y+"' K='"+k+"' pantoneName='"+pantoneName+"' >"; } } return colorToken; } /** * pass in list of patterns */ public void setPattern(final Map patterns, final int pageWidth, final int pageHeight, final float[][] CTM) { this.patterns=patterns; this.pageWidth=pageWidth; this.pageHeight=pageHeight; this.CTM=CTM; //System.out.println("set pattern called"); } /** used by generic decoder to asign color*/ public void setColor(final PdfPaint col) { this.currentColor=col; } /**return number of values used for color (ie 3 for rgb)*/ public int getColorComponentCount() { return componentCount; } /**pattern colorspace needs access to graphicsState*/ public void setGS(final GraphicsState currentGraphicsState) { this.gs=currentGraphicsState; } /**return raw values - only currently works for CMYK*/ public float[] getRawValues() { return rawValues; } /** * flag to show if YCCK image decoded so we can draw attention to user * @return */ public boolean isImageYCCK() { return hasYCCKimages; } public void setDecodeParms(final PdfObject parms) { this.decodeParms=parms; } public boolean isIndexConverted() { return isConverted; } /** * method to flush any caching values for cases where may need resetting (ie in CMYK where restore will render * last values in setColor used for caching invalid */ public void clearCache() { } public static ColorSpace getColorSpaceInstance() { ColorSpace rgbCS=ColorSpace.getInstance(ColorSpace.CS_sRGB); final String profile=System.getProperty("org.jpedal.RGBprofile"); if(profile!=null){ try{ rgbCS=new ICC_ColorSpace(ICC_Profile.getInstance(new FileInputStream(profile))); System.out.println("use "+profile); }catch(final Exception e){ LogWriter.writeLog("[PDF] Problem " + e.getMessage() + " with ICC data "); } } return rgbCS; } /** * ColorSpace.value in ICC * @return */ int getType() { return type; } /** * set PDF type (ColorSpaces variable) * @param rawValue */ void setType(int rawValue) { value=rawValue; rawCSType=rawValue; } void setRawColorSpace(int rawType) { rawCSType=rawType; } public int getRawColorSpacePDFType() { return rawCSType; } public BufferedImage JPEG2000ToImage(final byte[] data, final int pX, final int pY, final float[] decodeArray) throws PdfException { BufferedImage image; try { image = JDeliHelper.JPEG2000ToRGBImage(data); if(image!=null){ image = cleanupImage(image, pX, pY); } } catch (Exception ex) {//rethrow as Pdfexception throw new PdfException(ex.getMessage()); } return image; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy