Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* ===========================================
* 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
*
* ---------------
* ColorSpaceConvertor.java
* ---------------
*/
package org.jpedal.io;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import org.jpedal.JDeliHelper;
import org.jpedal.color.CMYKtoRGB;
import org.jpedal.color.ColorSpaces;
import org.jpedal.color.DeviceCMYKColorSpace;
import org.jpedal.utils.LogWriter;
/**
* set of static methods to save/load objects to convert images between
* different colorspaces -
*
* Several methods are very similar and I should recode my code to use a common
* method for the RGB conversion
*
* LogWriter is JPedal logging class
*
*/
public class ColorSpaceConvertor {
/** Flag to trigger raster printing */
public static boolean isUsingARGB;
/*
* slightly contrived but very effective way to convert to RGB
* @param width
* @param height
* @param data
* @return
*/
public static BufferedImage convertFromICCCMYK(final int width, final int height,byte[] data) {
/*make sure data big enough and pad out if not*/
final int size = width * height * 4;
if (data.length < size) {
final byte[] newData = new byte[size];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
}
int dim = width * height;
byte [] bp = JDeliHelper.convertCMYK2RGB(width, height, size, data);
if(bp == null){
bp = DeviceCMYKColorSpace.convertCMYK2RGBWithSimple(width, height, size, data);
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int [] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int r,g,b,pos = 0;
for (int i = 0; i < dim; i++) {
r = bp[pos++]&0xff;
g = bp[pos++]&0xff;
b = bp[pos++]&0xff;
pixels[i] = (r<<16) | (g<<8) | b ;
}
return img;
}
/**
* convert any BufferedImage to RGB colourspace.
*
* @param image is of type BufferedImage
* @return is of type BufferedImage
*/
public static BufferedImage convertToRGB(BufferedImage image) {
//don't bother if already rgb or ICC
if ((image.getType() != BufferedImage.TYPE_INT_RGB)) {
try{
/**/
final BufferedImage raw_image = image;
image =
new BufferedImage(
image.getWidth(),
image.getHeight(),
BufferedImage.TYPE_INT_RGB);
//ColorConvertOp xformOp = new ColorConvertOp(ColorSpaces.hints);/**/
//THIS VERSION IS AT LEAST 5 TIMES SLOWER!!!
//ColorConvertOp colOp = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), ColorSpaces.hints);
//image=colOp.filter(image,null);
//xformOp.filter(raw_image, image);
new ColorConvertOp(ColorSpaces.hints).filter(raw_image, image);
//image = raw_image;
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " converting to RGB");
} catch (final Error ee) {
LogWriter.writeLog("Error " + ee + " converting to RGB");
image=null;
}
}
return image;
}
/**
* convert a BufferedImage to RGB colourspace (used when I clip the image).
*
* @param image is of type BufferedImage
* @return is type BufferedImage
*/
public static BufferedImage convertToARGB(BufferedImage image) {
//don't bother if already rgb
if (image.getType() != BufferedImage.TYPE_INT_ARGB) {
try {
final BufferedImage raw_image = image;
image =
new BufferedImage(
raw_image.getWidth(),
raw_image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
final ColorConvertOp xformOp = new ColorConvertOp(null);
xformOp.filter(raw_image, image);
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " creating argb image");
}
}
isUsingARGB = true;
return image;
}
/**
* Convert YCbCr to RGB using formula.
* @param buffer is of type byte[]
* @param w is of type final int
* @param h is of type final int
* @return BufferedImage
*/
public static BufferedImage algorithmicConvertYCbCrToRGB(final byte[] buffer, final int w, final int h) {
BufferedImage image = null;
final byte[] new_data = new byte[w * h * 3];
int pixelCount = w * h*3;
if(pixelCount>buffer.length) {
pixelCount = buffer.length;
}
int r=0,g=0,b=0;
int lastY =-1, lastCb =-1, lastCr =-1;
int pixelReached = 0;
float val1;
for (int i = 0; i < pixelCount; i += 3) {
final int Y = ((buffer[i] & 255));
final int Cb = ((buffer[1+i] & 255));
final int Cr = ((buffer[2+i] & 255));
if((lastY ==Y)&&(lastCb ==Cb)&&(lastCr ==Cr)){
//use existing values
}else{//work out new
val1=298.082f*Y;
r = (int)(((val1+(408.583f*Cr))/256f)-222.921);
if(r<0) {
r = 0;
}
if(r>255) {
r = 255;
}
g = (int)(((val1-(100.291f*Cb)-(208.120f*Cr))/256f)+135.576f);
if(g<0) {
g = 0;
}
if(g>255) {
g = 255;
}
b = (int)(((val1+(516.412f*Cb))/256f)-276.836f);
if(b<0) {
b = 0;
}
if(b>255) {
b = 255;
}
lastY =Y;
lastCb =Cb;
lastCr =Cr;
}
new_data[pixelReached++] =(byte) (r);
new_data[pixelReached++] = (byte) (g);
new_data[pixelReached++] = (byte) (b);
}
try {
image =new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
final Raster raster = createInterleavedRaster(new_data, w, h);
image.setData(raster);
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " with 24 bit RGB image");
}
return image;
}
public static BufferedImage convertIndexedToFlat(final int d, final int w, final int h, final byte[] data, final byte[] index, final boolean isARGB, final boolean isDownsampled) {
BufferedImage image;
final DataBuffer db;
//assume true in case of 8 bit and disprove
//not currently used
final boolean isGrayscale=false;//d==8; //@change
final int[] bandsRGB = {0,1,2};
final int[] bandsARGB = {0,1,2,3};
int[] bands;
int components=3;
if(isARGB){
bands=bandsARGB;
components=4;
}else {
bands = bandsRGB;
}
byte[] newData=convertIndexToRGBByte(index, w, h, components, d, data, isDownsampled, isARGB);
if(isARGB) {
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
} else if(isGrayscale) {
image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
} else {
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
}
if(isGrayscale){
final byte[] grayData=new byte[w*h];
int j=0;
for(int i=0;i= length) {
break;
}
if (index == null) {
id1 = ((aData << shift[3 - samples]) & 192);
if (id1 == 192) { //top value white needs to be 255 so trap
id1 = 255;
}
newData[pt++] = (byte) (id1);
} else {
id1 = ((aData >> shift[samples]) & 3) * 3;
newData[pt++] = index[id1];
newData[pt++] = index[id1 + 1];
newData[pt++] = index[id1 + 2];
if (isARGB) {
if (id1 == 0) {
newData[pt++] = (byte) 0;
} else {
newData[pt++] = 0;
}
}
}
//ignore filler bits
widthReached++;
if (widthReached == w) {
widthReached = 0;
samples = 8;
}
}
}
}
/**
* Convert YCC to CMY via formula and the CMYK to sRGB via profiles.
* @param buffer is of type byte[]
* @param w is of type int
* @param h is of type int
* @return BufferedImage
*/
public static BufferedImage iccConvertCMYKImageToRGB(final byte[] buffer, final int w, final int h) {
final int pixelCount = w * h*4;
int Y,Cb,Cr,CENTER,lastY=-1,lastCb=-1,lastCr=-1,lastCENTER=-1;
int outputC=0, outputM=0,outputY=0;
double R,G,B;
//turn YCC in Buffer to CYM using profile
for (int i = 0; i < pixelCount; i += 4) {
Y=(buffer[i] & 255);
Cb = (buffer[i+1] & 255);
Cr = (buffer[i+2] & 255);
CENTER = (buffer[i+3] & 255);
if(Y==lastY && Cb==lastCb && Cr==lastCr && CENTER==lastCENTER){
//no change so use last value
}else{ //new value
R = Y + 1.402 * Cr - 179.456;
if(R<0d) {
R = 0d;
} else if(R>255d) {
R = 255d;
}
G=Y - 0.34414 * Cb - 0.71414 * Cr + 135.45984;
if(G<0d) {
G = 0d;
} else if(G>255d) {
G = 255d;
}
B = Y + 1.772 * Cb - 226.816;
if(B<0d) {
B = 0d;
} else if(B>255d) {
B = 255d;
}
outputC = 255 - (int)R;
outputM = 255 - (int)G;
outputY = 255 - (int)B;
//flag so we can just reuse if next value the same
lastY=Y;
lastCb=Cb;
lastCr=Cr;
lastCENTER=CENTER;
}
//put back as CMY
buffer[i] = (byte) (outputC );
buffer[i + 1] = (byte) (outputM );
buffer[i + 2] = (byte) (outputY );
}
return CMYKtoRGB.convert(buffer,w,h);
}
/**
* Convert a BufferedImage to RGB colourspace.
* @param image is of type BufferedImage
* @param newType is of type int
* @return BufferedImage
*/
public static BufferedImage convertColorspace(BufferedImage image, final int newType) {
try {
final BufferedImage raw_image = image;
image =
new BufferedImage(
raw_image.getWidth(),
raw_image.getHeight(),
newType);
final ColorConvertOp xformOp = new ColorConvertOp(null);
xformOp.filter(raw_image, image);
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " converting image");
}
return image;
}
/**convenience method used to check value within bounds*/
static double clip01(double value) {
if (value < 0) {
value = 0;
}
if (value > 1) {
value = 1;
}
return value;
}
public static WritableRaster createCompatibleWritableRaaster(final ColorModel colorModel, final int w, final int h) {
return colorModel.createCompatibleWritableRaster(w, h);
}
public static Raster createInterleavedRaster(final byte[] data, final int w, final int h) {
final DataBuffer db = new DataBufferByte(data, data.length);
final int[] bands = {0,1,2};
return Raster.createInterleavedRaster(db,w,h,w * 3,3,bands,null);
}
public static void drawImage(final Graphics2D g2, final BufferedImage tileImg, final AffineTransform tileAff, final ImageObserver observer) {
g2.drawImage(tileImg,tileAff,observer);
}
public static void flatten4bpc(final int w, final byte[] data, final int newSize, final byte[] newData) {
final int origSize=data.length;
byte rawByte;
int ptr=0,currentLine=0;
final boolean oddValues=((w & 1)==1);
for(int ii=0;iiw){ //ignore second value if odd as just packing
currentLine=0;
}else{
newData[ptr]=(byte) ((rawByte & 15) <<4);
if(newData[ptr]==-16) //fix for white
{
newData[ptr] = (byte) 255;
}
ptr++;
}
if(ptr==newSize) {
ii = origSize;
}
}
}
public static BufferedImage createRGBImage(int width, int height, byte[] data) {
// System.out.println("createARGBImage "+width+" "+height+" "+data.length);
final DataBuffer db = new DataBufferByte(data, data.length);
final int[] bands = { 0, 1, 2 };
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final Raster raster = Raster.createInterleavedRaster(db, width, height, width * 3,3, bands, null);
image.setData(raster);
return image;
}
public static BufferedImage createARGBImage(int width, int height, byte[] data) {
final DataBuffer db = new DataBufferByte(data, data.length);
final int[] bands = { 0, 1, 2,3 };
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Raster raster = Raster.createInterleavedRaster(db, width, height, width * 4, 4, bands, null);
image.setData(raster);
return image;
}
/* save raw CMYK data by converting to RGB using algorithm method -
* pdfsages supplied the C source and I have converted -
* This works very well on most colours but not dark shades which are
* all rolled into black
*
* This is what xpdf seems to use -
* Note we store the output data in our input queue to reduce memory
* usage - we have seen raw 2000 * 2000 images and having input and output
* buffers is a LOT of memory -
* I have kept the doubles in as I just rewrote Leonard's code -
* I haven't really looked at optimisation beyond memory issues
*
* @param buffer is of type byte[]
* @param w is of type final int
* @param h is of type final int
* @return type BufferedImage
*/
public static BufferedImage algorithmicConvertCMYKImageToRGB(final byte[] buffer, final int w, final int h) {
BufferedImage image = null;
final byte[] new_data = new byte[w * h * 3];
final int pixelCount = w * h*4;
double lastC=-1,lastM=-1.12,lastY=-1.12,lastK=-1.21;
final double x=255;
double c, m, y, aw, ac, am, ay, ar, ag, ab;
double outRed=0, outGreen=0, outBlue=0;
int pixelReached = 0;
for (int i = 0; i < pixelCount; i += 4) {
final double inCyan = (buffer[i]&0xff)/x ;
final double inMagenta = (buffer[i + 1]&0xff) / x;
final double inYellow = (buffer[i + 2]&0xff) / x;
final double inBlack = (buffer[i + 3]&0xff) / x;
if((lastC==inCyan)&&(lastM==inMagenta)&&
(lastY==inYellow)&&(lastK==inBlack)){
//use existing values
}else{//work out new
final double k = 1;
c = clip01(inCyan + inBlack);
m = clip01(inMagenta + inBlack);
y = clip01(inYellow + inBlack);
aw = (k - c) * (k - m) * (k - y);
ac = c * (k - m) * (k - y);
am = (k - c) * m * (k - y);
ay = (k - c) * (k - m) * y;
ar = (k - c) * m * y;
ag = c * (k - m) * y;
ab = c * m * (k - y);
outRed = x*clip01(aw + 0.9137 * am + 0.9961 * ay + 0.9882 * ar);
outGreen = x*clip01(aw + 0.6196 * ac + ay + 0.5176 * ag);
outBlue =
x*clip01(
aw
+ 0.7804 * ac
+ 0.5412 * am
+ 0.0667 * ar
+ 0.2118 * ag
+ 0.4863 * ab);
lastC=inCyan;
lastM=inMagenta;
lastY=inYellow;
lastK=inBlack;
}
new_data[pixelReached++] =(byte)(outRed);
new_data[pixelReached++] = (byte) (outGreen);
new_data[pixelReached++] = (byte) (outBlue);
}
try {
image = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
final Raster raster = createInterleavedRaster(new_data, w, h);
image.setData(raster);
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " with 24 bit RGB image");
}
return image;
}
}