]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/image/PngIhdrChunk.java
b71bc8f75a0e96eb1a8db57a8ff53169a2fb7671
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / internal / image / PngIhdrChunk.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 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
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19
20 class PngIhdrChunk extends PngChunk {
21         static final int IHDR_DATA_LENGTH = 13;
22
23         static final int WIDTH_DATA_OFFSET = DATA_OFFSET + 0;
24         static final int HEIGHT_DATA_OFFSET = DATA_OFFSET + 4;
25         static final int BIT_DEPTH_OFFSET = DATA_OFFSET + 8;
26         static final int COLOR_TYPE_OFFSET = DATA_OFFSET + 9;
27         static final int COMPRESSION_METHOD_OFFSET = DATA_OFFSET + 10;
28         static final int FILTER_METHOD_OFFSET = DATA_OFFSET + 11;
29         static final int INTERLACE_METHOD_OFFSET = DATA_OFFSET + 12;
30
31         static final byte COLOR_TYPE_GRAYSCALE = 0;
32         static final byte COLOR_TYPE_RGB = 2;
33         static final byte COLOR_TYPE_PALETTE = 3;
34         static final byte COLOR_TYPE_GRAYSCALE_WITH_ALPHA = 4;
35         static final byte COLOR_TYPE_RGB_WITH_ALPHA = 6;
36
37         static final int INTERLACE_METHOD_NONE = 0;
38         static final int INTERLACE_METHOD_ADAM7 = 1;
39
40         static final int FILTER_NONE = 0;
41         static final int FILTER_SUB = 1;
42         static final int FILTER_UP = 2;
43         static final int FILTER_AVERAGE = 3;
44         static final int FILTER_PAETH = 4;
45
46         static final byte[] ValidBitDepths = {1, 2, 4, 8, 16};
47         static final byte[] ValidColorTypes = {0, 2, 3, 4, 6};
48
49         int width, height;
50         byte bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
51
52 PngIhdrChunk(int width, int height, byte bitDepth, byte colorType, byte compressionMethod, byte filterMethod, byte interlaceMethod) {
53         super(IHDR_DATA_LENGTH);
54         setType(TYPE_IHDR);
55         setWidth(width);
56         setHeight(height);
57         setBitDepth(bitDepth);
58         setColorType(colorType);
59         setCompressionMethod(compressionMethod);
60         setFilterMethod(filterMethod);
61         setInterlaceMethod(interlaceMethod);
62         setCRC(computeCRC());
63 }
64
65 /**
66  * Construct a PNGChunk using the reference bytes
67  * given.
68  */
69 PngIhdrChunk(byte[] reference) {
70         super(reference);
71         if (reference.length <= IHDR_DATA_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
72         width = getInt32(WIDTH_DATA_OFFSET);
73         height = getInt32(HEIGHT_DATA_OFFSET);
74         bitDepth = reference[BIT_DEPTH_OFFSET];
75         colorType = reference[COLOR_TYPE_OFFSET];
76         compressionMethod = reference[COMPRESSION_METHOD_OFFSET];
77         filterMethod = reference[FILTER_METHOD_OFFSET];
78         interlaceMethod = reference[INTERLACE_METHOD_OFFSET];
79 }
80
81 @Override
82 int getChunkType() {
83         return CHUNK_IHDR;
84 }
85
86 /**
87  * Get the image's width in pixels.
88  */
89 int getWidth() {
90         return width;
91 }
92
93 /**
94  * Set the image's width in pixels.
95  */
96 void setWidth(int value) {
97         setInt32(WIDTH_DATA_OFFSET, value);
98         width = value;
99 }
100
101 /**
102  * Get the image's height in pixels.
103  */
104 int getHeight() {
105         return height;
106 }
107
108 /**
109  * Set the image's height in pixels.
110  */
111 void setHeight(int value) {
112         setInt32(HEIGHT_DATA_OFFSET, value);
113         height = value;
114 }
115
116 /**
117  * Get the image's bit depth.
118  * This is limited to the values 1, 2, 4, 8, or 16.
119  */
120 byte getBitDepth() {
121         return bitDepth;
122 }
123
124 /**
125  * Set the image's bit depth.
126  * This is limited to the values 1, 2, 4, 8, or 16.
127  */
128 void setBitDepth(byte value) {
129         reference[BIT_DEPTH_OFFSET] = value;
130         bitDepth = value;
131 }
132
133 /**
134  * Get the image's color type.
135  * This is limited to the values:
136  * 0 - Grayscale image.
137  * 2 - RGB triple.
138  * 3 - Palette.
139  * 4 - Grayscale with Alpha channel.
140  * 6 - RGB with Alpha channel.
141  */
142 byte getColorType() {
143         return colorType;
144 }
145
146 /**
147  * Set the image's color type.
148  * This is limited to the values:
149  * 0 - Grayscale image.
150  * 2 - RGB triple.
151  * 3 - Palette.
152  * 4 - Grayscale with Alpha channel.
153  * 6 - RGB with Alpha channel.
154  */
155 void setColorType(byte value) {
156         reference[COLOR_TYPE_OFFSET] = value;
157         colorType = value;
158 }
159
160 /**
161  * Get the image's compression method.
162  * This value must be 0.
163  */
164 byte getCompressionMethod() {
165         return compressionMethod;
166 }
167
168 /**
169  * Set the image's compression method.
170  * This value must be 0.
171  */
172 void setCompressionMethod(byte value) {
173         reference[COMPRESSION_METHOD_OFFSET] = value;
174         compressionMethod = value;
175 }
176
177 /**
178  * Get the image's filter method.
179  * This value must be 0.
180  */
181 byte getFilterMethod() {
182         return filterMethod;
183 }
184
185 /**
186  * Set the image's filter method.
187  * This value must be 0.
188  */
189 void setFilterMethod(byte value) {
190         reference[FILTER_METHOD_OFFSET] = value;
191         filterMethod = value;
192 }
193
194 /**
195  * Get the image's interlace method.
196  * This value is limited to:
197  * 0 - No interlacing used.
198  * 1 - Adam7 interlacing used.
199  */
200 byte getInterlaceMethod() {
201         return interlaceMethod;
202 }
203
204 /**
205  * Set the image's interlace method.
206  * This value is limited to:
207  * 0 - No interlacing used.
208  * 1 - Adam7 interlacing used.
209  */
210 void setInterlaceMethod(byte value) {
211         reference[INTERLACE_METHOD_OFFSET] = value;
212         interlaceMethod = value;
213 }
214
215 /**
216  * Answer whether the chunk is a valid IHDR chunk.
217  */
218 @Override
219 void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
220         // An IHDR chunk is invalid if any other chunk has
221         // been read.
222         if (readState.readIHDR
223                 || readState.readPLTE
224                 || readState.readIDAT
225                 || readState.readIEND)
226         {
227                 SWT.error(SWT.ERROR_INVALID_IMAGE);
228         } else {
229                 readState.readIHDR = true;
230         }
231
232         super.validate(readState, headerChunk);
233
234         if (length != IHDR_DATA_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
235         if (compressionMethod != 0) SWT.error(SWT.ERROR_INVALID_IMAGE);
236         if (interlaceMethod != INTERLACE_METHOD_NONE &&
237                 interlaceMethod != INTERLACE_METHOD_ADAM7) {
238                         SWT.error(SWT.ERROR_INVALID_IMAGE);
239         }
240
241         boolean colorTypeIsValid = false;
242         for (int i = 0; i < ValidColorTypes.length; i++) {
243                 if (ValidColorTypes[i] == colorType) {
244                         colorTypeIsValid = true;
245                         break;
246                 }
247         }
248         if (!colorTypeIsValid) SWT.error(SWT.ERROR_INVALID_IMAGE);
249
250         boolean bitDepthIsValid = false;
251         for (int i = 0; i < ValidBitDepths.length; i++) {
252                 if (ValidBitDepths[i] == bitDepth) {
253                         bitDepthIsValid = true;
254                         break;
255                 }
256         }
257         if (!bitDepthIsValid) SWT.error(SWT.ERROR_INVALID_IMAGE);
258
259         if ((colorType == COLOR_TYPE_RGB
260                 || colorType == COLOR_TYPE_RGB_WITH_ALPHA
261                 || colorType == COLOR_TYPE_GRAYSCALE_WITH_ALPHA)
262                 && bitDepth < 8)
263         {
264                         SWT.error(SWT.ERROR_INVALID_IMAGE);
265         }
266
267         if (colorType == COLOR_TYPE_PALETTE && bitDepth > 8) {
268                 SWT.error(SWT.ERROR_INVALID_IMAGE);
269         }
270 }
271
272 String getColorTypeString() {
273         switch (colorType) {
274                 case COLOR_TYPE_GRAYSCALE:                              return "Grayscale";
275                 case COLOR_TYPE_RGB:                                    return "RGB";
276                 case COLOR_TYPE_PALETTE:                                return "Palette";
277                 case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:   return "Grayscale with Alpha";
278                 case COLOR_TYPE_RGB_WITH_ALPHA:                 return "RGB with Alpha";
279                 default:                                                                return "Unknown - " + colorType;
280         }
281 }
282
283 String getFilterMethodString() {
284         switch (filterMethod) {
285                 case FILTER_NONE:               return "None";
286                 case FILTER_SUB:                return "Sub";
287                 case FILTER_UP:                 return "Up";
288                 case FILTER_AVERAGE:    return "Average";
289                 case FILTER_PAETH:              return "Paeth";
290                 default:                                return "Unknown";
291         }
292 }
293
294 String getInterlaceMethodString() {
295         switch (interlaceMethod) {
296                 case INTERLACE_METHOD_NONE:     return "Not Interlaced";
297                 case INTERLACE_METHOD_ADAM7:    return "Interlaced - ADAM7";
298                 default:                                return "Unknown";
299         }
300 }
301
302 @Override
303 void contributeToString(StringBuilder buffer) {
304         buffer.append("\n\tWidth: ");
305         buffer.append(width);
306         buffer.append("\n\tHeight: ");
307         buffer.append(height);
308         buffer.append("\n\tBit Depth: ");
309         buffer.append(bitDepth);
310         buffer.append("\n\tColor Type: ");
311         buffer.append(getColorTypeString());
312         buffer.append("\n\tCompression Method: ");
313         buffer.append(compressionMethod);
314         buffer.append("\n\tFilter Method: ");
315         buffer.append(getFilterMethodString());
316         buffer.append("\n\tInterlace Method: ");
317         buffer.append(getInterlaceMethodString());
318 }
319
320 boolean getMustHavePalette() {
321         return colorType == COLOR_TYPE_PALETTE;
322 }
323
324 boolean getCanHavePalette() {
325         return colorType != COLOR_TYPE_GRAYSCALE &&
326                 colorType != COLOR_TYPE_GRAYSCALE_WITH_ALPHA;
327 }
328
329 /**
330  * Answer the pixel size in bits based on the color type
331  * and bit depth.
332  */
333 int getBitsPerPixel() {
334         switch (colorType) {
335                 case COLOR_TYPE_RGB_WITH_ALPHA:
336                         return 4 * bitDepth;
337                 case COLOR_TYPE_RGB:
338                         return 3 * bitDepth;
339                 case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
340                         return 2 * bitDepth;
341                 case COLOR_TYPE_GRAYSCALE:
342                 case COLOR_TYPE_PALETTE:
343                         return bitDepth;
344                 default:
345                         SWT.error(SWT.ERROR_INVALID_IMAGE);
346                         return 0;
347         }
348 }
349
350 /**
351  * Answer the pixel size in bits based on the color type
352  * and bit depth.
353  */
354 int getSwtBitsPerPixel() {
355         switch (colorType) {
356                 case COLOR_TYPE_RGB_WITH_ALPHA:
357                 case COLOR_TYPE_RGB:
358                 case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
359                         return 24;
360                 case COLOR_TYPE_GRAYSCALE:
361                 case COLOR_TYPE_PALETTE:
362                         return Math.min(bitDepth, 8);
363                 default:
364                         SWT.error(SWT.ERROR_INVALID_IMAGE);
365                         return 0;
366         }
367 }
368
369 int getFilterByteOffset() {
370         if (bitDepth < 8) return 1;
371         return getBitsPerPixel() / 8;
372 }
373
374 boolean usesDirectColor() {
375         switch (colorType) {
376                 case COLOR_TYPE_GRAYSCALE:
377                 case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
378                 case COLOR_TYPE_RGB:
379                 case COLOR_TYPE_RGB_WITH_ALPHA:
380                         return true;
381                 default:
382                         return false;
383         }
384 }
385
386 PaletteData createGrayscalePalette() {
387         int depth = Math.min(bitDepth, 8);
388         int max = (1 << depth) - 1;
389         int delta = 255 / max;
390         int gray = 0;
391         RGB[] rgbs = new RGB[max + 1];
392         for (int i = 0; i <= max; i++) {
393                 rgbs[i] = new RGB(gray, gray, gray);
394                 gray += delta;
395         }
396         return new PaletteData(rgbs);
397 }
398
399 PaletteData getPaletteData() {
400         switch (colorType) {
401                 case COLOR_TYPE_GRAYSCALE:
402                         return createGrayscalePalette();
403                 case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
404                 case COLOR_TYPE_RGB:
405                 case COLOR_TYPE_RGB_WITH_ALPHA:
406                         return new PaletteData(0xFF0000, 0xFF00, 0xFF);
407                 default:
408                         return null;
409         }
410 }
411
412
413
414 }