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 org.eclipse.swt.*;
013: import org.eclipse.swt.graphics.*;
014:
015: class PngIhdrChunk extends PngChunk {
016: static final int IHDR_DATA_LENGTH = 13;
017:
018: static final int WIDTH_DATA_OFFSET = DATA_OFFSET + 0;
019: static final int HEIGHT_DATA_OFFSET = DATA_OFFSET + 4;
020: static final int BIT_DEPTH_OFFSET = DATA_OFFSET + 8;
021: static final int COLOR_TYPE_OFFSET = DATA_OFFSET + 9;
022: static final int COMPRESSION_METHOD_OFFSET = DATA_OFFSET + 10;
023: static final int FILTER_METHOD_OFFSET = DATA_OFFSET + 11;
024: static final int INTERLACE_METHOD_OFFSET = DATA_OFFSET + 12;
025:
026: static final byte COLOR_TYPE_GRAYSCALE = 0;
027: static final byte COLOR_TYPE_RGB = 2;
028: static final byte COLOR_TYPE_PALETTE = 3;
029: static final byte COLOR_TYPE_GRAYSCALE_WITH_ALPHA = 4;
030: static final byte COLOR_TYPE_RGB_WITH_ALPHA = 6;
031:
032: static final int INTERLACE_METHOD_NONE = 0;
033: static final int INTERLACE_METHOD_ADAM7 = 1;
034:
035: static final int FILTER_NONE = 0;
036: static final int FILTER_SUB = 1;
037: static final int FILTER_UP = 2;
038: static final int FILTER_AVERAGE = 3;
039: static final int FILTER_PAETH = 4;
040:
041: static final byte[] ValidBitDepths = { 1, 2, 4, 8, 16 };
042: static final byte[] ValidColorTypes = { 0, 2, 3, 4, 6 };
043:
044: int width, height;
045: byte bitDepth, colorType, compressionMethod, filterMethod,
046: interlaceMethod;
047:
048: PngIhdrChunk(int width, int height, byte bitDepth, byte colorType,
049: byte compressionMethod, byte filterMethod,
050: byte interlaceMethod) {
051: super (IHDR_DATA_LENGTH);
052: setType(TYPE_IHDR);
053: setWidth(width);
054: setHeight(height);
055: setBitDepth(bitDepth);
056: setColorType(colorType);
057: setCompressionMethod(compressionMethod);
058: setFilterMethod(filterMethod);
059: setInterlaceMethod(interlaceMethod);
060: setCRC(computeCRC());
061: }
062:
063: /**
064: * Construct a PNGChunk using the reference bytes
065: * given.
066: */
067: PngIhdrChunk(byte[] reference) {
068: super (reference);
069: if (reference.length <= IHDR_DATA_LENGTH)
070: SWT.error(SWT.ERROR_INVALID_IMAGE);
071: width = getInt32(WIDTH_DATA_OFFSET);
072: height = getInt32(HEIGHT_DATA_OFFSET);
073: bitDepth = reference[BIT_DEPTH_OFFSET];
074: colorType = reference[COLOR_TYPE_OFFSET];
075: compressionMethod = reference[COMPRESSION_METHOD_OFFSET];
076: filterMethod = reference[FILTER_METHOD_OFFSET];
077: interlaceMethod = reference[INTERLACE_METHOD_OFFSET];
078: }
079:
080: int getChunkType() {
081: return CHUNK_IHDR;
082: }
083:
084: /**
085: * Get the image's width in pixels.
086: */
087: int getWidth() {
088: return width;
089: }
090:
091: /**
092: * Set the image's width in pixels.
093: */
094: void setWidth(int value) {
095: setInt32(WIDTH_DATA_OFFSET, value);
096: width = value;
097: }
098:
099: /**
100: * Get the image's height in pixels.
101: */
102: int getHeight() {
103: return height;
104: }
105:
106: /**
107: * Set the image's height in pixels.
108: */
109: void setHeight(int value) {
110: setInt32(HEIGHT_DATA_OFFSET, value);
111: height = value;
112: }
113:
114: /**
115: * Get the image's bit depth.
116: * This is limited to the values 1, 2, 4, 8, or 16.
117: */
118: byte getBitDepth() {
119: return bitDepth;
120: }
121:
122: /**
123: * Set the image's bit depth.
124: * This is limited to the values 1, 2, 4, 8, or 16.
125: */
126: void setBitDepth(byte value) {
127: reference[BIT_DEPTH_OFFSET] = value;
128: bitDepth = value;
129: }
130:
131: /**
132: * Get the image's color type.
133: * This is limited to the values:
134: * 0 - Grayscale image.
135: * 2 - RGB triple.
136: * 3 - Palette.
137: * 4 - Grayscale with Alpha channel.
138: * 6 - RGB with Alpha channel.
139: */
140: byte getColorType() {
141: return colorType;
142: }
143:
144: /**
145: * Set the image's color type.
146: * This is limited to the values:
147: * 0 - Grayscale image.
148: * 2 - RGB triple.
149: * 3 - Palette.
150: * 4 - Grayscale with Alpha channel.
151: * 6 - RGB with Alpha channel.
152: */
153: void setColorType(byte value) {
154: reference[COLOR_TYPE_OFFSET] = value;
155: colorType = value;
156: }
157:
158: /**
159: * Get the image's compression method.
160: * This value must be 0.
161: */
162: byte getCompressionMethod() {
163: return compressionMethod;
164: }
165:
166: /**
167: * Set the image's compression method.
168: * This value must be 0.
169: */
170: void setCompressionMethod(byte value) {
171: reference[COMPRESSION_METHOD_OFFSET] = value;
172: compressionMethod = value;
173: }
174:
175: /**
176: * Get the image's filter method.
177: * This value must be 0.
178: */
179: byte getFilterMethod() {
180: return filterMethod;
181: }
182:
183: /**
184: * Set the image's filter method.
185: * This value must be 0.
186: */
187: void setFilterMethod(byte value) {
188: reference[FILTER_METHOD_OFFSET] = value;
189: filterMethod = value;
190: }
191:
192: /**
193: * Get the image's interlace method.
194: * This value is limited to:
195: * 0 - No interlacing used.
196: * 1 - Adam7 interlacing used.
197: */
198: byte getInterlaceMethod() {
199: return interlaceMethod;
200: }
201:
202: /**
203: * Set the image's interlace method.
204: * This value is limited to:
205: * 0 - No interlacing used.
206: * 1 - Adam7 interlacing used.
207: */
208: void setInterlaceMethod(byte value) {
209: reference[INTERLACE_METHOD_OFFSET] = value;
210: interlaceMethod = value;
211: }
212:
213: /**
214: * Answer whether the chunk is a valid IHDR chunk.
215: */
216: void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
217: // An IHDR chunk is invalid if any other chunk has
218: // been read.
219: if (readState.readIHDR || readState.readPLTE
220: || readState.readIDAT || readState.readIEND) {
221: SWT.error(SWT.ERROR_INVALID_IMAGE);
222: } else {
223: readState.readIHDR = true;
224: }
225:
226: super .validate(readState, headerChunk);
227:
228: if (length != IHDR_DATA_LENGTH)
229: SWT.error(SWT.ERROR_INVALID_IMAGE);
230: if (compressionMethod != 0)
231: SWT.error(SWT.ERROR_INVALID_IMAGE);
232: if (interlaceMethod != INTERLACE_METHOD_NONE
233: && interlaceMethod != INTERLACE_METHOD_ADAM7) {
234: SWT.error(SWT.ERROR_INVALID_IMAGE);
235: }
236:
237: boolean colorTypeIsValid = false;
238: for (int i = 0; i < ValidColorTypes.length; i++) {
239: if (ValidColorTypes[i] == colorType) {
240: colorTypeIsValid = true;
241: break;
242: }
243: }
244: if (!colorTypeIsValid)
245: SWT.error(SWT.ERROR_INVALID_IMAGE);
246:
247: boolean bitDepthIsValid = false;
248: for (int i = 0; i < ValidBitDepths.length; i++) {
249: if (ValidBitDepths[i] == bitDepth) {
250: bitDepthIsValid = true;
251: break;
252: }
253: }
254: if (!bitDepthIsValid)
255: SWT.error(SWT.ERROR_INVALID_IMAGE);
256:
257: if ((colorType == COLOR_TYPE_RGB
258: || colorType == COLOR_TYPE_RGB_WITH_ALPHA || colorType == COLOR_TYPE_GRAYSCALE_WITH_ALPHA)
259: && bitDepth < 8) {
260: SWT.error(SWT.ERROR_INVALID_IMAGE);
261: }
262:
263: if (colorType == COLOR_TYPE_PALETTE && bitDepth > 8) {
264: SWT.error(SWT.ERROR_INVALID_IMAGE);
265: }
266: }
267:
268: String getColorTypeString() {
269: switch (colorType) {
270: case COLOR_TYPE_GRAYSCALE:
271: return "Grayscale";
272: case COLOR_TYPE_RGB:
273: return "RGB";
274: case COLOR_TYPE_PALETTE:
275: return "Palette";
276: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
277: return "Grayscale with Alpha";
278: case COLOR_TYPE_RGB_WITH_ALPHA:
279: return "RGB with Alpha";
280: default:
281: return "Unknown - " + colorType;
282: }
283: }
284:
285: String getFilterMethodString() {
286: switch (filterMethod) {
287: case FILTER_NONE:
288: return "None";
289: case FILTER_SUB:
290: return "Sub";
291: case FILTER_UP:
292: return "Up";
293: case FILTER_AVERAGE:
294: return "Average";
295: case FILTER_PAETH:
296: return "Paeth";
297: default:
298: return "Unknown";
299: }
300: }
301:
302: String getInterlaceMethodString() {
303: switch (interlaceMethod) {
304: case INTERLACE_METHOD_NONE:
305: return "Not Interlaced";
306: case INTERLACE_METHOD_ADAM7:
307: return "Interlaced - ADAM7";
308: default:
309: return "Unknown";
310: }
311: }
312:
313: void contributeToString(StringBuffer buffer) {
314: buffer.append("\n\tWidth: ");
315: buffer.append(width);
316: buffer.append("\n\tHeight: ");
317: buffer.append(height);
318: buffer.append("\n\tBit Depth: ");
319: buffer.append(bitDepth);
320: buffer.append("\n\tColor Type: ");
321: buffer.append(getColorTypeString());
322: buffer.append("\n\tCompression Method: ");
323: buffer.append(compressionMethod);
324: buffer.append("\n\tFilter Method: ");
325: buffer.append(getFilterMethodString());
326: buffer.append("\n\tInterlace Method: ");
327: buffer.append(getInterlaceMethodString());
328: }
329:
330: boolean getMustHavePalette() {
331: return colorType == COLOR_TYPE_PALETTE;
332: }
333:
334: boolean getCanHavePalette() {
335: return colorType != COLOR_TYPE_GRAYSCALE
336: && colorType != COLOR_TYPE_GRAYSCALE_WITH_ALPHA;
337: }
338:
339: /**
340: * Answer the pixel size in bits based on the color type
341: * and bit depth.
342: */
343: int getBitsPerPixel() {
344: switch (colorType) {
345: case COLOR_TYPE_RGB_WITH_ALPHA:
346: return 4 * bitDepth;
347: case COLOR_TYPE_RGB:
348: return 3 * bitDepth;
349: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
350: return 2 * bitDepth;
351: case COLOR_TYPE_GRAYSCALE:
352: case COLOR_TYPE_PALETTE:
353: return bitDepth;
354: default:
355: SWT.error(SWT.ERROR_INVALID_IMAGE);
356: return 0;
357: }
358: }
359:
360: /**
361: * Answer the pixel size in bits based on the color type
362: * and bit depth.
363: */
364: int getSwtBitsPerPixel() {
365: switch (colorType) {
366: case COLOR_TYPE_RGB_WITH_ALPHA:
367: case COLOR_TYPE_RGB:
368: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
369: return 24;
370: case COLOR_TYPE_GRAYSCALE:
371: case COLOR_TYPE_PALETTE:
372: return Math.min(bitDepth, 8);
373: default:
374: SWT.error(SWT.ERROR_INVALID_IMAGE);
375: return 0;
376: }
377: }
378:
379: int getFilterByteOffset() {
380: if (bitDepth < 8)
381: return 1;
382: return getBitsPerPixel() / 8;
383: }
384:
385: boolean usesDirectColor() {
386: switch (colorType) {
387: case COLOR_TYPE_GRAYSCALE:
388: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
389: case COLOR_TYPE_RGB:
390: case COLOR_TYPE_RGB_WITH_ALPHA:
391: return true;
392: default:
393: return false;
394: }
395: }
396:
397: PaletteData createGrayscalePalette() {
398: int depth = Math.min(bitDepth, 8);
399: int max = (1 << depth) - 1;
400: int delta = 255 / max;
401: int gray = 0;
402: RGB[] rgbs = new RGB[max + 1];
403: for (int i = 0; i <= max; i++) {
404: rgbs[i] = new RGB(gray, gray, gray);
405: gray += delta;
406: }
407: return new PaletteData(rgbs);
408: }
409:
410: PaletteData getPaletteData() {
411: switch (colorType) {
412: case COLOR_TYPE_GRAYSCALE:
413: return createGrayscalePalette();
414: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
415: case COLOR_TYPE_RGB:
416: case COLOR_TYPE_RGB_WITH_ALPHA:
417: return new PaletteData(0xFF0000, 0xFF00, 0xFF);
418: default:
419: return null;
420: }
421: }
422:
423: }
|