/*
* Copyright © 2009-2011 Rebecca G. Bettencourt / Kreative Software
* <p>
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a>
* <p>
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
* <p>
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License (the "LGPL License"), in which
* case the provisions of LGPL License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the LGPL License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL License.
* @since PowerPaint 1.0
* @author Rebecca G. Bettencourt, Kreative Software
*/
package com.kreative.paint.pict;
import java.awt.image.*;
import java.io.*;
import java.util.*;
public class PICTUtilities {
private PICTUtilities() {}
public static byte[] makeByteArray(Object... objs) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
for (Object o : objs) {
if (o instanceof Byte) dos.writeByte((Byte)o);
else if (o instanceof Short) dos.writeShort((Short)o);
else if (o instanceof Integer) dos.writeInt((Integer)o);
else if (o instanceof Long) dos.writeLong((Long)o);
else if (o instanceof Float) dos.writeFloat((Float)o);
else if (o instanceof Double) dos.writeDouble((Double)o);
else if (o instanceof Boolean) dos.writeBoolean((Boolean)o);
else if (o instanceof Character) dos.writeChar((Character)o);
else if (o instanceof String) {
dos.writeInt(((String)o).length());
dos.writeChars((String)o);
}
else if (o instanceof StringBuffer) {
dos.writeInt((o.toString()).length());
dos.writeChars(o.toString());
}
else if (o instanceof byte[]) {
dos.writeInt(((byte[])o).length);
dos.write((byte[])o);
}
else if (o instanceof ColorSpec) ((ColorSpec)o).write(dos);
else if (o instanceof ColorTable) ((ColorTable)o).write(dos);
else if (o instanceof PixMap) ((PixMap)o).write(dos, true);
else if (o instanceof Point) ((Point)o).write(dos);
else if (o instanceof Polygon) ((Polygon)o).write(dos);
else if (o instanceof Rect) ((Rect)o).write(dos);
else if (o instanceof Region) ((Region)o).write(dos);
else if (o instanceof RGBColor) ((RGBColor)o).write(dos);
}
dos.close();
bos.close();
return bos.toByteArray();
}
public static Object[] unmakeByteArray(byte[] data, Class<?>... classes) throws IOException {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bis);
List<Object> objs = new Vector<Object>();
for (Class<?> c : classes) {
if (c == byte.class || c == Byte.class) objs.add(dis.readByte());
else if (c == short.class || c == Short.class) objs.add(dis.readShort());
else if (c == int.class || c == Integer.class) objs.add(dis.readInt());
else if (c == long.class || c == Long.class) objs.add(dis.readLong());
else if (c == float.class || c == Float.class) objs.add(dis.readFloat());
else if (c == double.class || c == Double.class) objs.add(dis.readDouble());
else if (c == boolean.class || c == Boolean.class) objs.add(dis.readBoolean());
else if (c == char.class || c == Character.class) objs.add(dis.readChar());
else if (c == String.class) {
int len = dis.readInt();
StringBuffer sb = new StringBuffer(len);
while (len-->0) sb.append(dis.readChar());
objs.add(sb.toString());
}
else if (c == StringBuffer.class) {
int len = dis.readInt();
StringBuffer sb = new StringBuffer(len);
while (len-->0) sb.append(dis.readChar());
objs.add(sb);
}
else if (c == byte[].class) {
byte[] d = new byte[dis.readInt()];
dis.readFully(d);
objs.add(d);
}
else if (c == ColorSpec.class) objs.add(ColorSpec.read(dis));
else if (c == ColorTable.class) objs.add(ColorTable.read(dis));
else if (c == PixMap.class) objs.add(PixMap.read(dis, true));
else if (c == Point.class) objs.add(Point.read(dis));
else if (c == Polygon.class) objs.add(Polygon.read(dis));
else if (c == Rect.class) objs.add(Rect.read(dis));
else if (c == Region.class) objs.add(Region.read(dis));
else if (c == RGBColor.class) objs.add(RGBColor.read(dis));
}
dis.close();
bis.close();
return objs.toArray(new Object[0]);
}
public static byte[] packBits(byte[] data) {
byte[] runs = new byte[data.length*2];
int runsPtr = 0;
for (byte b : data) {
if (runsPtr >= 2 && runs[runsPtr-1] == b && runs[runsPtr-2] < 127) {
runs[runsPtr-2]++;
} else {
runs[runsPtr++] = 1;
runs[runsPtr++] = b;
}
}
byte[] comp = new byte[data.length*2];
int compPtr = 0;
int compCntPtr = 0;
for (int i = 0; i < runsPtr; i += 2) {
int cnt = runs[i];
byte b = runs[i+1];
if (cnt > 1) {
comp[compPtr++] = (byte)(-cnt+1);
comp[compPtr++] = b;
compCntPtr = compPtr;
} else {
if (compCntPtr == compPtr || comp[compCntPtr] >= 127) {
comp[compPtr++] = 0;
comp[compPtr++] = b;
} else {
comp[compCntPtr]++;
comp[compPtr++] = b;
}
}
}
byte[] fin = new byte[compPtr];
for (int i = 0; i < compPtr; i++) fin[i] = comp[i];
return fin;
}
public static byte[] unpackBits(byte[] data) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int dataPtr = 0;
while (dataPtr < data.length) {
int v = data[dataPtr++];
if (v < 0) {
int count = -v+1;
byte d = data[dataPtr++];
while (count-->0) bos.write(d);
} else {
int count = v+1;
while (count-->0) bos.write(data[dataPtr++]);
}
}
return bos.toByteArray();
}
public static PICTInstruction makeBitsRect(int x, int y, BufferedImage img, int matte, float hRes, float vRes) {
int w = img.getWidth();
int h = img.getHeight();
int[] pixels = new int[w*h];
img.getRGB(0, 0, w, h, pixels, 0, w);
Set<Integer> colors = new HashSet<Integer>();
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] >= 0) {
pixels[i] = matte | 0xFF000000;
} else {
pixels[i] |= 0xFF000000;
}
colors.add(pixels[i] | 0xFF000000);
}
if (colors.size() <= 256) {
// indexed
PixMap pm = new PixMap();
pm.baseAddr = 0;
pm.rowBytes = w | 0x8000; while ((pm.rowBytes & 3) != 0) pm.rowBytes++;
pm.bounds = new Rect(x, y, w, h);
pm.pmVersion = 0;
pm.packType = PixMap.PACK_TYPE_PACKBITS;
pm.packSize = 0;
pm.hRes = hRes;
pm.vRes = vRes;
pm.pixelType = PixMap.PIXEL_TYPE_INDEXED;
pm.pixelSize = PixMap.PIXEL_SIZE_8BIT;
pm.cmpCount = PixMap.COMPONENT_COUNT_INDEXED;
pm.cmpSize = PixMap.COMPONENT_SIZE_8BIT;
pm.planeBytes = 0;
pm.pmTable = 0;
pm.pmReserved = 0;
ColorTable ct = new ColorTable();
ct.ctSeed = 0;
ct.ctFlags = 0;
ct.ctSize = colors.size()-1;
Integer[] ca = colors.toArray(new Integer[0]);
Arrays.sort(ca, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int c : ca) {
ct.ctTable.add(new ColorSpec(c));
}
BufferedImage pdi = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED, ct.toIndexColorModel(8));
pdi.setRGB(0, 0, w, h, pixels, 0, w);
byte[] pddata = ((DataBufferByte)pdi.getData().getDataBuffer()).getData();
ByteArrayOutputStream pdb = new ByteArrayOutputStream();
DataOutputStream pdd = new DataOutputStream(pdb);
try {
byte[] pdscanline = new byte[(pm.rowBytes & 0x7FFF)];
if ((pm.rowBytes & 0x7FFF) < 8) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = pddata[pddx];
}
pdd.write(pdscanline);
}
} else if ((pm.rowBytes & 0x7FFF) > 250) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = pddata[pddx];
}
byte[] csl = packBits(pdscanline);
pdd.writeShort(csl.length);
pdd.write(csl);
}
} else {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = pddata[pddx];
}
byte[] csl = packBits(pdscanline);
pdd.writeByte(csl.length);
pdd.write(csl);
}
}
pdd.close();
pdb.close();
} catch (IOException ex) {}
byte[] pd = pdb.toByteArray();
return new PICTInstruction.PackBitsRect(pm, ct, pm.bounds, pm.bounds, PICTInstruction.ModeConstants.SRC_COPY, pd);
} else {
// rgb
PixMap pm = new PixMap();
pm.baseAddr = 0;
pm.rowBytes = (w*4) | 0x8000;
pm.bounds = new Rect(x, y, w, h);
pm.pmVersion = 0;
pm.packType = PixMap.PACK_TYPE_BY_COMPONENT;
pm.packSize = 0;
pm.hRes = hRes;
pm.vRes = vRes;
pm.pixelType = PixMap.PIXEL_TYPE_RGBDIRECT;
pm.pixelSize = PixMap.PIXEL_SIZE_32BIT;
pm.cmpCount = PixMap.COMPONENT_COUNT_RGB;
pm.cmpSize = PixMap.COMPONENT_SIZE_32BIT;
pm.planeBytes = 0;
pm.pmTable = 0;
pm.pmReserved = 0;
ByteArrayOutputStream pdb = new ByteArrayOutputStream();
DataOutputStream pdd = new DataOutputStream(pdb);
try {
byte[] pdscanline = new byte[w*3];
if ((pm.rowBytes & 0x7FFF) < 8) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
pdd.write(pdscanline);
}
} else if ((pm.rowBytes & 0x7FFF) > 250) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
byte[] csl = packBits(pdscanline);
pdd.writeShort(csl.length);
pdd.write(csl);
}
} else {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
byte[] csl = packBits(pdscanline);
pdd.writeByte(csl.length);
pdd.write(csl);
}
}
pdd.close();
pdb.close();
} catch (IOException ex) {}
byte[] pd = pdb.toByteArray();
pm.packSize = pd.length;
return new PICTInstruction.DirectBitsRect(pm, pm.bounds, pm.bounds, PICTInstruction.ModeConstants.SRC_COPY, pd);
}
}
public static PICTInstruction makeBitsRgn(int x, int y, BufferedImage img, int matte, float hRes, float vRes) {
int w = img.getWidth();
int h = img.getHeight();
int[] pixels = new int[w*h];
img.getRGB(0, 0, w, h, pixels, 0, w);
Region rgn = Region.fromAlpha(x, y, w, h, pixels, 0, w);
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] >= 0) {
pixels[i] = matte | 0xFF000000;
} else {
pixels[i] |= 0xFF000000;
}
}
PixMap pm = new PixMap();
pm.baseAddr = 0;
pm.rowBytes = (w*4) | 0x8000;
pm.bounds = new Rect(x, y, w, h);
pm.pmVersion = 0;
pm.packType = PixMap.PACK_TYPE_BY_COMPONENT;
pm.packSize = 0;
pm.hRes = hRes;
pm.vRes = vRes;
pm.pixelType = PixMap.PIXEL_TYPE_RGBDIRECT;
pm.pixelSize = PixMap.PIXEL_SIZE_32BIT;
pm.cmpCount = PixMap.COMPONENT_COUNT_RGB;
pm.cmpSize = PixMap.COMPONENT_SIZE_32BIT;
pm.planeBytes = 0;
pm.pmTable = 0;
pm.pmReserved = 0;
ByteArrayOutputStream pdb = new ByteArrayOutputStream();
DataOutputStream pdd = new DataOutputStream(pdb);
try {
byte[] pdscanline = new byte[w*3];
if ((pm.rowBytes & 0x7FFF) < 8) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
pdd.write(pdscanline);
}
} else if ((pm.rowBytes & 0x7FFF) > 250) {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
byte[] csl = packBits(pdscanline);
pdd.writeShort(csl.length);
pdd.write(csl);
}
} else {
for (int ly = 0, pddy = 0; ly < h; ly++, pddy += w) {
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx] = (byte)((pixels[pddx] >>> 16) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w] = (byte)((pixels[pddx] >>> 8) & 0xFF);
}
for (int lx = 0, pddx = pddy; lx < w; lx++, pddx++) {
pdscanline[lx+w+w] = (byte)((pixels[pddx] >>> 0) & 0xFF);
}
byte[] csl = packBits(pdscanline);
pdd.writeByte(csl.length);
pdd.write(csl);
}
}
pdd.close();
pdb.close();
} catch (IOException ex) {}
byte[] pd = pdb.toByteArray();
pm.packSize = pd.length;
return new PICTInstruction.DirectBitsRgn(pm, pm.bounds, pm.bounds, PICTInstruction.ModeConstants.SRC_COPY, rgn, pd);
}
public static BufferedImage pixmapToImage(PixMap pm, ColorTable ct, byte[] data, int bg, int fg, boolean pixpat, boolean packed) {
// DECOMPRESS THE DATA TO GET THE RAW PIXEL DATA
if (((pm.packType == PixMap.PACK_TYPE_PACKBITS) && !packed) || (pm.packType == PixMap.PACK_TYPE_UNPACKED) || ((pm.rowBytes & 0x7FFF) < 8)) {
// no decompression necessary
} else if (pm.packType == PixMap.PACK_TYPE_UNPACKED_NO_PADDING) {
byte[] ndata = new byte[data.length*4/3];
for (int di = 0, ndi = 0; di < data.length && ndi < ndata.length; di += 3, ndi += 4) {
ndata[ndi+0] = 0;
ndata[ndi+1] = data[di+0];
ndata[ndi+2] = data[di+1];
ndata[ndi+3] = data[di+2];
}
data = ndata;
} else if ((pm.rowBytes & 0x7FFF) > 250) {
try {
ByteArrayInputStream bin = new ByteArrayInputStream(data);
DataInputStream din = new DataInputStream(bin);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
for (int y = pm.bounds.top; y < pm.bounds.bottom; y++) {
byte[] scanline = new byte[din.readUnsignedShort()];
din.readFully(scanline);
scanline = unpackBits(scanline);
if (pm.packType == PixMap.PACK_TYPE_BY_COMPONENT) {
if (pm.cmpCount == PixMap.COMPONENT_COUNT_ARGB) {
byte[] nscanline = new byte[scanline.length];
int sli = 0;
for (int nsli = 0; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 1; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 2; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 3; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
scanline = nscanline;
} else if (pm.cmpCount == PixMap.COMPONENT_COUNT_RGB) {
byte[] nscanline = new byte[scanline.length*4/3];
int sli = 0;
for (int nsli = 0; nsli < nscanline.length; nsli += 4) {
nscanline[nsli] = 0;
}
for (int nsli = 1; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 2; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 3; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
scanline = nscanline;
}
}
dout.write(scanline);
}
dout.close();
bout.close();
din.close();
bin.close();
data = bout.toByteArray();
} catch (IOException ioe) {
return null;
}
} else {
try {
ByteArrayInputStream bin = new ByteArrayInputStream(data);
DataInputStream din = new DataInputStream(bin);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
for (int y = pm.bounds.top; y < pm.bounds.bottom; y++) {
byte[] scanline = new byte[din.readUnsignedByte()];
din.readFully(scanline);
scanline = unpackBits(scanline);
if (pm.packType == PixMap.PACK_TYPE_BY_COMPONENT) {
if (pm.cmpCount == PixMap.COMPONENT_COUNT_ARGB) {
byte[] nscanline = new byte[scanline.length];
int sli = 0;
for (int nsli = 0; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 1; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 2; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 3; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
scanline = nscanline;
} else if (pm.cmpCount == PixMap.COMPONENT_COUNT_RGB) {
byte[] nscanline = new byte[scanline.length*4/3];
int sli = 0;
for (int nsli = 0; nsli < nscanline.length; nsli += 4) {
nscanline[nsli] = 0;
}
for (int nsli = 1; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 2; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
for (int nsli = 3; nsli < nscanline.length; nsli += 4, sli++) {
nscanline[nsli] = scanline[sli];
}
scanline = nscanline;
}
}
dout.write(scanline);
}
dout.close();
bout.close();
din.close();
bin.close();
data = bout.toByteArray();
} catch (IOException ioe) {
return null;
}
}
// CREATE THE COLOR TABLE
int[] colors;
if (ct != null) {
colors = ct.toIntArray();
if (colors.length < (1 << pm.pixelSize)) {
int[] newcolors = new int[1 << pm.pixelSize];
for (int i = 0; i < colors.length; i++) {
newcolors[i] = colors[i];
}
int k = newcolors.length - colors.length - 1;
if (k == 0) {
for (int i = colors.length; i < newcolors.length; i++) {
newcolors[i] = fg;
}
} else {
int bga = (bg >>> 24) & 0xFF;
int bgr = (bg >>> 16) & 0xFF;
int bgg = (bg >>> 8) & 0xFF;
int bgb = (bg >>> 0) & 0xFF;
int fga = (fg >>> 24) & 0xFF;
int fgr = (fg >>> 16) & 0xFF;
int fgg = (fg >>> 8) & 0xFF;
int fgb = (fg >>> 0) & 0xFF;
for (int i = colors.length, j = 0; i < newcolors.length; i++, j++) {
int a = bga + (fga-bga)*j/k;
int r = bgr + (fgr-bgr)*j/k;
int g = bgg + (fgg-bgg)*j/k;
int b = bgb + (fgb-bgb)*j/k;
newcolors[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
colors = newcolors;
}
} else if (pixpat) {
colors = new int[1 << pm.pixelSize];
int k = colors.length-1;
int bga = (bg >>> 24) & 0xFF;
int bgr = (bg >>> 16) & 0xFF;
int bgg = (bg >>> 8) & 0xFF;
int bgb = (bg >>> 0) & 0xFF;
int fga = (fg >>> 24) & 0xFF;
int fgr = (fg >>> 16) & 0xFF;
int fgg = (fg >>> 8) & 0xFF;
int fgb = (fg >>> 0) & 0xFF;
for (int i = 0; i < colors.length; i++) {
int a = bga + (fga-bga)*i/k;
int r = bgr + (fgr-bgr)*i/k;
int g = bgg + (fgg-bgg)*i/k;
int b = bgb + (fgb-bgb)*i/k;
colors[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
} else {
if (pm.pixelSize <= 1) colors = COLORS_1BIT;
else if (pm.pixelSize <= 2) colors = COLORS_2BIT;
else if (pm.pixelSize <= 4) colors = COLORS_4BIT;
else colors = COLORS_8BIT;
}
// CREATE THE IMAGE
int w = pm.bounds.right-pm.bounds.left;
int h = pm.bounds.bottom-pm.bounds.top;
int bw = (pm.rowBytes & 0x7FFF) * 8 / pm.pixelSize;
int[] pixels = new int[bw*h];
switch (pm.pixelSize) {
case PixMap.PIXEL_SIZE_32BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px++, dx += 4) {
if (pm.cmpCount == PixMap.COMPONENT_COUNT_ARGB) {
pixels[px] = ((data[dx+0] & 0xFF) << 24) | ((data[dx+1] & 0xFF) << 16) | ((data[dx+2] & 0xFF) << 8) | (data[dx+3] & 0xFF);
} else {
pixels[px] = 0xFF000000 | ((data[dx+1] & 0xFF) << 16) | ((data[dx+2] & 0xFF) << 8) | (data[dx+3] & 0xFF);
}
}
}
break;
case PixMap.PIXEL_SIZE_16BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px++, dx += 2) {
int sh = ((data[dx+0] & 0xFF) << 8) | (data[dx+1] & 0xFF);
int r = ((sh >>> 10) & 0x1F) * 255 / 31;
int g = ((sh >>> 5) & 0x1F) * 255 / 31;
int b = (sh & 0x1F) * 255 / 31;
pixels[px] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
break;
case PixMap.PIXEL_SIZE_8BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px++, dx++) {
pixels[px] = colors[data[dx] & 0xFF];
}
}
break;
case PixMap.PIXEL_SIZE_4BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px += 2, dx++) {
pixels[px] = colors[(data[dx] >>> 4) & 0xF];
pixels[px+1] = colors[data[dx] & 0xF];
}
}
break;
case PixMap.PIXEL_SIZE_2BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px += 4, dx++) {
pixels[px] = colors[(data[dx] >>> 6) & 0x3];
pixels[px+1] = colors[(data[dx] >>> 4) & 0x3];
pixels[px+2] = colors[(data[dx] >>> 2) & 0x3];
pixels[px+3] = colors[data[dx] & 0x3];
}
}
break;
case PixMap.PIXEL_SIZE_1BIT:
for (int ly = 0, py = 0, dy = 0; ly < h && py < pixels.length && dy < data.length; ly++, py += bw, dy += (pm.rowBytes & 0x7FFF)) {
for (int lx = 0, px = py, dx = dy; lx < w && px < pixels.length && dx < data.length; lx++, px += 8, dx++) {
pixels[px] = colors[(data[dx] >>> 7) & 0x1];
pixels[px+1] = colors[(data[dx] >>> 6) & 0x1];
pixels[px+2] = colors[(data[dx] >>> 5) & 0x1];
pixels[px+3] = colors[(data[dx] >>> 4) & 0x1];
pixels[px+4] = colors[(data[dx] >>> 3) & 0x1];
pixels[px+5] = colors[(data[dx] >>> 2) & 0x1];
pixels[px+6] = colors[(data[dx] >>> 1) & 0x1];
pixels[px+7] = colors[data[dx] & 0x1];
}
}
break;
}
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, w, h, pixels, 0, bw);
return img;
}
public static byte[] encodeString(String s) {
try {
return s.getBytes("MACROMAN");
} catch (UnsupportedEncodingException uee) {
ByteArrayOutputStream bs = new ByteArrayOutputStream(s.length());
for (char ch : s.toCharArray()) {
if (ch < 0x80) bs.write(ch);
else {
boolean found = false;
for (int i = 0x80; i < 0x100; i++) {
if (MACROMAN[i] == ch) {
found = true;
bs.write(i);
break;
}
}
if (!found) bs.write('?');
}
}
return bs.toByteArray();
}
}
public static String decodeString(byte[] data) {
try {
return new String(data, "MACROMAN");
} catch (UnsupportedEncodingException uee) {
StringBuffer sb = new StringBuffer(data.length);
for (byte b : data) {
if (b >= 0) sb.append((char)b);
else sb.append(MACROMAN[b & 0xFF]);
}
return sb.toString();
}
}
public static final int[] COLORS_8BIT = {
0xFFFFFFFF, 0xFFFFFFCC, 0xFFFFFF99, 0xFFFFFF66, 0xFFFFFF33, 0xFFFFFF00, 0xFFFFCCFF, 0xFFFFCCCC,
0xFFFFCC99, 0xFFFFCC66, 0xFFFFCC33, 0xFFFFCC00, 0xFFFF99FF, 0xFFFF99CC, 0xFFFF9999, 0xFFFF9966,
0xFFFF9933, 0xFFFF9900, 0xFFFF66FF, 0xFFFF66CC, 0xFFFF6699, 0xFFFF6666, 0xFFFF6633, 0xFFFF6600,
0xFFFF33FF, 0xFFFF33CC, 0xFFFF3399, 0xFFFF3366, 0xFFFF3333, 0xFFFF3300, 0xFFFF00FF, 0xFFFF00CC,
0xFFFF0099, 0xFFFF0066, 0xFFFF0033, 0xFFFF0000, 0xFFCCFFFF, 0xFFCCFFCC, 0xFFCCFF99, 0xFFCCFF66,
0xFFCCFF33, 0xFFCCFF00, 0xFFCCCCFF, 0xFFCCCCCC, 0xFFCCCC99, 0xFFCCCC66, 0xFFCCCC33, 0xFFCCCC00,
0xFFCC99FF, 0xFFCC99CC, 0xFFCC9999, 0xFFCC9966, 0xFFCC9933, 0xFFCC9900, 0xFFCC66FF, 0xFFCC66CC,
0xFFCC6699, 0xFFCC6666, 0xFFCC6633, 0xFFCC6600, 0xFFCC33FF, 0xFFCC33CC, 0xFFCC3399, 0xFFCC3366,
0xFFCC3333, 0xFFCC3300, 0xFFCC00FF, 0xFFCC00CC, 0xFFCC0099, 0xFFCC0066, 0xFFCC0033, 0xFFCC0000,
0xFF99FFFF, 0xFF99FFCC, 0xFF99FF99, 0xFF99FF66, 0xFF99FF33, 0xFF99FF00, 0xFF99CCFF, 0xFF99CCCC,
0xFF99CC99, 0xFF99CC66, 0xFF99CC33, 0xFF99CC00, 0xFF9999FF, 0xFF9999CC, 0xFF999999, 0xFF999966,
0xFF999933, 0xFF999900, 0xFF9966FF, 0xFF9966CC, 0xFF996699, 0xFF996666, 0xFF996633, 0xFF996600,
0xFF9933FF, 0xFF9933CC, 0xFF993399, 0xFF993366, 0xFF993333, 0xFF993300, 0xFF9900FF, 0xFF9900CC,
0xFF990099, 0xFF990066, 0xFF990033, 0xFF990000, 0xFF66FFFF, 0xFF66FFCC, 0xFF66FF99, 0xFF66FF66,
0xFF66FF33, 0xFF66FF00, 0xFF66CCFF, 0xFF66CCCC, 0xFF66CC99, 0xFF66CC66, 0xFF66CC33, 0xFF66CC00,
0xFF6699FF, 0xFF6699CC, 0xFF669999, 0xFF669966, 0xFF669933, 0xFF669900, 0xFF6666FF, 0xFF6666CC,
0xFF666699, 0xFF666666, 0xFF666633, 0xFF666600, 0xFF6633FF, 0xFF6633CC, 0xFF663399, 0xFF663366,
0xFF663333, 0xFF663300, 0xFF6600FF, 0xFF6600CC, 0xFF660099, 0xFF660066, 0xFF660033, 0xFF660000,
0xFF33FFFF, 0xFF33FFCC, 0xFF33FF99, 0xFF33FF66, 0xFF33FF33, 0xFF33FF00, 0xFF33CCFF, 0xFF33CCCC,
0xFF33CC99, 0xFF33CC66, 0xFF33CC33, 0xFF33CC00, 0xFF3399FF, 0xFF3399CC, 0xFF339999, 0xFF339966,
0xFF339933, 0xFF339900, 0xFF3366FF, 0xFF3366CC, 0xFF336699, 0xFF336666, 0xFF336633, 0xFF336600,
0xFF3333FF, 0xFF3333CC, 0xFF333399, 0xFF333366, 0xFF333333, 0xFF333300, 0xFF3300FF, 0xFF3300CC,
0xFF330099, 0xFF330066, 0xFF330033, 0xFF330000, 0xFF00FFFF, 0xFF00FFCC, 0xFF00FF99, 0xFF00FF66,
0xFF00FF33, 0xFF00FF00, 0xFF00CCFF, 0xFF00CCCC, 0xFF00CC99, 0xFF00CC66, 0xFF00CC33, 0xFF00CC00,
0xFF0099FF, 0xFF0099CC, 0xFF009999, 0xFF009966, 0xFF009933, 0xFF009900, 0xFF0066FF, 0xFF0066CC,
0xFF006699, 0xFF006666, 0xFF006633, 0xFF006600, 0xFF0033FF, 0xFF0033CC, 0xFF003399, 0xFF003366,
0xFF003333, 0xFF003300, 0xFF0000FF, 0xFF0000CC, 0xFF000099, 0xFF000066, 0xFF000033, 0xFFEE0000,
0xFFDD0000, 0xFFBB0000, 0xFFAA0000, 0xFF880000, 0xFF770000, 0xFF550000, 0xFF440000, 0xFF220000,
0xFF110000, 0xFF00EE00, 0xFF00DD00, 0xFF00BB00, 0xFF00AA00, 0xFF008800, 0xFF007700, 0xFF005500,
0xFF004400, 0xFF002200, 0xFF001100, 0xFF0000EE, 0xFF0000DD, 0xFF0000BB, 0xFF0000AA, 0xFF000088,
0xFF000077, 0xFF000055, 0xFF000044, 0xFF000022, 0xFF000011, 0xFFEEEEEE, 0xFFDDDDDD, 0xFFBBBBBB,
0xFFAAAAAA, 0xFF888888, 0xFF777777, 0xFF555555, 0xFF444444, 0xFF222222, 0xFF111111, 0xFF000000
};
public static final int[] COLORS_4BIT = {
0xFFFFFFFF, 0xFFFCF305, 0xFFFF6503, 0xFFDD0907, 0xFFF30885, 0xFF4700A5, 0xFF0000D4, 0xFF02ABEB,
0xFF1FB814, 0xFF006512, 0xFF562D05, 0xFF91713A, 0xFFC0C0C0, 0xFF808080, 0xFF404040, 0xFF000000
};
public static final int[] COLORS_2BIT = {
0xFFFFFFFF, 0xFF808080, 0xFFCCCCFF, 0xFF000000
};
public static final int[] COLORS_1BIT = {
0xFFFFFFFF, 0xFF000000
};
private static final char[] MACROMAN = {
'\u0000','\u0001','\u0002','\u0003','\u0004','\u0005','\u0006','\u0007',
'\u0008','\u0009','\n','\u000B','\u000C','\r','\u000E','\u000F',
'\u0010','\u0011','\u0012','\u0013','\u0014','\u0015','\u0016','\u0017',
'\u0018','\u0019','\u001A','\u001B','\u001C','\u001D','\u001E','\u001F',
'\u0020','\u0021','\u0022','\u0023','\u0024','\u0025','\u0026','\'',
'\u0028','\u0029','\u002A','\u002B','\u002C','\u002D','\u002E','\u002F',
'\u0030','\u0031','\u0032','\u0033','\u0034','\u0035','\u0036','\u0037',
'\u0038','\u0039','\u003A','\u003B','\u003C','\u003D','\u003E','\u003F',
'\u0040','\u0041','\u0042','\u0043','\u0044','\u0045','\u0046','\u0047',
'\u0048','\u0049','\u004A','\u004B','\u004C','\u004D','\u004E','\u004F',
'\u0050','\u0051','\u0052','\u0053','\u0054','\u0055','\u0056','\u0057',
'\u0058','\u0059','\u005A','\u005B','\\','\u005D','\u005E','\u005F',
'\u0060','\u0061','\u0062','\u0063','\u0064','\u0065','\u0066','\u0067',
'\u0068','\u0069','\u006A','\u006B','\u006C','\u006D','\u006E','\u006F',
'\u0070','\u0071','\u0072','\u0073','\u0074','\u0075','\u0076','\u0077',
'\u0078','\u0079','\u007A','\u007B','\u007C','\u007D','\u007E','\u007F',
'\u00C4','\u00C5','\u00C7','\u00C9','\u00D1','\u00D6','\u00DC','\u00E1',
'\u00E0','\u00E2','\u00E4','\u00E3','\u00E5','\u00E7','\u00E9','\u00E8',
'\u00EA','\u00EB','\u00ED','\u00EC','\u00EE','\u00EF','\u00F1','\u00F3',
'\u00F2','\u00F4','\u00F6','\u00F5','\u00FA','\u00F9','\u00FB','\u00FC',
'\u2020','\u00B0','\u00A2','\u00A3','\u00A7','\u2022','\u00B6','\u00DF',
'\u00AE','\u00A9','\u2122','\u00B4','\u00A8','\u2260','\u00C6','\u00D8',
'\u221E','\u00B1','\u2264','\u2265','\u00A5','\u00B5','\u2202','\u2211',
'\u220F','\u03C0','\u222B','\u00AA','\u00BA','\u03A9','\u00E6','\u00F8',
'\u00BF','\u00A1','\u00AC','\u221A','\u0192','\u2248','\u2206','\u00AB',
'\u00BB','\u2026','\u00A0','\u00C0','\u00C3','\u00D5','\u0152','\u0153',
'\u2013','\u2014','\u201C','\u201D','\u2018','\u2019','\u00F7','\u25CA',
'\u00FF','\u0178','\u2044','\u20AC','\u2039','\u203A','\uFB01','\uFB02',
'\u2021','\u00B7','\u201A','\u201E','\u2030','\u00C2','\u00CA','\u00C1',
'\u00CB','\u00C8','\u00CD','\u00CE','\u00CF','\u00CC','\u00D3','\u00D4',
'\uF8FF','\u00D2','\u00DA','\u00DB','\u00D9','\u0131','\u02C6','\u02DC',
'\u00AF','\u02D8','\u02D9','\u02DA','\u00B8','\u02DD','\u02DB','\u02C7',
};
}