public static byte[] createPNGdata(int[] rgb, int w, int h) {
int deepth = 0;
int[] palette = paletteBuild(rgb);
deepth = TinaLib.sqrt(palette.length);
int j = 1;
for (int i = 0; i < deepth; i++)
j = j << i;
if(j<palette.length)deepth++;
return createPNGdata(rgb, palette, w, h, deepth);
}
public static byte[] createPNGdata(int[] rgb, int w, int h, int deepth) {
int[] palette = paletteBuild(rgb, deepth);
return createPNGdata(rgb, palette, w, h, deepth);
}
public static byte[] createPNGdata(int[] rgb, int[] paletteRgb, int w, int h, int deepth) {
int wid = w * deepth % 8 != 0 ? w * deepth / 8 + 2 : w * deepth / 8 + 1;
byte[] ImageData = new byte[80 + paletteRgb.length * 3 + ((paletteRgb[0] & 0xFF000000) == 0 ? 13 : 0) + wid * h];
int wPoint = 0, crc_s;
wPoint += IOutil.writeInt(0x89504e47, ImageData, wPoint);// png标头
wPoint += IOutil.writeInt(0x0d0a1a0a, ImageData, wPoint);// png标头
wPoint += IOutil.writeInt(13, ImageData, wPoint);// IHDR 块长度
crc_s = wPoint;
wPoint += IOutil.writeInt(0x49484452, ImageData, wPoint);// IHDR标头
wPoint += IOutil.writeInt(w, ImageData, wPoint);// width
wPoint += IOutil.writeInt(h, ImageData, wPoint);// height
wPoint += IOutil.writeByte(deepth, ImageData, wPoint);// color depth
wPoint += IOutil.writeInt(0x03000000, ImageData, wPoint);// 填充信息
wPoint += IOutil.writeInt(IOutil.checksum(ImageData, crc_s, 17), ImageData, wPoint);// IHDR CRC
wPoint += paletteData(paletteRgb, ImageData, wPoint);
if ((paletteRgb[0] & 0xFF000000) == 0) { // trns;
wPoint += IOutil.writeInt(0x00000001, ImageData, wPoint);
wPoint += IOutil.writeInt(0x74524e53, ImageData, wPoint);
wPoint += IOutil.writeByte(0x00, ImageData, wPoint);
wPoint += IOutil.writeInt(0x40e6d866, ImageData, wPoint);
}
wPoint += idataBuild(rgb, paletteRgb, ImageData, deepth, w, h, wPoint);
wPoint += IOutil.writeInt(0x00000000, ImageData, wPoint);// IEND 块长
wPoint += IOutil.writeInt(0x49454E44, ImageData, wPoint);// IEND 标头
wPoint += IOutil.writeInt(0xAE426082, ImageData, wPoint);// IEND CRC
return ImageData;
}
private static int[] paletteBuild(int[] rgb, int deepth) {
int[] palette = new int[(1 << deepth)];
for (int i = 0; i < palette.length; i++)
palette[i] = 0xFF000000;
int colorCount = 0;
int color;
for (int i = 0; i < rgb.length; i++) {
if (colorCount >= (1 << deepth)) break;
color = rgb[i] & 0xFFFFFFFF;
if (TinaLib.binarySearch(palette, color, false) < 0) {
palette[colorCount++] = color;
TinaLib.sort(palette, false);
}
}
int[] data = new int[colorCount];
System.arraycopy(palette, 0, data, 0, colorCount);
return data;
}
private static int[] paletteBuild(int[] rgb) {
int[] palette = new int[256];
for (int i = 0; i < palette.length; i++)
palette[i] = 0xFF000000;
int colorCount = 0;
int color;
for (int i = 0; i < rgb.length; i++) {
color = rgb[i] & 0xFFFFFFFF;
if (TinaLib.binarySearch(palette, color, false) < 0) {
palette[colorCount++] = color;
TinaLib.sort(palette, false);
}
}
int[] data = new int[colorCount];
System.arraycopy(palette, 0, data, 0, colorCount);
return data;
}
private static int paletteData(int[] palette, byte[] buf, int off) {
int wPoint = off;
wPoint += IOutil.writeInt(palette.length * 3, buf, wPoint);
int crc_s = wPoint;
wPoint += IOutil.writeInt(0x504C5445, buf, wPoint);
for (int i = 0; i < palette.length; i++) {
buf[wPoint++] = (byte) ((palette[i] & 0xFF0000) >> 16);
buf[wPoint++] = (byte) ((palette[i] & 0xFF00) >> 8);
buf[wPoint++] = (byte) (palette[i] & 0xFF);
}
wPoint += IOutil.writeInt(IOutil.checksum(buf, crc_s, wPoint - crc_s), buf, wPoint);
return palette.length * 3+12;
}
private static int idataBuild(int[] rgb, int[] palette, byte[] buf, int deepth, int w, int h, int off_s) {
int wid = w * deepth % 8 != 0 ? w * deepth / 8 + 2 : w * deepth / 8 + 1;
int wPoint = off_s, crc_s;
int length = wid * h;
int off = 64;
long index, idxUSI = 0;
wPoint += IOutil.writeInt(length + 11, buf, wPoint);// idata 长度
crc_s = wPoint;
wPoint += IOutil.writeInt(0x49444154, buf, wPoint);// idata 标记头
// Lz77 无压缩固定头
wPoint += IOutil.writeByte(0x78, buf, wPoint);
wPoint += IOutil.writeByte(0xda, buf, wPoint);
wPoint += IOutil.writeByte(0x1, buf, wPoint);
// Lz77 HLen
wPoint += IOutil.writeByte(length & 0xFF, buf, wPoint);
wPoint += IOutil.writeByte((length & 0xFF00) >>> 8, buf, wPoint);
wPoint += IOutil.writeByte((length ^ 0xFFFF) & 0xFF, buf, wPoint);
wPoint += IOutil.writeByte(((length ^ 0xFFFF) & 0xFF00) >>> 8, buf, wPoint);
for (int y = 0; y < h; y++)
for (int x = 0, x0 = 0; x < w; x++) {
if (x0 == 0) buf[wPoint + y * wid + x0++] = 0;
index = TinaLib.binarySearch(palette, rgb[y * w + x], false);
idxUSI |= index << (off -= deepth);
if (off <= 64 - (deepth * w)) {
for (int j = 0; j < deepth; j++)
buf[wPoint + y * wid + x0++] = (byte) ((idxUSI >>> (56 - j * 8)) & 0xFF);
idxUSI = 0;
off = 64;
}
}
wPoint += IOutil.writeInt(IOutil.Adler32(buf, wPoint, length), buf, wPoint+length);
wPoint+=length;
IOutil.writeInt(IOutil.checksum(buf, crc_s, wPoint - crc_s), buf, wPoint);
return length + 23;
}
public final class IOutil
{
public static int writeInt(int v, byte[] b, int off) {
b[off] = (byte) (0xFF & (v >> 24));
b[off + 1] = (byte) (0xFF & (v >> 16));
b[off + 2] = (byte) (0xFF & (v >> 8));
b[off + 3] = (byte) (0xFF & v);
return 4;
}
public static int writeShort(int v, byte[] b, int off) {
b[off] = (byte) (0xFF & (v >> 8));
b[off + 1] = (byte) (0xFF & v);
return 2;
}
public static int writeByte(int v, byte[] b, int off) {
b[off] = (byte) v;
return 1;
}
public static int readShort(byte[] src, int off) {
return (src[off] & 0xFF) << 8 | (src[off + 1] & 0xFF);
}
public static int readInt(byte[] src, int off) {
return (src[off] & 0xFF) << 24 | (src[off + 1] & 0xFF) << 16 | (src[off + 2] & 0xFF) << 8 | (src[off + 3] & 0xFF);
}
private static int[] crc_t;// CRC table
private static void mk() {
int c, k;
crc_t = new int[256];
for (int n = 0; n < 256; n++) {
c = n;
for (k = 0; k < 8; k++)
c = (c & 1) == 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
crc_t[n] = c;
}
}
private static int update(byte[] buf, int off, int len) {
int c = 0xffffffff;
int n;
if (crc_t == null) mk();
for (n = off; n < len + off; n++) {
c = crc_t[(c ^ buf[n]) & 0xff] ^ (c >>> 8);
}
return c;
}
public static int checksum(byte[] buf, int off, int len) {
return update(buf, off, len) ^ 0xffffffff;
}
public static void releaseTable() {
if (crc_t != null) crc_t = null;
System.gc();
Thread.yield();
}
public static int Adler32(byte[] buf, int off, int len) {
int s1 = 1 & 0x0000FFFF;
int s2 = (1 >> 16) & 0x0000FFFF;
len += off;
for (int j = off; j < len; j++) {
s1 += (buf[j] & 0x000000FF);
s2 += s1;
}
s1 = s1 % 0xFFF1;
s2 = s2 % 0xFFF1;
return (int) ((s2 << 16) & 0xFFFF0000) | (int) (s1 & 0x0000FFFF);
}
}
|