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