[richfaces-svn-commits] JBoss Rich Faces SVN: r18809 - in sandbox/trunk/prototypes: indexed-png-transformation and 1 other directories.
richfaces-svn-commits at lists.jboss.org
richfaces-svn-commits at lists.jboss.org
Thu Aug 19 08:13:59 EDT 2010
Author: nbelaevski
Date: 2010-08-19 08:13:59 -0400 (Thu, 19 Aug 2010)
New Revision: 18809
Added:
sandbox/trunk/prototypes/indexed-png-transformation/
sandbox/trunk/prototypes/indexed-png-transformation/src/
sandbox/trunk/prototypes/indexed-png-transformation/src/Main.java
Log:
Initial import of Main class doing all the work
Added: sandbox/trunk/prototypes/indexed-png-transformation/src/Main.java
===================================================================
--- sandbox/trunk/prototypes/indexed-png-transformation/src/Main.java (rev 0)
+++ sandbox/trunk/prototypes/indexed-png-transformation/src/Main.java 2010-08-19 12:13:59 UTC (rev 18809)
@@ -0,0 +1,486 @@
+import java.awt.Color;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.nio.charset.Charset;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+
+public class Main {
+
+ private InputStream inChannel;
+
+ private OutputStream outChannel;
+
+ private Color[] colors = new Color[] {
+ Color.BLUE, Color.GREEN, Color.BLACK
+ };
+
+ private boolean isIndexed = false;
+
+ private Charset asciiCharset = Charset.forName("US-ASCII");
+
+ private static final int _8192 = 8192;
+
+ private int sectionLength;
+
+ private int imageWidth;
+
+ private byte[] lengthBytes = new byte[4];
+
+ private byte[] chunkTypeBytes = new byte[4];
+
+ private class Section {
+
+ protected void writeHeaderSectionData() throws IOException {
+ outChannel.write(lengthBytes);
+ outChannel.write(chunkTypeBytes);
+ }
+
+ protected void writeInt(int value) throws IOException {
+ byte[] bs = new byte[4];
+ ByteBuffer.wrap(bs).order(ByteOrder.BIG_ENDIAN).asIntBuffer().put(value);
+ outChannel.write(bs);
+ }
+
+ protected void writeSectionData() throws IOException {
+ byte[] bs = new byte[_8192];
+ int read = 0;
+ int remaining = sectionLength;
+
+ while ((read = inChannel.read(bs, 0, Math.min(remaining, bs.length))) > 0) {
+ outChannel.write(bs, 0, read);
+ remaining -= read;
+ }
+
+ if (remaining > 0) {
+ throw new IllegalArgumentException();
+ }
+
+ byte[] crc = new byte[4];
+ if (inChannel.read(crc) < crc.length) {
+ throw new IllegalArgumentException();
+ }
+
+ outChannel.write(crc);
+ }
+
+
+ public void write() throws IOException {
+ writeHeaderSectionData();
+ writeSectionData();
+ }
+ };
+
+ private class HeaderSection extends Section {
+
+ @Override
+ protected void writeSectionData() throws IOException {
+//// Width 4 bytes
+//// Height 4 bytes
+//// Bit depth 1 byte
+//// Colour type 1 byte
+//// Compression method 1 byte
+//// Filter method 1 byte
+//// Interlace method 1 byte
+
+ byte[] headerBytes = new byte[sectionLength];
+
+ if (inChannel.read(headerBytes) < headerBytes.length) {
+ throw new IllegalArgumentException();
+ }
+
+ if (headerBytes[8] != 8) {
+ throw new IllegalStateException("Color depth is not 8");
+ }
+
+ if (headerBytes[9] != 2 && headerBytes[9] != 3) {
+ throw new IllegalStateException("Unsupported color type");
+ }
+
+ imageWidth = ByteBuffer.wrap(headerBytes, 0, 4).order(ByteOrder.BIG_ENDIAN).asIntBuffer().get();
+
+ isIndexed = (headerBytes[9] == 3);
+
+ outChannel.write(headerBytes);
+
+ byte[] crc = new byte[4];
+ if (inChannel.read(crc) < crc.length) {
+ throw new IllegalArgumentException();
+ }
+
+ outChannel.write(crc);
+ }
+
+ };
+
+ private void transformColors(byte[] data, int offset, int length) {
+ float[] intensities = new float[3];
+
+ for (int i = offset; i < length + offset; i+= 3) {
+ float weight = 0;
+ for (int j = 0; j < intensities.length; j++) {
+ weight += (intensities[j] = ((float)(data[i + j] & 0xFF)) / 255);
+ }
+
+ float r = 0;
+ float g = 0;
+ float b = 0;
+
+ for (int j = 0; j < intensities.length; j++) {
+ r += intensities[j] * colors[j].getRed();
+ g += intensities[j] * colors[j].getGreen();
+ b += intensities[j] * colors[j].getBlue();
+ }
+
+ data[i] = (byte) (r);
+ data[i + 1] = (byte) (g);
+ data[i + 2] = (byte) (b);
+ }
+ }
+
+ private class PaletteSection extends Section {
+ @Override
+ protected void writeSectionData() throws IOException {
+ if (!isIndexed) {
+ super.writeSectionData();
+ } else {
+ byte[] data = new byte[2000 * 3];
+ int read;
+ int remaining = sectionLength;
+
+ assert (data.length < _8192);
+
+ CRC32 crc32 = new CRC32();
+ crc32.update(chunkTypeBytes);
+
+ while ((read = (inChannel.read(data, 0, Math.min(remaining, data.length)))) > 0) {
+ remaining -= read;
+
+ transformColors(data, 0, read);
+
+ outChannel.write(data, 0, read);
+ crc32.update(data, 0, read);
+ }
+
+ if (remaining > 0) {
+ throw new IllegalArgumentException();
+ }
+
+ inChannel.skip(4);
+
+ writeInt((int) crc32.getValue());
+ }
+ }
+ };
+
+ private class LimitedInputStream extends FilterInputStream {
+
+ private int remaining;
+
+ protected LimitedInputStream() {
+ super(inChannel);
+
+ this.remaining = sectionLength;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return Math.min(super.available(), this.remaining);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (this.remaining > 0) {
+ int read = super.read();
+ if (read != -1) {
+ this.remaining--;
+ }
+
+ return read;
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int read = super.read(b, 0, Math.min(len, this.remaining));
+ if (read > 0) {
+ this.remaining -= read;
+ }
+
+ return read;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ long toSkip = Math.min(this.remaining, n);
+ long skipped = super.skip(toSkip);
+
+ if (skipped > 0) {
+ this.remaining -= skipped;
+ }
+
+ return skipped;
+ }
+ };
+
+ private class DataSection extends Section {
+
+ private byte paeth(byte a, byte b, byte c) {
+ int p = (a & 0xFF) + (b & 0xFF) - (c & 0xFF);
+ int pa = Math.abs(p - a);
+ int pb = Math.abs(p - b);
+ int pc = Math.abs(p - c);
+
+ int pr;
+
+ if (pa <= pb && pa <= pc) {
+ pr = a;
+ } else if (pb <= pc) {
+ pr = b;
+ } else {
+ pr = c;
+ }
+
+ return (byte) pr;
+ };
+
+ private class Filter {
+ byte a = 0;
+ byte b = 0;
+ byte c = 0;
+
+ byte oa = 0;
+ byte ob = 0;
+ byte oc = 0;
+
+ int step = 3;
+ protected int idx;
+
+ byte[] bs;
+ byte[] ps;
+
+ public void setIdx(int idx) {
+ this.idx = idx;
+
+ oa = a;
+ ob = b;
+ oc = c;
+
+ b = ps[idx];
+ if (idx > step) {
+ a = bs[idx - step];
+ c = ps[idx - step];
+ }
+ }
+
+ public void next() {
+ setIdx(idx += step);
+ }
+ };
+
+ private class SubFilter extends Filter {
+ @Override
+ public void next() {
+ bs[idx] = (byte)((bs[idx] & 0xFF) + (a & 0xFF) - (oa & 0xFF));
+ setIdx(idx + step);
+ }
+ };
+
+ private class UpFilter extends Filter {
+ @Override
+ public void next() {
+ bs[idx] = (byte)((bs[idx] & 0xFF) + (b & 0xFF) - (ob & 0xFF));
+ setIdx(idx + step);
+ }
+ };
+
+ private class PaethFilter extends Filter {
+ @Override
+ public void next() {
+ bs[idx] = (byte) (paeth(a, b, c) - paeth(oa, ob, oc) + (bs[idx] & 0xFF));
+ setIdx(idx + step);
+ }
+ }
+
+ private void reconstruct(byte[] bs, byte[] ps) {
+ Filter[] filters = new Filter[3];
+
+ for (int i = 0; i < filters.length; i++) {
+ switch (bs[0]) {
+ case 0:
+ filters[i] = new Filter();
+ break;
+ case 1:
+ filters[i] = new SubFilter();
+ break;
+ case 2:
+ filters[i] = new UpFilter();
+ break;
+ case 4:
+ filters[i] = new PaethFilter();
+ break;
+
+ default:
+ System.out.println(bs[0]);
+ throw new IllegalArgumentException();
+ }
+
+ filters[i].bs = bs;
+ filters[i].ps = ps;
+ filters[i].step = 3;
+
+ filters[i].setIdx(1 + i);
+ }
+
+ for (int i = 1; i < (bs.length - 1) / 3; i++) {
+ for (Filter filter : filters) {
+ filter.next();
+ }
+ }
+
+ bs[0] = 0;
+ }
+
+ @Override
+ public void write() throws IOException {
+ if (isIndexed) {
+ super.write();
+ } else {
+ byte[] ps = new byte[imageWidth * 3 + 1];
+ byte[] bs = new byte[imageWidth * 3 + 1];
+
+ assert (bs.length < _8192);
+
+ int read = 0;
+
+ InputStream inflaterInputStream = new BufferedInputStream(new InflaterInputStream(new LimitedInputStream(), new Inflater(), 2048), _8192);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(sectionLength);
+ DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(baos, new Deflater(), 2048);
+
+ while ((read = (inflaterInputStream.read(bs)) ) > 0) {
+ reconstruct(bs, ps);
+ transformColors(bs, 1, read - 1);
+
+ deflaterOutputStream.write(bs, 0, read);
+
+ byte[] swapVar = bs;
+ bs = ps;
+ ps = swapVar;
+ }
+
+ deflaterOutputStream.finish();
+
+ byte[] compressedSectionBytes = baos.toByteArray();
+ writeInt(compressedSectionBytes.length);
+
+ CRC32 crc32 = new CRC32();
+ outChannel.write(chunkTypeBytes);
+ crc32.update(chunkTypeBytes);
+
+ if (inChannel.skip(4) < 4) {
+ throw new IllegalArgumentException();
+ }
+
+ outChannel.write(compressedSectionBytes);
+
+ writeInt((int) crc32.getValue());
+ }
+ }
+
+ };
+
+ private Section readNextSection() throws IOException {
+ int read = inChannel.read(lengthBytes);
+ if (read != -1) {
+ if (read < lengthBytes.length) {
+ throw new IllegalArgumentException();
+ }
+
+ if (inChannel.read(chunkTypeBytes) < chunkTypeBytes.length) {
+ throw new IllegalArgumentException();
+ }
+
+ IntBuffer lengthBuffer = ByteBuffer.wrap(lengthBytes).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
+ sectionLength = lengthBuffer.get(0);
+ String chunkTypeString = new String(chunkTypeBytes, asciiCharset);
+
+ if ("IHDR".equals(chunkTypeString)) {
+ return new HeaderSection();
+ } else if ("PLTE".equals(chunkTypeString)) {
+ return new PaletteSection();
+ } else if ("IDAT".equals(chunkTypeString)) {
+ return new DataSection();
+ } else {
+ return new Section();
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private void process(File inFile, File outFile) throws Exception {
+ try {
+ inChannel = new BufferedInputStream(new FileInputStream(inFile), _8192);
+ outChannel = new FileOutputStream(outFile);
+
+ //skip 8-bytes of header
+ byte[] bs = new byte[8];
+ if (inChannel.read(bs) < bs.length) {
+ throw new IllegalArgumentException();
+ }
+ outChannel.write(bs);
+
+ Section section = null;
+ while ((section = readNextSection()) != null) {
+ section.write();
+ }
+ } finally {
+ inChannel.close();
+ outChannel.close();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ File outFile = new File(args[1]);
+ outFile.delete();
+ outFile.createNewFile();
+
+ new Main().process(new File(args[0]), outFile);
+ }
+}
More information about the richfaces-svn-commits
mailing list