org.jpedal.parser.image.ImageDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/*
* ===========================================
* 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-2016 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
*
* ---------------
* ImageDecoder.java
* ---------------
*/
package org.jpedal.parser.image;
import com.idrsolutions.pdf.color.shading.BitReader;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import org.jpedal.color.*;
import org.jpedal.exception.PdfException;
import org.jpedal.external.ErrorTracker;
import org.jpedal.external.ImageDataHandler;
import org.jpedal.external.ImageHandler;
import org.jpedal.images.ImageTransformer;
import org.jpedal.images.ImageTransformerDouble;
import org.jpedal.images.SamplingFactory;
import org.jpedal.io.ColorSpaceConvertor;
import org.jpedal.io.ObjectStore;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.objects.PdfImageData;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.raw.PdfArrayIterator;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.parser.BaseDecoder;
import org.jpedal.parser.ParserOptions;
import org.jpedal.parser.PdfObjectCache;
import org.jpedal.parser.ValueTypes;
import org.jpedal.parser.image.data.ImageData;
import org.jpedal.parser.image.downsample.DownSampler;
import org.jpedal.parser.image.mask.MaskDataDecoder;
import org.jpedal.parser.image.mask.MaskDecoder;
import org.jpedal.parser.image.mask.SMaskDecoder;
import org.jpedal.parser.image.utils.ConvertMaskToImage;
import org.jpedal.render.SwingDisplay;
import org.jpedal.utils.LogWriter;
public class ImageDecoder extends BaseDecoder{
private boolean cacheLargeImages;
//Allow print to use transparency in printing instead of removing it
public static boolean allowPrintTransparency;
protected ParserOptions parserOptions;
final PdfImageData pdfImages;
private boolean getSamplingOnly;
//flag to show if image transparent*/
boolean isMask=true;
String imagesInFile;
PdfObjectCache cache;
final ImageHandler customImageHandler;
final PdfPageData pageData;
final ObjectStore objectStoreStreamRef;
//name of current image in pdf
String currentImage = "";
final ErrorTracker errorTracker;
final PdfObjectReader currentPdfFile;
//images on page
public final int imageCount;
public ImageDecoder(final int imageCount, final PdfObjectReader currentPdfFile, final ErrorTracker errorTracker, final ImageHandler customImageHandler, final ObjectStore objectStoreStreamRef, final PdfImageData pdfImages, final PdfPageData pageData, final String imagesInFile) {
this.imageCount=imageCount;
this.currentPdfFile=currentPdfFile;
this.errorTracker=errorTracker;
this.customImageHandler=customImageHandler;
this.objectStoreStreamRef=objectStoreStreamRef;
this.pdfImages=pdfImages;
this.pageData=pageData;
this.imagesInFile=imagesInFile;
}
private GenericColorSpace setupXObjectColorspace(final PdfObject XObject, final ImageData imageData){
final int width=imageData.getWidth();
final int height=imageData.getHeight();
final int depth=imageData.getDepth();
//handle colour information
GenericColorSpace decodeColorData=new DeviceRGBColorSpace();
final PdfArrayIterator ColorSpace=XObject.getMixedArray(PdfDictionary.ColorSpace);
if(ColorSpace.getTokenCount()>0){ //if not set will be zero
decodeColorData= ColorspaceFactory.getColorSpaceInstance(currentPdfFile, ColorSpace);
}
decodeColorData.setPrinting(parserOptions.isPrinting());
//track colorspace use
cache.put(PdfObjectCache.ColorspacesUsed, decodeColorData.getID(),"x");
//fix for odd itext file (/PDFdata/baseline_screens/debug3/Leistung.pdf)
final byte[] indexData=decodeColorData.getIndexedMap();
if(depth==8){
final byte[] objectData=imageData.getObjectData();
if(indexData!=null && decodeColorData.getID()==ColorSpaces.DeviceRGB && width*height==objectData.length) {
final PdfObject newMask = XObject.getDictionary(PdfDictionary.Mask);
final int[] maskArray = XObject.getIntArray(PdfDictionary.Mask);
if (newMask != null || maskArray!=null) {
//this specific case has all zeros
if (maskArray != null && maskArray.length == 2 && maskArray[0] == 255 && maskArray[0] == maskArray[1] && decodeColorData.getIndexedMap() != null && decodeColorData.getIndexedMap().length == 768) {
//see if index looks corrupt (ie all zeros) We exit as soon as we have disproved
boolean isCorrupt = true;
for (int jj = 0; jj < 768; jj++) {
if (indexData[jj] != 0) {
isCorrupt = false;
jj = 768;
}
}
if (isCorrupt) {
decodeColorData = new DeviceGrayColorSpace();
}
}
}
}
}
//pass through decode params
final PdfObject parms=XObject.getDictionary(PdfDictionary.DecodeParms);
if(parms!=null) {
decodeColorData.setDecodeParms(parms);
}
return decodeColorData;
}
public BufferedImage processImageXObject(PdfObject XObject, String image_name, byte[] objectData, final String details) throws PdfException {
BufferedImage image=null;
//add filename to make it unique
image_name = parserOptions.getFileName()+ '-' + image_name;
// System.out.println("XObject="+XObject+" "+XObject.getObjectRefAsString());
PdfObject newSMask=XObject.getDictionary(PdfDictionary.SMask);
final PdfObject newMask=XObject.getDictionary(PdfDictionary.Mask);
final int[] maskArray=XObject.getIntArray(PdfDictionary.Mask);
ImageData imageData=new ImageData(XObject, objectData);
imageData.getFilter(XObject);
GenericColorSpace decodeColorData = setupXObjectColorspace(XObject, imageData);
imageData.setCompCount(decodeColorData.getColorSpace().getNumComponents());
/*
* New code to apply SMask and Mask to data
* (note old isMask)
*/
byte[] convertedData=XObject.getConvertedData();
if(convertedData!=null){ //reuse converted mask data
objectData=convertedData;
decodeColorData=new DeviceRGBColorSpace();
//imageData.setObjectData(objectData);
imageData=null;
}else if(newSMask!=null || newMask!=null || maskArray!=null){
if(newSMask!=null && XObject.getInt(PdfDictionary.Width)==1 && XObject.getInt(PdfDictionary.Height)==1 && XObject.getInt(PdfDictionary.BitsPerComponent)==8){ //swap out the image with inverted SMask if empty
//silly case we handle in code below // /baseline_screens/11dec/grayscale.pdf
}else{
//WE NEED TO CONVERT JPG to raw DATA in IMAGE
if(imageData.isDCT()){
objectData=JPEGDecoder.getBytesFromJPEG(objectData,decodeColorData,XObject);
imageData.setObjectData(objectData);
XObject.setMixedArray(PdfDictionary.Filter,null);
XObject.setDecodedStream(objectData);
}else if(imageData.isJPX()){
objectData=JPeg2000ImageDecoder.getBytesFromJPEG2000(objectData);
if(decodeColorData.getID() == ColorSpaces.DeviceN){
objectData = ((DeviceNColorSpace)decodeColorData).getRGBBytes(objectData, imageData.getWidth(), imageData.getHeight());
}
imageData.setObjectData(objectData);
XObject.setMixedArray(PdfDictionary.Filter,null);
XObject.setDecodedStream(objectData);
decodeColorData=new DeviceRGBColorSpace();
}
if(newSMask!=null){
///WE NEED TO CONVERT JPG to raw DATA in smask as well
ImageData smaskImageData=new ImageData(newSMask, null);
smaskImageData.getFilter(newSMask);
GenericColorSpace maskColorSpace = setupXObjectColorspace(newSMask, smaskImageData);
byte[] maskData =currentPdfFile.readStream(newSMask,true,true,false, false,false, newSMask.getCacheName(currentPdfFile.getObjectReader()));
if(1==1){
objectData = SMaskDecoder.applyJPX_JBIG_Smask(imageData, smaskImageData, maskData,XObject, newSMask, decodeColorData, maskColorSpace);
}else{ // old method
maskData = MaskDataDecoder.getSMaskData(maskData,smaskImageData, newSMask,setupXObjectColorspace(newSMask, smaskImageData));
objectData=SMaskDecoder.applySMask(maskData,imageData,decodeColorData, newSMask,XObject);
}
XObject.setConvertedData(objectData);
}else{ //mask
byte[] index=decodeColorData.getIndexedMap();
if(index!=null){
index=decodeColorData.convertIndexToRGB(index);
if(maskArray!=null){
return getIndexedMaskImage(index, imageData, maskArray);
}
objectData=ColorSpaceConvertor.convertIndexToRGBByte(index, imageData.getWidth(), imageData.getHeight(), imageData.getCompCount(), imageData.getDepth(), objectData, false, false);
decodeColorData=new DeviceRGBColorSpace();
imageData.setObjectData(objectData);
decodeColorData.setIndex(null, 0);
// imageData.setCompCount(3);
// imageData.setDepth(8);
}
///WE NEED TO CONVERT JPG to raw DATA in mask as well
ImageData maskImageData;
if(newMask==null){
maskImageData=new ImageData(XObject, objectData);
}else{
maskImageData=new ImageData(newMask, objectData);
}
if(maskArray!=null){
return MaskDataDecoder.applyMaskArray(imageData, maskArray);
}
byte[] maskData= currentPdfFile.readStream(newMask, true, true, false, false, false, newMask.getCacheName(currentPdfFile.getObjectReader()));
maskData = MaskDataDecoder.getSMaskData(maskData,maskImageData, newMask,setupXObjectColorspace(newMask, maskImageData));
objectData=MaskDecoder.applyMask(imageData,decodeColorData,newMask,XObject,maskData);
XObject.setConvertedData(objectData);
decodeColorData=new DeviceRGBColorSpace();
XObject.setDictionary(PdfDictionary.Mask, null);
XObject.setIntArray(PdfDictionary.Mask, null);
}
// String dest="/Users/markee/Desktop/deviceRGB/"+org.jpedal.DevFlags.currentFile.substring(org.jpedal.DevFlags.currentFile.lastIndexOf("/"));
// ObjectStore.copy(org.jpedal.DevFlags.currentFile, dest);
//also set SMask to null (will set image to DeviceRGB below
//XObject.setDictionary(PdfDictionary.SMask, null);
imageData=null;
}
}
//reset if changed in Mask/SMask code
if(imageData==null){
imageData=new ImageData(XObject, objectData);
decodeColorData = new DeviceRGBColorSpace(true); //sets to 4 comp ARGB
imageData.setCompCount(4);
newSMask=null;
}
isMask= XObject.getBoolean(PdfDictionary.ImageMask);
LogWriter.writeLog("Processing XObject: " + image_name + ' ' + XObject.getObjectRefAsString() + " width=" + imageData.getWidth() + " Height=" + imageData.getHeight() +
" Depth=" + imageData.getDepth() + " colorspace=" + decodeColorData);
//allow user to process image
if(customImageHandler != null && !(customImageHandler instanceof ImageDataHandler)){
image= customImageHandler.processImageData(gs,XObject); //user gets raw JPEG data
}
//deal with special case of 1x1 pixel backed onto large inverted Smask which would be very slow in Generic code
//see (11dec/grayscale.pdf)
if(newSMask!=null && XObject.getInt(PdfDictionary.Width)==1 && XObject.getInt(PdfDictionary.Height)==1 && XObject.getInt(PdfDictionary.BitsPerComponent)==8){ //swap out the image with inverted SMask if empty
image = ConvertMaskToImage.convert(newSMask, currentPdfFile);
}else if(customImageHandler==null ||(image==null && !customImageHandler.alwaysIgnoreGenericHandler())) {
image = processImage(decodeColorData, imageData, isMask, XObject);
}
//add details to string so we can pass back
if(ImageCommands.trackImages && image!=null && details!=null){
setImageInfo(imageData, details, decodeColorData, image);
}
return image;
}
private static BufferedImage getIndexedMaskImage(byte[] index, ImageData imageData, int[] maskArray) {
int d = imageData.getDepth();
int p = 0;
int c = 0;
boolean[] invisible = new boolean[1 << d];
for (int i = 0; i < maskArray.length; i+=2) {
int start = maskArray[i];
int end = maskArray[i+1];
if(start==end){
invisible[start] = true;
}else{
for (int j = start; j < end; j++) {
invisible[j] = true;
}
}
}
int[] indexColors = new int[index.length / 3];
for (int i = 0; i < indexColors.length; i++) {
indexColors[i] = (255 << 24) | ((index[c++] & 0xff) << 16) | ((index[c++] & 0xff) << 8) | (index[c++] & 0xff);
}
BitReader reader = new BitReader(imageData.getObjectData(), d < 8);
BufferedImage img = new BufferedImage(imageData.getWidth(), imageData.getHeight(), BufferedImage.TYPE_INT_ARGB);
int output[] = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int imageDim = imageData.getWidth() * imageData.getHeight();
int w = imageData.getWidth();
int wc = 0;
for (int i = 0; i < imageDim; i++) {
int v = reader.getPositive(d);
if(!invisible[v]){
output[p++] = indexColors[v];
}else{
p++;
}
wc++;
if (wc == w) {
int balance = 8 - (reader.getPointer() % 8);
wc = 0;
if (balance != 8) {
reader.getPositive(balance);
}
}
}
return img;
}
private void setImageInfo(final ImageData imageData, final String details, GenericColorSpace decodeColorData, BufferedImage image) {
final int width=imageData.getWidth();
final int height=imageData.getHeight();
//work out effective dpi
float dpi = gs.CTM[0][0];
if(dpi ==0) {
dpi = gs.CTM[0][1];
}
if(dpi <0) {
dpi = -dpi;
}
dpi =(int)(width/dpi*100);
//add details to string
final StringBuilder imageInfo=new StringBuilder(details);
imageInfo.append(" w=");
imageInfo.append(width);
imageInfo.append(" h=");
imageInfo.append(height);
imageInfo.append(' ');
imageInfo.append((int) dpi);
imageInfo.append(' ');
imageInfo.append(ColorSpaces.IDtoString(decodeColorData.getID()));
imageInfo.append(" (");
imageInfo.append(image.getWidth());
imageInfo.append(' ');
imageInfo.append(image.getHeight());
imageInfo.append(" type=");
imageInfo.append(image.getType());
imageInfo.append(')');
if(imagesInFile.isEmpty()) {
imagesInFile = imageInfo.toString();
} else {
imageInfo.append('\n');
imageInfo.append(imagesInFile);
imagesInFile=imageInfo.toString();
}
}
public void setSamplingOnly(final boolean getSamplingOnly){
this.getSamplingOnly=getSamplingOnly;
}
public String getImagesInFile() {
return this.imagesInFile;
}
@Override
public void setParams(final ParserOptions parserOptions) {
this.parserOptions=parserOptions;
//Set flag to allow tunring on/off transparency optimisations in printing
String value = System.getProperty("org.jpedal.printTransparency");
if(value!=null){
ImageDecoder.allowPrintTransparency = parserOptions.isPrinting() && value.equalsIgnoreCase("true");
}
//Set flag to allow tunring on/off transparency optimisations in printing
value = System.getProperty("org.jpedal.viewerLargeImageCaching");
if(value!=null){
cacheLargeImages = value.equalsIgnoreCase("true");
}
}
/**
* save the current image, clipping and
* resizing clip. This gives us a clipped hires copy.
*/
public void generateClippedImage(BufferedImage image) {
final int pageRotation=pageData.getRotation(parserOptions.getPageNumber());
//object to scale and clip. Creating instance does the scaling
final ImageTransformerDouble image_transformation = new ImageTransformerDouble(gs, image, parserOptions.createScaledVersion(), 1, pageRotation);
//extract images either scaled/clipped or scaled then clipped
if(image_transformation!=null){
image_transformation.doubleScaleTransformShear();
//get intermediate image and save
image = image_transformation.getImage();
}
//convert mask into proper image if saving clipped images
if(isMask){
image = convertMaskToImage(image,gs.nonstrokeColorSpace.getColor().getRGB());
}
//@suda - image saved here is being saved out as garbage. Do we need to alter colorspace or issue in our image decoder.
//releate comment in JDeliHelper
if(objectStoreStreamRef.saveStoredImageAsBytes("CLIP_"+currentImage, image, false)) {
errorTracker.addPageFailureMessage("Problem saving " + image);
}
//complete the image and workout co-ordinates
image_transformation.completeImage();
//get final image to allow for way we draw 'upside down'
image = image_transformation.getImage();
//allow for null image returned (ie if too small)
if (image != null) {
//store final image on disk & in memory
if(parserOptions.imagesNeeded()){
//get initial values
float x = image_transformation.getImageX();
float y = image_transformation.getImageY();
float w = image_transformation.getImageW();
float h = image_transformation.getImageH();
pdfImages.setImageInfo(currentImage, parserOptions.getPageNumber(), x, y, w, h);
}
//
// //save the scaled/clipped version of image if allowed
// if(parserOptions.isFinalImagesExtracted()){
//
// image_transformation.doubleScaleTransformScale();
//
// objectStoreStreamRef.saveStoredImage(
// currentImage,
// ImageCommands.addBackgroundToMask(image, isMask),
// false,
// "png");
//
// }
}
}
private static BufferedImage convertMaskToImage(final BufferedImage outputImage, final int foreground) {
final int[] maskCol = {((foreground >> 16) & 0xFF), ((foreground >> 8) & 0xFF),((foreground) & 0xFF),255};
final BufferedImage img = new BufferedImage(outputImage.getWidth(), outputImage.getHeight(), outputImage.getType());
final Raster src = outputImage.getRaster();
final WritableRaster dest = img.getRaster();
final int[] values = new int[4];
final int w=outputImage.getWidth(),h=outputImage.getHeight();
for (int yy = 0; yy < h; yy++) {
for (int xx = 0; xx < w; xx++) {
//get raw color data
src.getPixel(xx, yy, values);
//System.out.println(values[0]+" "+values[1]+" "+values[2]+" "+values[3]+" ");
//if not transparent, fill with color
if (values[3] > 2) {
dest.setPixel(xx, yy, maskCol);
}
}
}
return img;
}
/**
* save the current image in raw and scaled/clipped version
* @param image
*/
public void generateTransformedImageSingle(BufferedImage image) {
//
if(parserOptions.isRawImagesExtracted()){
objectStoreStreamRef.saveStoredImageAsBytes('R'+currentImage,image,false);
}
// get clipped image and co-ords
final Area clipping_shape = gs.getClippingShape();
//object to scale and clip. Creating instance does the scaling
final ImageTransformer image_transformation =new ImageTransformer(gs,image);
//get initial values
float x = image_transformation.getImageX();
float y = image_transformation.getImageY();
float w = image_transformation.getImageW();
float h = image_transformation.getImageH();
//apply clip as well if exists and not inline image
if (customImageHandler!=null && clipping_shape != null && clipping_shape.getBounds().getWidth()>1 &&
clipping_shape.getBounds().getHeight()>1 && !customImageHandler.imageHasBeenScaled()) {
//see if clip is wider than image and ignore if so
if (!clipping_shape.contains(x, y, w, h)) {
//do the clipping
image_transformation.clipImage(clipping_shape);
//get ALTERED values
x = image_transformation.getImageX();
y = image_transformation.getImageY();
w = image_transformation.getImageW();
h = image_transformation.getImageH();
}
}
image = image_transformation.getImage();
//allow for null image returned (ie if too small)
if (image != null) {
pdfImages.setImageInfo(currentImage, parserOptions.getPageNumber(), x, y, w, h);
//save the scaled/clipped version of image if allowed
if(parserOptions.isFinalImagesExtracted()){
objectStoreStreamRef.saveStoredImageAsBytes(currentImage,ImageCommands.addBackgroundToMask(image, isMask), false);
}
}
}
/**
* read in the image and process and save raw image
*/
BufferedImage processImage(GenericColorSpace decodeColorData,
final ImageData imageData, final boolean imageMask,
final PdfObject XObject) throws PdfException {
//track its use
cache.put(PdfObjectCache.ColorspacesUsed, decodeColorData.getID(), "x");
imageData.getFilter(XObject);
BufferedImage image = null;//
//allow user to process image
if(customImageHandler instanceof ImageDataHandler){
image = customImageHandler.processImageData(gs, XObject);
} else if (imageData.isJPX()) {
removeJPXEncodingFromImageData(imageData, XObject);
} else if(imageData.isDCT()) {
int adobeColorTransform = 1;
PdfObject decodeParms=XObject.getDictionary(PdfDictionary.DecodeParms);
if(decodeParms!=null){
adobeColorTransform = decodeParms.getInt(PdfDictionary.ColorTransform);
}
byte[] objectData;
try {
objectData = JPEGDecoder.getUnconvertedBytesFromJPEG(imageData.getObjectData(), adobeColorTransform);
if (objectData == null) { //fix for lgpl version
objectData = JPEGDecoder.getBytesFromJPEGWithImageIO(imageData.getObjectData(), decodeColorData, XObject);
decodeColorData = new DeviceRGBColorSpace();
imageData.setCompCount(3);
imageData.setDecodeArray(null);
}
} catch (Exception e) {
LogWriter.writeLog("[PDF] Exception " + e + " Processing JPEG data in ImageDecoder");
objectData = JPEGDecoder.getBytesFromJPEGWithImageIO(imageData.getObjectData(), decodeColorData, XObject);
decodeColorData = new DeviceRGBColorSpace();
imageData.setCompCount(3);
imageData.setDecodeArray(null);
}
XObject.setMixedArray(PdfDictionary.Filter, null);
XObject.setDecodedStream(objectData);
imageData.setObjectData(objectData);
imageData.setDCT(false);
imageData.setDepth(8);
imageData.wasDCT(true);
}
if(image!=null){
return image;
}else{
return convertDataToImage(imageMask, imageData, XObject, decodeColorData);
}
}
static void removeJPXEncodingFromImageData(final ImageData imageData, final PdfObject XObject) {
final byte[] objectData = JPeg2000ImageDecoder.getUnconvertedBytesFromJPEG2000(imageData.getObjectData());
imageData.setObjectData(objectData);
XObject.setMixedArray(PdfDictionary.Filter, null);
XObject.setDecodedStream(objectData);
imageData.setDepth(8);
imageData.setIsJPX(false);
}
private BufferedImage convertDataToImage(final boolean imageMask, final ImageData imageData, final PdfObject XObject, GenericColorSpace decodeColorData) {
int sampling=1;
BufferedImage image;
//setup any imageMask
byte[] maskCol =null;
if (imageMask) {
maskCol=ImageCommands.getMaskColor(gs);
}
//setup sub-sampling
if(parserOptions.isRenderPage() && streamType!= ValueTypes.PATTERN){
setDownsampledImageSize(imageData, XObject,multiplyer,decodeColorData);
}
//down-sample size if displaying (some cases excluded at present)
if(parserOptions.isRenderPage() &&
decodeColorData.getID()!=ColorSpaces.ICC &&
imageData.getMode()!=ImageCommands.ID &&
(imageData.getDepth()==1 || imageData.getDepth()==8)
&& imageData.getpX()>0 && imageData.getpY()>0 && (SamplingFactory.isPrintDownsampleEnabled || !parserOptions.isPrinting())){
sampling=setSampling(imageData, decodeColorData);
if(sampling>1 && multiplyer>1){
sampling = (int) (sampling/ multiplyer);
}
}
//get sampling and exit from this code as we don't need to go further
if(getSamplingOnly){
int w=imageData.getWidth();
int h=imageData.getHeight();
if(imageData.getpX()>0 && imageData.getpY()>0){
final float scaleX=(((float)w)/imageData.getpX());
final float scaleY=(((float)h)/imageData.getpY());
if(scaleX>100 || scaleY>100){
//ignore
}else if(scaleX 0 && decodeColorData.getIndexedMap()==null){ //for the moment ignore if indexed (we may need to recode)
ImageCommands.applyDecodeArray(imageData.getObjectData(), imageData.getDepth(), decodeArray,decodeColorData.getID());
}
//apply any transfer function directly to data (does not work on DCT data)
final Object[] TRvalues=gs.getTR();
if(TRvalues!=null){ //array of values
ImageCommands.applyTR(imageData, TRvalues, currentPdfFile);
}
//switch to 8 bit and reduce bw image size by averaging
if(sampling>1 && !imageData.wasDCT()){
//choose whether we cache raw data so we can redecode images at different resolutions in Viewer
if(cacheLargeImages && decodeColorData.getIndexedMap()==null){
decodeColorData.dataToRGBByteArray(imageData.getObjectData(), imageData.getWidth(), imageData.getHeight());
if(SwingDisplay.testSampling){
System.out.println("cached image full size= "+imageData.getWidth()+", "+imageData.getHeight()+" Bits="+imageData.getDepth()+
" "+decodeColorData+" count="+imageData.getCompCount()+" bytes="+imageData.getObjectData().length);
}
objectStoreStreamRef.saveRawImageData(parserOptions.getPageNumber() + String.valueOf(imageCount),imageData.getObjectData(),
imageData.getWidth(),imageData.getHeight(),imageData.getDepth(), imageData.getpX(), imageData.getpY(),
maskCol,ColorSpaces.DeviceRGB);
}
decodeColorData = DownSampler.downSampleImage(decodeColorData, imageData, maskCol, sampling);
}
if (maskCol!=null) {
image = ImageDataToJavaImage.makeMaskImage(parserOptions, gs, current,imageData, decodeColorData, maskCol);
} else { //handle other types
LogWriter.writeLog( imageData.getWidth() + "W * " + imageData.getHeight() + "H BPC=" + imageData.getDepth() + ' ' + decodeColorData);
image =ImageDataToJavaImage.makeImage(decodeColorData,imageData);
}
if(image == null && !imageData.isRemoved()){
parserOptions.imagesProcessedFully=false;
}
if (maskCol!=null && gs.nonstrokeColorSpace.getColor().isTexture()) { //case 19095 vistair
float mm[][] = gs.CTM;
int w=imageData.getWidth();
int h=imageData.getHeight();
AffineTransform affine = new AffineTransform(mm[0][0], mm[0][1], mm[1][0], mm[1][1], mm[2][0], mm[2][1]);
BufferedImage temp = ((PatternColorSpace)gs.nonstrokeColorSpace).getRawImage(affine);
BufferedImage scrap = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if(temp!=null){
TexturePaint tp = new TexturePaint(temp, new Rectangle(0,0,temp.getWidth(),temp.getHeight()));
Graphics2D g2 = scrap.createGraphics();
g2.setPaint(tp);
Rectangle rect = new Rectangle(0,0,w,h);
g2.fill(rect);
}
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (image.getRGB(x, y) == -16777216) { //255 0 0 0
int pRGB = scrap.getRGB(x, y);
image.setRGB(x, y, pRGB);
}
}
}
}
return image;
}
private int setSampling(final ImageData imageData, GenericColorSpace decodeColorData) {
//see what we could reduce to and still be big enough for page
int sampling=1;
int w=imageData.getWidth();
int h=imageData.getHeight();
int newW=w;
int newH=h;
int pX=imageData.getpX();
int pY=imageData.getpY();
//limit size (allow bigger grayscale
if(multiplyer<=1 && !parserOptions.isPrinting()){
int maxAllowed=1000;
if(decodeColorData.getID()==ColorSpaces.DeviceGray){
maxAllowed=4000;
}
if(pX>maxAllowed) {
pX = maxAllowed;
}
if(pY>maxAllowed) {
pY = maxAllowed;
}
}
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;
}
imageData.setpX(pX);
imageData.setpY(pY);
return sampling;
}
private void setDownsampledImageSize(final ImageData imageData, final PdfObject XObject, final float multiplyer, final GenericColorSpace decodeColorData) {
int w=imageData.getWidth();
int h=imageData.getHeight();
if(parserOptions.isPrinting() && SamplingFactory.isPrintDownsampleEnabled && w<4000){
imageData.setpX(pageData.getCropBoxWidth(parserOptions.getPageNumber())*4);
imageData.setpY(pageData.getCropBoxHeight(parserOptions.getPageNumber())*4);
}else if(SamplingFactory.downsampleLevel== SamplingFactory.high || getSamplingOnly){// && w>500 && h>500){ // ignore small items
//ensure all positive for comparison
final float[][] CTM=new float[3][3];
for(int ii=0;ii<3;ii++){
for(int jj=0;jj<3;jj++){
if(gs.CTM[ii][jj]<0) {
CTM[ii][jj] = -gs.CTM[ii][jj];
} else {
CTM[ii][jj] = gs.CTM[ii][jj];
}
}
}
if(CTM[0][0]==0 || CTM[0][0]1){
imageData.setpX((int) (imageData.getpX()* multiplyer));
imageData.setpY((int) (imageData.getpX()* multiplyer));
}
//avoid for scanned text
if(imageData.getDepth()==1 && !hasMask &&
decodeColorData.getID()== ColorSpaces.DeviceGray && imageData.getHeight()<300){
imageData.setpX(0);
imageData.setpY(0);
}
}
public void setRes(final PdfObjectCache cache) {
this.cache=cache;
}
public int processImage(final String s, final int dataPointer, final PdfObject xObject)throws Exception {
return 0;
}
public int processImage(final int dataPointer, final int startInlineStream, final byte[] stream, final int tokenNumber)throws Exception {
return 0;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy