comparison dwt/internal/image/PngEncoder.d @ 2:57151e2793a2

More common modules from dwt-linux
author Frank Benoit <benoit@tionex.de>
date Wed, 23 Jan 2008 12:01:46 +0100
parents
children 36f5cb12e1a2
comparison
equal deleted inserted replaced
1:8ac7199abbc4 2:57151e2793a2
1 /*******************************************************************************
2 * Copyright (c) 2000, 2006 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwt.internal.image.PngEncoder;
14
15 import dwt.internal.image.LEDataOutputStream;
16 import dwt.internal.image.PngDeflater;
17 import dwt.dwthelper.ByteArrayOutputStream;
18 import dwt.DWT;
19 import dwt.graphics.ImageData;
20 import dwt.graphics.ImageLoader;
21 import dwt.graphics.RGB;
22 import dwt.internal.image.PngChunk;
23
24 import tango.core.Exception;
25
26 final class PngEncoder {
27
28 static const byte SIGNATURE[] = [cast(byte) '\211', cast(byte) 'P', cast(byte) 'N', cast(byte) 'G', cast(byte) '\r', cast(byte) '\n', cast(byte) '\032', cast(byte) '\n'];
29 static const byte TAG_IHDR[] = [cast(byte) 'I', cast(byte) 'H', cast(byte) 'D', cast(byte) 'R'];
30 static const byte TAG_PLTE[] = [cast(byte) 'P', cast(byte) 'L', cast(byte) 'T', cast(byte) 'E'];
31 static const byte TAG_TRNS[] = [cast(byte) 't', cast(byte) 'R', cast(byte) 'N', cast(byte) 'S'];
32 static const byte TAG_IDAT[] = [cast(byte) 'I', cast(byte) 'D', cast(byte) 'A', cast(byte) 'T'];
33 static const byte TAG_IEND[] = [cast(byte) 'I', cast(byte) 'E', cast(byte) 'N', cast(byte) 'D'];
34
35 ByteArrayOutputStream bytes;
36 PngChunk chunk;
37
38 ImageLoader loader;
39 ImageData data;
40 int transparencyType;
41
42 int width, height, bitDepth, colorType;
43
44 int compressionMethod = 0;
45 int filterMethod = 0;
46 int interlaceMethod = 0;
47
48 public this(ImageLoader loader) {
49 this.bytes = new ByteArrayOutputStream(1024);
50 this.loader = loader;
51 this.data = loader.data[0];
52 this.transparencyType = data.getTransparencyType();
53
54 this.width = data.width;
55 this.height = data.height;
56
57 this.bitDepth = 8;
58
59 this.colorType = 2;
60
61 if (data.palette.isDirect) {
62 if (transparencyType is DWT.TRANSPARENCY_ALPHA) {
63 this.colorType = 6;
64 }
65 }
66 else {
67 this.colorType = 3;
68 }
69
70 if (!(colorType is 2 || colorType is 3 || colorType is 6)) DWT.error(DWT.ERROR_INVALID_IMAGE);
71
72 }
73
74 void writeShort(ByteArrayOutputStream baos, int theShort) {
75
76 byte byte1 = cast(byte) ((theShort >> 8) & 0xff);
77 byte byte2 = cast(byte) (theShort & 0xff);
78 byte[] temp = [byte1, byte2];
79 baos.write(temp, 0, 2);
80
81 }
82
83 void writeInt(ByteArrayOutputStream baos, int theInt) {
84
85 byte byte1 = cast(byte) ((theInt >> 24) & 0xff);
86 byte byte2 = cast(byte) ((theInt >> 16) & 0xff);
87 byte byte3 = cast(byte) ((theInt >> 8) & 0xff);
88 byte byte4 = cast(byte) (theInt & 0xff);
89 byte[] temp = [byte1, byte2, byte3, byte4];
90 baos.write(temp, 0, 4);
91
92 }
93
94 void writeChunk(byte[] tag, byte[] buffer) {
95
96 int bufferLength = (buffer !is null) ? buffer.length : 0;
97
98 chunk = new PngChunk(bufferLength);
99
100 writeInt(bytes, bufferLength);
101 bytes.write(tag, 0, 4);
102 chunk.setType(tag);
103 if (bufferLength !is 0) {
104 bytes.write(buffer, 0, bufferLength);
105 chunk.setData(buffer);
106 }
107 else {
108 chunk.setCRC(chunk.computeCRC());
109 }
110 writeInt(bytes, chunk.getCRC());
111
112 }
113
114 void writeSignature() {
115
116 bytes.write(SIGNATURE, 0, 8);
117
118 }
119
120 void writeHeader() {
121
122 ByteArrayOutputStream baos = new ByteArrayOutputStream(13);
123
124 writeInt(baos, width);
125 writeInt(baos, height);
126 baos.write(bitDepth);
127 baos.write(colorType);
128 baos.write(compressionMethod);
129 baos.write(filterMethod);
130 baos.write(interlaceMethod);
131
132 writeChunk(TAG_IHDR, baos.toByteArray());
133
134 }
135
136 void writePalette() {
137
138 RGB[] RGBs = data.palette.getRGBs();
139
140 if (RGBs.length > 256) DWT.error(DWT.ERROR_INVALID_IMAGE);
141
142 ByteArrayOutputStream baos = new ByteArrayOutputStream(RGBs.length);
143
144 for (int i = 0; i < RGBs.length; i++) {
145
146 baos.write(cast(byte) RGBs[i].red);
147 baos.write(cast(byte) RGBs[i].green);
148 baos.write(cast(byte) RGBs[i].blue);
149
150 }
151
152 writeChunk(TAG_PLTE, baos.toByteArray());
153
154 }
155
156 void writeTransparency() {
157
158 ByteArrayOutputStream baos = new ByteArrayOutputStream();
159
160 switch (transparencyType) {
161
162 case DWT.TRANSPARENCY_ALPHA:
163
164 int pixelValue, alphaValue;
165
166 byte[] alphas = new byte[data.palette.getRGBs().length];
167
168 for (int y = 0; y < height; y++) {
169
170 for (int x = 0; x < width; x++) {
171
172 pixelValue = data.getPixel(x, y);
173 alphaValue = data.getAlpha(x, y);
174
175 alphas[pixelValue] = cast(byte) alphaValue;
176
177 }
178
179 }
180
181 baos.write(alphas, 0, alphas.length);
182
183 break;
184
185 case DWT.TRANSPARENCY_PIXEL:
186
187 int pixel = data.transparentPixel;
188
189 if (colorType is 2) {
190
191 int redMask = data.palette.redMask;
192 int redShift = data.palette.redShift;
193 int greenMask = data.palette.greenMask;
194 int greenShift = data.palette.greenShift;
195 int blueShift = data.palette.blueShift;
196 int blueMask = data.palette.blueMask;
197
198 int r = pixel & redMask;
199 r = (redShift < 0) ? r >>> -redShift : r << redShift;
200 int g = pixel & greenMask;
201 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
202 int b = pixel & blueMask;
203 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
204
205 writeShort(baos, r);
206 writeShort(baos, g);
207 writeShort(baos, b);
208
209 }
210
211 if (colorType is 3) {
212
213 byte[] padding = new byte[pixel + 1];
214
215 for (int i = 0; i < pixel; i++) {
216
217 padding[i] = cast(byte) 255;
218
219 }
220
221 padding[pixel] = cast(byte) 0;
222
223 baos.write(padding, 0, padding.length);
224
225 }
226
227 break;
228 default:
229
230 }
231
232 writeChunk(TAG_TRNS, baos.toByteArray());
233
234 }
235
236 void writeImageData() {
237
238 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
239
240 if (colorType is 3) {
241
242 int[] lineData = new int[width];
243
244 for (int y = 0; y < height; y++) {
245
246 byte filter[] = [0];
247 baos.write(filter, 0, 1);
248
249 data.getPixels(0, y, width, lineData, 0);
250
251 for (int x = 0; x < lineData.length; x++) {
252
253 baos.write(cast(byte) lineData[x]);
254
255 }
256
257 }
258
259 }
260
261 else {
262
263 int[] lineData = new int[width];
264 byte[] alphaData = new byte[width];
265
266 int redMask = data.palette.redMask;
267 int redShift = data.palette.redShift;
268 int greenMask = data.palette.greenMask;
269 int greenShift = data.palette.greenShift;
270 int blueShift = data.palette.blueShift;
271 int blueMask = data.palette.blueMask;
272
273 for (int y = 0; y < height; y++) {
274
275 byte filter[] = [0];
276 baos.write(filter, 0, 1);
277
278 data.getPixels(0, y, width, lineData, 0);
279
280 if (colorType is 6) {
281 data.getAlphas(0, y, width, alphaData, 0);
282 }
283
284 for (int x = 0; x < lineData.length; x++) {
285
286 int pixel = lineData[x];
287
288 int r = pixel & redMask;
289 r = (redShift < 0) ? r >>> -redShift : r << redShift;
290 int g = pixel & greenMask;
291 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
292 int b = pixel & blueMask;
293 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
294
295 byte pixels[] = [cast(byte) r, cast(byte) g, cast(byte) b];
296 baos.write(pixels, 0, 3);
297
298 if (colorType is 6) {
299
300 byte alpha[] = [alphaData[x]];
301 baos.write(alpha, 0, 1);
302
303 }
304
305 }
306
307 }
308
309 }
310
311 PngDeflater deflater = new PngDeflater();
312 byte[] compressed = deflater.deflate(baos.toByteArray());
313
314 writeChunk(TAG_IDAT, compressed);
315
316 }
317
318 void writeEnd() {
319
320 writeChunk(TAG_IEND, null);
321
322 }
323
324 public void encode(LEDataOutputStream outputStream) {
325
326 try {
327
328 writeSignature();
329 writeHeader();
330
331 if (colorType is 3) {
332 writePalette();
333 }
334
335 bool transparencyAlpha = (transparencyType is DWT.TRANSPARENCY_ALPHA);
336 bool transparencyPixel = (transparencyType is DWT.TRANSPARENCY_PIXEL);
337 bool type2Transparency = (colorType is 2 && transparencyPixel);
338 bool type3Transparency = (colorType is 3 && (transparencyAlpha || transparencyPixel));
339
340 if (type2Transparency || type3Transparency) {
341 writeTransparency();
342 }
343
344 writeImageData();
345 writeEnd();
346
347 outputStream.write(bytes.toByteArray());
348
349 }
350
351 catch (IOException e) {
352
353 DWT.error(DWT.ERROR_IO, e);
354
355 }
356
357 }
358
359 }