001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.internal.image;
011:
012: import java.io.ByteArrayOutputStream;
013: import java.io.IOException;
014: import java.io.OutputStream;
015:
016: import org.eclipse.swt.SWT;
017: import org.eclipse.swt.graphics.ImageData;
018: import org.eclipse.swt.graphics.ImageLoader;
019: import org.eclipse.swt.graphics.RGB;
020: import org.eclipse.swt.internal.Compatibility;
021:
022: final class PngEncoder extends Object {
023:
024: static final byte SIGNATURE[] = { (byte) '\211', (byte) 'P',
025: (byte) 'N', (byte) 'G', (byte) '\r', (byte) '\n',
026: (byte) '\032', (byte) '\n' };
027: static final byte TAG_IHDR[] = { (byte) 'I', (byte) 'H',
028: (byte) 'D', (byte) 'R' };
029: static final byte TAG_PLTE[] = { (byte) 'P', (byte) 'L',
030: (byte) 'T', (byte) 'E' };
031: static final byte TAG_TRNS[] = { (byte) 't', (byte) 'R',
032: (byte) 'N', (byte) 'S' };
033: static final byte TAG_IDAT[] = { (byte) 'I', (byte) 'D',
034: (byte) 'A', (byte) 'T' };
035: static final byte TAG_IEND[] = { (byte) 'I', (byte) 'E',
036: (byte) 'N', (byte) 'D' };
037:
038: ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
039: PngChunk chunk;
040:
041: ImageLoader loader;
042: ImageData data;
043: int transparencyType;
044:
045: int width, height, bitDepth, colorType;
046:
047: int compressionMethod = 0;
048: int filterMethod = 0;
049: int interlaceMethod = 0;
050:
051: public PngEncoder(ImageLoader loader) {
052:
053: this .loader = loader;
054: this .data = loader.data[0];
055: this .transparencyType = data.getTransparencyType();
056:
057: this .width = data.width;
058: this .height = data.height;
059:
060: this .bitDepth = 8;
061:
062: this .colorType = 2;
063:
064: if (data.palette.isDirect) {
065: if (transparencyType == SWT.TRANSPARENCY_ALPHA) {
066: this .colorType = 6;
067: }
068: } else {
069: this .colorType = 3;
070: }
071:
072: if (!(colorType == 2 || colorType == 3 || colorType == 6))
073: SWT.error(SWT.ERROR_INVALID_IMAGE);
074:
075: }
076:
077: void writeShort(ByteArrayOutputStream baos, int theShort) {
078:
079: byte byte1 = (byte) ((theShort >> 8) & 0xff);
080: byte byte2 = (byte) (theShort & 0xff);
081: byte[] temp = { byte1, byte2 };
082: baos.write(temp, 0, 2);
083:
084: }
085:
086: void writeInt(ByteArrayOutputStream baos, int theInt) {
087:
088: byte byte1 = (byte) ((theInt >> 24) & 0xff);
089: byte byte2 = (byte) ((theInt >> 16) & 0xff);
090: byte byte3 = (byte) ((theInt >> 8) & 0xff);
091: byte byte4 = (byte) (theInt & 0xff);
092: byte[] temp = { byte1, byte2, byte3, byte4 };
093: baos.write(temp, 0, 4);
094:
095: }
096:
097: void writeChunk(byte[] tag, byte[] buffer) {
098:
099: int bufferLength = (buffer != null) ? buffer.length : 0;
100:
101: chunk = new PngChunk(bufferLength);
102:
103: writeInt(bytes, bufferLength);
104: bytes.write(tag, 0, 4);
105: chunk.setType(tag);
106: if (bufferLength != 0) {
107: bytes.write(buffer, 0, bufferLength);
108: chunk.setData(buffer);
109: } else {
110: chunk.setCRC(chunk.computeCRC());
111: }
112: writeInt(bytes, chunk.getCRC());
113:
114: }
115:
116: void writeSignature() {
117:
118: bytes.write(SIGNATURE, 0, 8);
119:
120: }
121:
122: void writeHeader() {
123:
124: ByteArrayOutputStream baos = new ByteArrayOutputStream(13);
125:
126: writeInt(baos, width);
127: writeInt(baos, height);
128: baos.write(bitDepth);
129: baos.write(colorType);
130: baos.write(compressionMethod);
131: baos.write(filterMethod);
132: baos.write(interlaceMethod);
133:
134: writeChunk(TAG_IHDR, baos.toByteArray());
135:
136: }
137:
138: void writePalette() {
139:
140: RGB[] RGBs = data.palette.getRGBs();
141:
142: if (RGBs.length > 256)
143: SWT.error(SWT.ERROR_INVALID_IMAGE);
144:
145: ByteArrayOutputStream baos = new ByteArrayOutputStream(
146: RGBs.length);
147:
148: for (int i = 0; i < RGBs.length; i++) {
149:
150: baos.write((byte) RGBs[i].red);
151: baos.write((byte) RGBs[i].green);
152: baos.write((byte) RGBs[i].blue);
153:
154: }
155:
156: writeChunk(TAG_PLTE, baos.toByteArray());
157:
158: }
159:
160: void writeTransparency() {
161:
162: ByteArrayOutputStream baos = new ByteArrayOutputStream();
163:
164: switch (transparencyType) {
165:
166: case SWT.TRANSPARENCY_ALPHA:
167:
168: int pixelValue,
169: alphaValue;
170:
171: byte[] alphas = new byte[data.palette.getRGBs().length];
172:
173: for (int y = 0; y < height; y++) {
174:
175: for (int x = 0; x < width; x++) {
176:
177: pixelValue = data.getPixel(x, y);
178: alphaValue = data.getAlpha(x, y);
179:
180: alphas[pixelValue] = (byte) alphaValue;
181:
182: }
183:
184: }
185:
186: baos.write(alphas, 0, alphas.length);
187:
188: break;
189:
190: case SWT.TRANSPARENCY_PIXEL:
191:
192: int pixel = data.transparentPixel;
193:
194: if (colorType == 2) {
195:
196: int redMask = data.palette.redMask;
197: int redShift = data.palette.redShift;
198: int greenMask = data.palette.greenMask;
199: int greenShift = data.palette.greenShift;
200: int blueShift = data.palette.blueShift;
201: int blueMask = data.palette.blueMask;
202:
203: int r = pixel & redMask;
204: r = (redShift < 0) ? r >>> -redShift : r << redShift;
205: int g = pixel & greenMask;
206: g = (greenShift < 0) ? g >>> -greenShift
207: : g << greenShift;
208: int b = pixel & blueMask;
209: b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
210:
211: writeShort(baos, r);
212: writeShort(baos, g);
213: writeShort(baos, b);
214:
215: }
216:
217: if (colorType == 3) {
218:
219: byte[] padding = new byte[pixel + 1];
220:
221: for (int i = 0; i < pixel; i++) {
222:
223: padding[i] = (byte) 255;
224:
225: }
226:
227: padding[pixel] = (byte) 0;
228:
229: baos.write(padding, 0, padding.length);
230:
231: }
232:
233: break;
234:
235: }
236:
237: writeChunk(TAG_TRNS, baos.toByteArray());
238:
239: }
240:
241: void writeImageData() throws IOException {
242:
243: ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
244: OutputStream os = Compatibility.newDeflaterOutputStream(baos);
245: if (os == null)
246: os = baos;
247:
248: if (colorType == 3) {
249:
250: byte[] lineData = new byte[width];
251:
252: for (int y = 0; y < height; y++) {
253:
254: int filter = 0;
255: os.write(filter);
256:
257: data.getPixels(0, y, width, lineData, 0);
258:
259: for (int x = 0; x < lineData.length; x++) {
260:
261: os.write(lineData[x]);
262:
263: }
264:
265: }
266:
267: }
268:
269: else {
270:
271: int[] lineData = new int[width];
272: byte[] alphaData = null;
273: if (colorType == 6) {
274: alphaData = new byte[width];
275: }
276:
277: int redMask = data.palette.redMask;
278: int redShift = data.palette.redShift;
279: int greenMask = data.palette.greenMask;
280: int greenShift = data.palette.greenShift;
281: int blueShift = data.palette.blueShift;
282: int blueMask = data.palette.blueMask;
283:
284: for (int y = 0; y < height; y++) {
285:
286: int filter = 0;
287: os.write(filter);
288:
289: data.getPixels(0, y, width, lineData, 0);
290:
291: if (colorType == 6) {
292: data.getAlphas(0, y, width, alphaData, 0);
293: }
294:
295: for (int x = 0; x < lineData.length; x++) {
296:
297: int pixel = lineData[x];
298:
299: int r = pixel & redMask;
300: r = (redShift < 0) ? r >>> -redShift
301: : r << redShift;
302: int g = pixel & greenMask;
303: g = (greenShift < 0) ? g >>> -greenShift
304: : g << greenShift;
305: int b = pixel & blueMask;
306: b = (blueShift < 0) ? b >>> -blueShift
307: : b << blueShift;
308:
309: os.write(r);
310: os.write(g);
311: os.write(b);
312:
313: if (colorType == 6) {
314: os.write(alphaData[x]);
315: }
316:
317: }
318:
319: }
320:
321: }
322:
323: os.flush();
324: os.close();
325:
326: byte[] compressed = baos.toByteArray();
327: if (os == baos) {
328: PngDeflater deflater = new PngDeflater();
329: compressed = deflater.deflate(compressed);
330: }
331:
332: writeChunk(TAG_IDAT, compressed);
333:
334: }
335:
336: void writeEnd() {
337:
338: writeChunk(TAG_IEND, null);
339:
340: }
341:
342: public void encode(LEDataOutputStream outputStream) {
343:
344: try {
345:
346: writeSignature();
347: writeHeader();
348:
349: if (colorType == 3) {
350: writePalette();
351: }
352:
353: boolean transparencyAlpha = (transparencyType == SWT.TRANSPARENCY_ALPHA);
354: boolean transparencyPixel = (transparencyType == SWT.TRANSPARENCY_PIXEL);
355: boolean type2Transparency = (colorType == 2 && transparencyPixel);
356: boolean type3Transparency = (colorType == 3 && (transparencyAlpha || transparencyPixel));
357:
358: if (type2Transparency || type3Transparency) {
359: writeTransparency();
360: }
361:
362: writeImageData();
363: writeEnd();
364:
365: outputStream.write(bytes.toByteArray());
366:
367: }
368:
369: catch (IOException e) {
370:
371: SWT.error(SWT.ERROR_IO, e);
372:
373: }
374:
375: }
376:
377: }
|