001:
002:
003:
004:
005:
006:
007:
008: import java.io.*;
009: import java.awt.image.*;
010: import java.awt.*;
011: import java.awt.Image;
012: import java.util.zip.*;
013:
014: class BeauchampEncoder
015: {
016: public static final boolean ENCODE_ALPHA = true;
017: public static final boolean NO_ALPHA = false;
018: public static final int FILTER_NONE = 0;
019: public static final int FILTER_SUB = 1;
020: public static final int FILTER_UP = 2;
021: public static final int FILTER_LAST = 2;
022: protected byte pngBytes[];
023: protected byte priorRow[];
024: protected byte leftBytes[];
025: protected int width;
026: protected int height;
027: protected int bytePos;
028: protected int maxPos;
029: protected int hdrPos;
030: protected int dataPos;
031: protected int endPos;
032: protected CRC32 crc;
033: protected long crcValue;
034: protected boolean encodeAlpha;
035: protected int filter;
036: protected int bytesPerPixel;
037: protected int compressionLevel;
038: public BeauchampEncoder()
039: {
040: this(null, false, 0, 0);
041: }
042:
043: public BeauchampEncoder(BufferedImage bufferedimage)
044: {
045: this(bufferedimage, false, 0, 0);
046: }
047:
048: public BeauchampEncoder(BufferedImage bufferedimage, boolean flag)
049: {
050: this(bufferedimage, flag, 0, 0);
051: }
052:
053: public BeauchampEncoder(BufferedImage bufferedimage, boolean flag, int i)
054: {
055: this(bufferedimage, flag, i, 0);
056: }
057:
058: public BeauchampEncoder(BufferedImage bufferedimage, boolean flag, int i, int j)
059: {
060: crc = new CRC32();
061: encodeAlpha = flag;
062: setFilter(i);
063: if(j >= 0 && j <= 9)
064: compressionLevel = j;
065: image = bufferedimage;
066:
067:
068: }
069:
070: protected boolean establishStorageInfo()
071: {
072: wRaster = image.getRaster();
073: int i = wRaster.getNumDataElements();
074: tType = wRaster.getTransferType();
075: if(tType == 0 && i == 4 || tType == 3 && i == 1)
076: bytesPerPixel = encodeAlpha ? 4 : 3;
077: else
078: if(tType == 0 && i == 1)
079: {
080: bytesPerPixel = 1;
081: encodeAlpha = false;
082: } else
083: {
084: return false;
085: }
086: return true;
087: }
088:
089: public byte[] pngEncode()
090: {
091: return pngEncode(encodeAlpha);
092: }
093:
094: public byte[] pngEncode(boolean flag)
095: {
096: byte abyte0[] = {
097: -119, 80, 78, 71, 13, 10, 26, 10
098: };
099: if(image == null)
100: return null;
101: width = image.getWidth(null);
102: height = image.getHeight(null);
103: image = image;
104: if(!establishStorageInfo())
105: return null;
106: pngBytes = new byte[(width + 1) * height * 3 + 200];
107: maxPos = 0;
108: bytePos = writeBytes(abyte0, 0);
109: hdrPos = bytePos;
110: writeHeader();
111: dataPos = bytePos;
112: if(writeImageData())
113: {
114: writeEnd();
115: pngBytes = resizeByteArray(pngBytes, maxPos);
116: } else
117: {
118: pngBytes = null;
119: }
120: return pngBytes;
121: }
122:
123: public void setImage(BufferedImage bufferedimage)
124: {
125: image = bufferedimage;
126: pngBytes = null;
127: }
128:
129: protected void writeHeader()
130: {
131: int i = bytePos = writeInt4(13, bytePos);
132: bytePos = writeString("IHDR", bytePos);
133: width = image.getWidth(null);
134: height = image.getHeight(null);
135: bytePos = writeInt4(width, bytePos);
136: bytePos = writeInt4(height, bytePos);
137: bytePos = writeByte(8, bytePos);
138: if(bytesPerPixel != 1)
139: bytePos = writeByte(encodeAlpha ? 6 : 2, bytePos);
140: else
141: bytePos = writeByte(3, bytePos);
142: bytePos = writeByte(0, bytePos);
143: bytePos = writeByte(0, bytePos);
144: bytePos = writeByte(0, bytePos);
145: crc.reset();
146: crc.update(pngBytes, i, bytePos - i);
147: crcValue = crc.getValue();
148: bytePos = writeInt4((int)crcValue, bytePos);
149: }
150:
151: protected boolean writeImageData()
152: {
153: int i = height;
154: int j = 0;
155: Deflater deflater = new Deflater(compressionLevel);
156: ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(1024);
157: DeflaterOutputStream deflateroutputstream = new DeflaterOutputStream(bytearrayoutputstream, deflater);
158: if(bytesPerPixel == 1)
159: writePalette((IndexColorModel)image.getColorModel());
160: try
161: {
162: int k;
163: for(; i > 0; i -= k)
164: {
165: k = Math.min(32767 / (width * (bytesPerPixel + 1)), i);
166: byte abyte0[] = new byte[width * k * bytesPerPixel + k];
167: if(filter == 1)
168: leftBytes = new byte[16];
169: if(filter == 2)
170: priorRow = new byte[width * bytesPerPixel];
171: byte abyte2[];
172: int ai[];
173: if(tType == 0)
174: {
175: abyte2 = (byte[])wRaster.getDataElements(0, j, width, k, null);
176: ai = null;
177: } else
178: {
179: ai = (int[])wRaster.getDataElements(0, j, width, k, null);
180: abyte2 = null;
181: }
182: int l = 0;
183: int j1 = 0;
184: int i1 = 1;
185: for(int l1 = 0; l1 < width * k; l1++)
186: {
187: if(l1 % width == 0)
188: {
189: abyte0[l++] = (byte)filter;
190: i1 = l;
191: }
192: if(bytesPerPixel == 1)
193: abyte0[l++] = abyte2[j1++];
194: else
195: if(tType == 0)
196: {
197: abyte0[l++] = abyte2[j1++];
198: abyte0[l++] = abyte2[j1++];
199: abyte0[l++] = abyte2[j1++];
200: if(encodeAlpha)
201: abyte0[l++] = abyte2[j1++];
202: else
203: j1++;
204: } else
205: {
206: abyte0[l++] = (byte)(ai[j1] >> 16 & 0xff);
207: abyte0[l++] = (byte)(ai[j1] >> 8 & 0xff);
208: abyte0[l++] = (byte)(ai[j1] & 0xff);
209: if(encodeAlpha)
210: abyte0[l++] = (byte)(ai[j1] >> 24 & 0xff);
211: j1++;
212: }
213: if(l1 % width == width - 1 && filter != 0)
214: {
215: if(filter == 1)
216: filterSub(abyte0, i1, width);
217: if(filter == 2)
218: filterUp(abyte0, i1, width);
219: }
220: }
221:
222: deflateroutputstream.write(abyte0, 0, l);
223: j += k;
224: }
225:
226: deflateroutputstream.close();
227: byte abyte1[] = bytearrayoutputstream.toByteArray();
228: int k1 = abyte1.length;
229: crc.reset();
230: bytePos = writeInt4(k1, bytePos);
231: bytePos = writeString("IDAT", bytePos);
232: crc.update("IDAT".getBytes());
233: bytePos = writeBytes(abyte1, k1, bytePos);
234: crc.update(abyte1, 0, k1);
235: crcValue = crc.getValue();
236: bytePos = writeInt4((int)crcValue, bytePos);
237: deflater.finish();
238: return true;
239: }
240: catch(IOException ioexception)
241: {
242: System.err.println(ioexception.toString());
243: }
244: return false;
245: }
246:
247: protected void writePalette(IndexColorModel indexcolormodel)
248: {
249: byte abyte0[] = new byte[256];
250: byte abyte1[] = new byte[256];
251: byte abyte2[] = new byte[256];
252: byte abyte3[] = new byte[768];
253: indexcolormodel.getReds(abyte0);
254: indexcolormodel.getGreens(abyte1);
255: indexcolormodel.getBlues(abyte2);
256: for(int i = 0; i < 256; i++)
257: {
258: abyte3[i * 3] = abyte0[i];
259: abyte3[i * 3 + 1] = abyte1[i];
260: abyte3[i * 3 + 2] = abyte2[i];
261: }
262:
263: bytePos = writeInt4(768, bytePos);
264: bytePos = writeString("PLTE", bytePos);
265: crc.reset();
266: crc.update("PLTE".getBytes());
267: bytePos = writeBytes(abyte3, bytePos);
268: crc.update(abyte3);
269: crcValue = crc.getValue();
270: bytePos = writeInt4((int)crcValue, bytePos);
271: }
272:
273: protected void filterSub(byte abyte0[], int i, int j)
274: {
275: int l = bytesPerPixel;
276: int i1 = i + l;
277: int j1 = j * bytesPerPixel;
278: int k1 = l;
279: int l1 = 0;
280: for(int k = i1; k < i + j1; k++)
281: {
282: leftBytes[k1] = abyte0[k];
283: abyte0[k] = (byte)((abyte0[k] - leftBytes[l1]) % 256);
284: k1 = (k1 + 1) % 15;
285: l1 = (l1 + 1) % 15;
286: }
287:
288: }
289:
290: protected void filterUp(byte abyte0[], int i, int j)
291: {
292: int l = j * bytesPerPixel;
293: for(int k = 0; k < l; k++)
294: {
295: byte byte0 = abyte0[i + k];
296: abyte0[i + k] = (byte)((abyte0[i + k] - priorRow[k]) % 256);
297: priorRow[k] = byte0;
298: }
299:
300: }
301:
302: public int getCompressionLevel()
303: {
304: return compressionLevel;
305: }
306:
307: public boolean getEncodeAlpha()
308: {
309: return encodeAlpha;
310: }
311:
312: public int getFilter()
313: {
314: return filter;
315: }
316:
317:
318: protected byte[] resizeByteArray(byte abyte0[], int i)
319: {
320: byte abyte1[] = new byte[i];
321: int j = abyte0.length;
322: System.arraycopy(abyte0, 0, abyte1, 0, Math.min(j, i));
323: return abyte1;
324: }
325:
326: public void setCompressionLevel(int i)
327: {
328: if(i >= 0 && i <= 9)
329: compressionLevel = i;
330: }
331:
332: public void setEncodeAlpha(boolean flag)
333: {
334: encodeAlpha = flag;
335: }
336:
337: public void setFilter(int i)
338: {
339: filter = 0;
340: if(i <= 2)
341: filter = i;
342: }
343:
344: protected int writeByte(int i, int j)
345: {
346: byte abyte0[] = {
347: (byte)i
348: };
349: return writeBytes(abyte0, j);
350: }
351:
352: protected int writeBytes(byte abyte0[], int i)
353: {
354: maxPos = Math.max(maxPos, i + abyte0.length);
355: if(abyte0.length + i > pngBytes.length)
356: pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, abyte0.length));
357: System.arraycopy(abyte0, 0, pngBytes, i, abyte0.length);
358: return i + abyte0.length;
359: }
360:
361: protected int writeBytes(byte abyte0[], int i, int j)
362: {
363: maxPos = Math.max(maxPos, j + i);
364: if(i + j > pngBytes.length)
365: pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, i));
366: System.arraycopy(abyte0, 0, pngBytes, j, i);
367: return j + i;
368: }
369:
370: protected void writeEnd()
371: {
372: bytePos = writeInt4(0, bytePos);
373: bytePos = writeString("IEND", bytePos);
374: crc.reset();
375: crc.update("IEND".getBytes());
376: crcValue = crc.getValue();
377: bytePos = writeInt4((int)crcValue, bytePos);
378: }
379:
380: protected int writeInt2(int i, int j)
381: {
382: byte abyte0[] = {
383: (byte)(i >> 8 & 0xff), (byte)(i & 0xff)
384: };
385: return writeBytes(abyte0, j);
386: }
387:
388: protected int writeInt4(int i, int j)
389: {
390: byte abyte0[] = {
391: (byte)(i >> 24 & 0xff), (byte)(i >> 16 & 0xff), (byte)(i >> 8 & 0xff), (byte)(i & 0xff)
392: };
393: return writeBytes(abyte0, j);
394: }
395:
396: protected int writeString(String s, int i)
397: {
398: return writeBytes(s.getBytes(), i);
399: }
400:
401:
402: protected BufferedImage image;
403: protected WritableRaster wRaster;
404: protected int tType;
405: }
406:
407:
408: public final class BeauchampKoala2PNG {
409:
410: final byte unused[] =new byte[2];
411: final byte bitmap[] =new byte[8000];
412: final byte mcolor[][] =new byte [25][40];
413: final byte color[][] = new byte[25][40];
414: final byte background[] =new byte[1];
415:
416:
417: static final Color[] c64Colors = new Color[] {
418: new Color( 0x00, 0x00, 0x00),
419: new Color( 0xff, 0xff, 0xff),
420: new Color( 0x88, 0x00, 0x00),
421: new Color( 0xaa, 0xff, 0xee),
422: new Color( 0xcc, 0x44, 0xcc),
423: new Color( 0x00, 0xcc, 0x55),
424: new Color( 0x00, 0x00, 0xaa),
425: new Color( 0xee, 0xee, 0x77),
426: new Color( 0xdd, 0x88, 0x55),
427: new Color( 0x66, 0x44, 0x00),
428: new Color( 0xff, 0x77, 0x77),
429: new Color( 0x33, 0x33, 0x33),
430: new Color( 0x77, 0x77, 0x77),
431: new Color( 0xaa, 0xff, 0x66),
432: new Color( 0x00, 0x88, 0xff),
433: new Color( 0xbb, 0xbb, 0xbb)
434: };
435:
436: public static final int koala_width= 320;
437: public static final int koala_height= 200;
438: public static final int koala_colors=16;
439:
440: static byte low_nibble(byte x) {
441: return (byte)((x) & 0x0f);
442: }
443:
444: static byte high_nibble(byte x) {
445: return (byte )(((x) >> 4) & 0x0f);
446: }
447:
448: byte getColor(byte row, byte col, int index) {
449:
450: if (index == 0) {
451: return low_nibble(background[0]);
452: }
453: else if (index == 1) {
454: return high_nibble(mcolor[row][col]);
455: }
456: else if (index == 2) {
457: return low_nibble(mcolor[row][col]);
458: }
459: else
460: return low_nibble(color[row][col]);
461: }
462:
463: byte[] convertFile(String theFile) {
464: try {
465: int pixelDepth=24;
466: FileInputStream inFile = new FileInputStream(theFile);
467:
468: int read = inFile.read(unused);
469: read = inFile.read(bitmap);
470:
471: for (int i = 0; i < 25; i++) {
472: read = inFile.read(mcolor[i]);
473: }
474:
475: for (int i = 0; i < 25; i++) {
476: read = inFile.read(color[i]);
477: }
478:
479: read = inFile.read(background);
480:
481: BufferedImage myImage =
482: new BufferedImage(
483: koala_width,
484: koala_height,
485: (pixelDepth == 8) ? BufferedImage.TYPE_BYTE_INDEXED : BufferedImage.TYPE_4BYTE_ABGR );
486: Graphics g;
487:
488: g = myImage.getGraphics();
489:
490: g.fillRect(0,0,koala_width,koala_height);
491:
492: int row = 0;
493: int col = 0 ;
494: int p = 0;
495: for (row = 0; row < 200; row++) {
496: int row8 = row / 8;
497:
498:
499: int pos = (row8) *320 + row % 8;
500:
501: int x = 0;
502: byte index = 0;
503: byte oldindex = -1;
504: for (col = 0; col < 40; col++) {
505: p = bitmap[pos];
506: if (p < 0) {
507: p +=256;
508: }
509:
510: for (int i = 0; i < 4; i++) {
511:
512: oldindex = index;
513: index = getColor((byte)(row8), (byte)col, (p & 3));
514:
515: g.setColor(c64Colors[index]);
516:
517: g.drawLine(x+6-i*2,row,x+6-i*2+1,row);
518: p >>= 2;
519: }
520:
521: x += 8;
522: pos += 8;
523: }
524: }
525:
526: int compressionLevel=9;
527:
528: byte pngBytes[];
529: int filter = 0;
530: boolean encodeAlpha= false;
531: BeauchampEncoder png = new BeauchampEncoder(
532: myImage,
533: (encodeAlpha) ? BeauchampEncoder.ENCODE_ALPHA : BeauchampEncoder.NO_ALPHA,
534: filter, compressionLevel );
535: pngBytes = png.pngEncode();
536:
537: return pngBytes;
538:
539: }
540: catch (Exception e) {
541: e.printStackTrace();
542: return null;
543:
544: }
545:
546: }
547:
548: public static void main (String[] args) {
549: try {
550: if (args.length < 2) {
551: System.out.print( new String(new BeauchampKoala2PNG().convertFile(args[0])) );
552: System.exit(0);
553: }
554: else {
555: FileOutputStream outfile = new FileOutputStream(args[1]);
556: outfile.write(new BeauchampKoala2PNG().convertFile(args[0]) );
557: System.exit(0);
558: }
559: }
560: catch (IndexOutOfBoundsException e) {
561: System.err.println("Parameters: [1] koa-file [2] png-file");
562: System.err.println("http://www.beauchamp.de/cbm");
563: System.err.println("You forgot to specify the filenames !");
564: }
565: catch (Exception e) {
566: System.err.println("Parameters: [1] koa-file [2] png-file");
567: System.err.println("http://www.beauchamp.de/cbm");
568: System.err.println("Some other exception occured!");
569: e.printStackTrace(System.err);
570: }
571:
572: }
573:
574: }
575:
576:
577:
578: