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

org.jpedal.io.ColorSpaceConvertor Maven / Gradle / Ivy

The newest version!
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/
 *
 * (C) Copyright 1997-2013, IDRsolutions and Contributors.
 *
 * 	This file is part of JPedal
 *
     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.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;

import org.jpedal.color.ColorSpaces;
import org.jpedal.color.DeviceCMYKColorSpace;
import org.jpedal.color.GenericColorSpace;
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 = false;

	/**
	 * slightly contrived but very effective way to convert to RGB
	 */
	public static BufferedImage convertFromICCCMYK(int width, int height, byte[] data) {

		BufferedImage image = null;
		try {

			/** make sure data big enough and pad out if not */
			int size = width * height * 4;
			if (data.length < size) {
				byte[] newData = new byte[size];
				System.arraycopy(data, 0, newData, 0, data.length);
				data = newData;
			}

			if (1 == 2) { // left for when they add hardware acceleration

				int[] bands = { 0, 1, 2, 3 };
				/** turn it into a BufferedImage so we can filter */
				DataBuffer db = new DataBufferByte(data, data.length);

				/** create RGB colorspace and model */
				ColorSpace rgbCS = GenericColorSpace.getColorSpaceInstance();

				/** define the conversion. hints can be replaced with null */
				ColorConvertOp CSToRGB = new ColorConvertOp(DeviceCMYKColorSpace.getColorSpaceInstance(), rgbCS, ColorSpaces.hints);

				/** create RGB colorspace and model */
				ComponentColorModel rgbModel = new ComponentColorModel(rgbCS, new int[] { 8, 8, 8 }, false, false, Transparency.OPAQUE,
						DataBuffer.TYPE_BYTE);

				image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

				WritableRaster rgbRaster = rgbModel.createCompatibleWritableRaster(width, height);
				CSToRGB.filter(Raster.createInterleavedRaster(db, width, height, width * 4, 4, bands, null), rgbRaster);
				image.setData(rgbRaster);
			}
			else {
				return profileConvertCMYKImageToRGB(data, width, height);
			}

		}
		catch (Exception ee) {

			if (LogWriter.isOutput()) LogWriter.writeLog("Exception  " + ee + " converting from ICC colorspace");
			ee.printStackTrace();
		}

		return image;
	}

	/**
	 * convert any BufferedImage to RGB colourspace
	 */
	public static BufferedImage convertToRGB(BufferedImage image) {

		// don't bother if already rgb or ICC
		if ((image.getType() != BufferedImage.TYPE_INT_RGB)) {

			try {
				/**/
				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 (Exception e) {

				e.printStackTrace();

				if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e.toString() + " converting to RGB");
			}
			catch (Error ee) {

				ee.printStackTrace();
				if (LogWriter.isOutput()) LogWriter.writeLog("Error " + ee.toString() + " converting to RGB");

				image = null;
			}
		}

		return image;
	}

	/**
	 * convert a BufferedImage to RGB colourspace (used when I clip the image)
	 */
	public static BufferedImage convertToARGB(BufferedImage image) {

		// don't bother if already rgb
		if (image.getType() != BufferedImage.TYPE_INT_ARGB) {
			try {
				BufferedImage raw_image = image;
				image = new BufferedImage(raw_image.getWidth(), raw_image.getHeight(), BufferedImage.TYPE_INT_ARGB);
				ColorConvertOp xformOp = new ColorConvertOp(null);
				xformOp.filter(raw_image, image);
			}
			catch (Exception e) {
				if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " creating argb image");
			}
		}

		isUsingARGB = true;

		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
	 */
	public static BufferedImage algorithmicConvertCMYKImageToRGB(byte[] buffer, int w, int h) {

		BufferedImage image = null;
		byte[] new_data = new byte[w * h * 3];

		int pixelCount = w * h * 4;

		double lastC = -1, lastM = -1.12, lastY = -1.12, lastK = -1.21;
		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 = i + 4) {

			double inCyan = (buffer[i] & 0xff) / x;
			double inMagenta = (buffer[i + 1] & 0xff) / x;
			double inYellow = (buffer[i + 2] & 0xff) / x;
			double inBlack = (buffer[i + 3] & 0xff) / x;

			if ((lastC == inCyan) && (lastM == inMagenta) && (lastY == inYellow) && (lastK == inBlack)) {
				// use existing values
			}
			else {// work out new
				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);

			Raster raster = createInterleavedRaster(new_data, w, h);
			image.setData(raster);

		}
		catch (Exception e) {
			if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " with 24 bit RGB image");
		}

		return image;
	}

	public static BufferedImage profileConvertCMYKImageToRGB(byte[] buffer, int w, int h) {

		ColorSpace CMYK = DeviceCMYKColorSpace.getColorSpaceInstance();

		BufferedImage image = null;
		byte[] new_data = new byte[w * h * 3];

		int pixelCount = w * h * 4;

		float lastC = -1, lastM = -1, lastY = -1, lastK = -1;
		float C, M, Y, K;

		float[] rgb = new float[3];

		/**
		 * loop through each pixel changing CMYK values to RGB
		 */
		int pixelReached = 0;
		for (int i = 0; i < pixelCount; i = i + 4) {

			C = (buffer[i] & 0xff) / 255f;
			M = (buffer[i + 1] & 0xff) / 255f;
			Y = (buffer[i + 2] & 0xff) / 255f;
			K = (buffer[i + 3] & 0xff) / 255f;

			if (lastC == C && lastM == M && lastY == Y && lastK == K) {
				// use existing values if not changed
			}
			else {// work out new

				rgb = CMYK.toRGB(new float[] { C, M, Y, K });

				lastC = C;
				lastM = M;
				lastY = Y;
				lastK = K;
			}

			new_data[pixelReached++] = (byte) (rgb[0] * 255);
			new_data[pixelReached++] = (byte) (rgb[1] * 255);
			new_data[pixelReached++] = (byte) (rgb[2] * 255);

		}

		/**
		 * turn data into RGB image
		 */
		try {

			image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
			Raster raster = createInterleavedRaster(new_data, w, h);
			image.setData(raster);

		}
		catch (Exception e) {
			if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " with 24 bit RGB image");
		}

		return image;
	}

	/**
	 * convert YCbCr to RGB using formula
	 * 
	 */
	public static BufferedImage algorithmicConvertYCbCrToRGB(byte[] buffer, int w, int h) {

		BufferedImage image = null;
		byte[] new_data = new byte[w * h * 3];

		int pixelCount = w * h * 3;

		if (pixelCount > buffer.length) pixelCount = buffer.length;

		// boolean isAllBlack=true;

		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 = i + 3) {

			int Y = ((buffer[i] & 255));
			int Cb = ((buffer[1 + i] & 255));
			int Cr = ((buffer[2 + i] & 255));

			if ((lastY == Y) && (lastCb == Cb) && (lastCr == Cr)) {
				// use existing values
			}
			else {// work out new

				// System.out.println(Y + " " + Cb + ' ' + Cr);

				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;

				// track blanks
				// if(Y==255 && Cr==0 && Cb==0) {
				//
				// }else
				// isAllBlack=false;

				// if (Y == 255 && Cr == Cb && (Cr!=0)) {

				// System.out.println(Y + " " + Cb + " " + Cr + " " + CENTER);

				// r = 255;
				// g = 255;
				// b = 255;

				// }

				// System.out.println(r+" "+g+ ' ' +b);

				lastY = Y;
				lastCb = Cb;
				lastCr = Cr;

			}

			new_data[pixelReached++] = (byte) (r);
			new_data[pixelReached++] = (byte) (g);
			new_data[pixelReached++] = (byte) (b);

		}

		// if(!nonTransparent || isAllBlack){
		//
		// wasRemoved=true;
		// return null;
		// }

		try {

			image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

			Raster raster = createInterleavedRaster(new_data, w, h);
			image.setData(raster);

		}
		catch (Exception e) {
			e.printStackTrace();

			if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " with 24 bit RGB image");
		}

		return image;
	}

	public static BufferedImage convertIndexedToFlat(int d, int w, int h, byte[] data, byte[] index, boolean isARGB, boolean isDownsampled) {

		BufferedImage image;
		DataBuffer db;
		int[] bandsRGB = { 0, 1, 2 };
		int[] bandsARGB = { 0, 1, 2, 3 };
		int[] bands;
		int components = 3;

		int indexLength = 0;

		if (index != null) indexLength = index.length;

		if (isARGB) {
			bands = bandsARGB;
			components = 4;
		}
		else bands = bandsRGB;

		int length = (w * h * components);

		// assume true in case of 8 bit and disprove
		// not currently used
		final boolean isGrayscale = false;// d==8; //@change

		byte[] newData = new byte[length];

		int id = 0;
		float ratio = 0f;

		switch (d) {
			case 8:

				int pt = 0;

				for (int ii = 0; ii < data.length - 1; ii++) {

					if (isDownsampled) ratio = (data[ii] & 0xff) / 255f;
					else id = (data[ii] & 0xff) * 3;

					if (pt >= length) break;

					// see - if really grayscale all components the same
					// if(index==null)
					// isGrayscale=isGrayscale && newData[pt]== newData[pt+1] && newData[pt]== newData[pt+2];
					// else
					// isGrayscale=isGrayscale && index[id]== index[id+1] && index[id]== index[id+2];

					if (isDownsampled) {
						if (ratio > 0) {
							newData[pt++] = (byte) ((255 - index[0]) * ratio);
							newData[pt++] = (byte) ((255 - index[1]) * ratio);
							newData[pt++] = (byte) ((255 - index[2]) * ratio);
						}
						else pt = pt + 3;
					}
					else {
						if (id < indexLength) {
							newData[pt++] = index[id];
							newData[pt++] = index[id + 1];
							newData[pt++] = index[id + 2];
						}
					}

					if (isARGB) {
						if (id == 0 && ratio == 0) newData[pt++] = (byte) 255;
						else newData[pt++] = 0;
					}
				}

				break;

			case 4:
				flatten4bpc(w, data, index, isARGB, length, newData);
				break;

			case 2:
				flatten2bpc(w, data, index, isARGB, length, newData);
				break;

			case 1:
				flatten1bpc(w, data, index, isARGB, length, 255, newData);
				break;

		}

		/** create the image */
		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) {

			byte[] grayData = new byte[w * h];
			int j = 0;
			for (int i = 0; i < newData.length; i = i + 3) {
				grayData[j] = newData[i];
				j++;
			}

			bands = new int[] { 0 };

			Raster raster = Raster.createInterleavedRaster(new DataBufferByte(grayData, grayData.length), w, h, w, 1, bands, null);

			image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
			image.setData(raster);

		}
		else {
			db = new DataBufferByte(newData, newData.length);
			WritableRaster raster = Raster.createInterleavedRaster(db, w, h, w * components, components, bands, null);
			image.setData(raster);
		}

		return image;
	}

	private static void flatten4bpc(int w, byte[] data, byte[] index, boolean isARGB, int length, byte[] newData) {

		int id1, pt = 0;
		int[] shift = { 4, 0 };
		int widthReached = 0;

		for (byte aData : data) {

			for (int samples = 0; samples < 2; samples++) {

				id1 = ((aData >> shift[samples]) & 15) * 3;

				if (pt >= length) break;

				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;
				}
			}
		}
	}

	public static void flatten1bpc(int w, byte[] data, byte[] index, boolean isARGB, int length, int transparency, byte[] newData) {

		int pt = 0;
		int id;// work through the bytes
		int widthReached = 0;
		for (byte aData : data) {

			for (int bits = 0; bits < 8; bits++) {

				// int id=((data[ii] & (1<>bits))*3;
				id = ((aData >> (7 - bits)) & 1) * 3;

				if (pt >= length) break;

				// @itemtoFix
				if (isARGB) {

					// System.out.println(id+" "+index[id]+" "+index[id+1]+" "+index[id+2]);

					// treat white as transparent
					if (1 == 2 && (index[id] & 255) > 250 && (index[id + 1] & 255) > 250 && (index[id + 2] & 255) > 250) {
						pt = pt + 4;
					}
					else
						if (id == 0) {
							newData[pt++] = index[id];
							newData[pt++] = index[id + 1];
							newData[pt++] = index[id + 2];

							newData[pt++] = (byte) transparency;

						}
						else {
							newData[pt++] = index[id];
							newData[pt++] = index[id + 1];
							newData[pt++] = index[id + 2];

							newData[pt++] = 0;
							// System.out.println(id+" "+index[id]+" "+index[id+1]+" "+index[id+2]);
						}

				}
				else {
					newData[pt++] = index[id];
					newData[pt++] = index[id + 1];
					newData[pt++] = index[id + 2];

				}
				// ignore filler bits
				widthReached++;
				if (widthReached == w) {
					widthReached = 0;
					bits = 8;
				}
			}
		}
	}

	/**
	 * convert to RGB or gray. If index is null we assume single component gray
	 * 
	 * @param w
	 * @param data
	 * @param index
	 * @param isARGB
	 * @param length
	 * @param newData
	 */
	public static void flatten2bpc(int w, byte[] data, byte[] index, boolean isARGB, int length, byte[] newData) {

		int id1, pt = 0;

		int[] shift = { 6, 4, 2, 0 };
		int widthReached = 0;

		for (byte aData : data) {

			for (int samples = 0; samples < 4; samples++) {

				if (pt >= 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
	 */
	public static BufferedImage iccConvertCMYKImageToRGB(byte[] buffer, int w, int h) throws IOException {

		/**
		 * set colorspaces and color models using profiles if set
		 */

		ColorSpace CMYK = DeviceCMYKColorSpace.getColorSpaceInstance();

		ColorSpace rgbCS = GenericColorSpace.getColorSpaceInstance();

		ColorModel rgbModel = new ComponentColorModel(rgbCS, new int[] { 8, 8, 8 }, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
		ColorConvertOp CSToRGB = new ColorConvertOp(CMYK, rgbCS, ColorSpaces.hints);

		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 = 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);

		}

		/**
		 * create CMYK raster from buffer
		 */
		Raster raster = Raster.createInterleavedRaster(new DataBufferByte(buffer, buffer.length), w, h, w * 4, 4, new int[] { 0, 1, 2, 3 }, null);
		WritableRaster rgbRaster = rgbModel.createCompatibleWritableRaster(w, h);

		/**
		 * convert to sRGB with profiles (I think this is done native as its much faster than my pure Java efforts)
		 */
		CSToRGB.filter(raster, rgbRaster);

		// data now sRGB so create image
		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		image.setData(rgbRaster);

		return image;
	}

	/**
	 * convert a BufferedImage to RGB colourspace
	 */
	public static BufferedImage convertColorspace(BufferedImage image, int newType) {

		try {
			BufferedImage raw_image = image;
			image = new BufferedImage(raw_image.getWidth(), raw_image.getHeight(), newType);
			ColorConvertOp xformOp = new ColorConvertOp(null);
			xformOp.filter(raw_image, image);
		}
		catch (Exception e) {
			if (LogWriter.isOutput()) LogWriter.writeLog("Exception " + e + " converting image");

		}
		return image;
	}

	/** convenience method used to check value within bounds */
	private static double clip01(double value) {

		if (value < 0) value = 0;

		if (value > 1) value = 1;

		return value;
	}

	public static WritableRaster createCompatibleWritableRaaster(ColorModel colorModel, int w, int h) {
		return colorModel.createCompatibleWritableRaster(w, h);
	}

	public static Raster createInterleavedRaster(byte[] data, int w, int h) {

		DataBuffer db = new DataBufferByte(data, data.length);
		int[] bands = { 0, 1, 2 };
		return Raster.createInterleavedRaster(db, w, h, w * 3, 3, bands, null);
	}

	public static void drawImage(Graphics2D g2, BufferedImage tileImg, AffineTransform tileAff, ImageObserver observer) {

		g2.drawImage(tileImg, tileAff, observer);
	}

	public static void flatten4bpc(int w, byte[] data, int newSize, byte[] newData) {

		int origSize = data.length;

		byte rawByte;
		int ptr = 0, currentLine = 0;
		boolean oddValues = ((w & 1) == 1);
		for (int ii = 0; ii < origSize; ii++) {
			rawByte = data[ii];

			currentLine = currentLine + 2;
			newData[ptr] = (byte) (rawByte & 240);
			if (newData[ptr] == -16) // fix for white
			newData[ptr] = (byte) 255;
			ptr++;

			if (oddValues && currentLine > w) { // 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;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy