comparison dwt/internal/image/WinICOFileFormat.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children e831403a80a9
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
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 *******************************************************************************/
11 module dwt.internal.image;
12
13
14 import java.io.IOException;
15
16 import dwt.DWT;
17 import dwt.graphics.ImageData;
18 import dwt.graphics.ImageLoader;
19 import dwt.graphics.PaletteData;
20
21 public final class WinICOFileFormat : FileFormat {
22
23 byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
24 // Destructively bit invert data in the given byte array.
25 for (int i = startIndex; i < endIndex; i++) {
26 data[i] = (byte)(255 - data[i - startIndex]);
27 }
28 return data;
29 }
30
31 static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
32 if (pad is newPad) return data;
33 int stride = (width * depth + 7) / 8;
34 int bpl = (stride + (pad - 1)) / pad * pad;
35 int newBpl = (stride + (newPad - 1)) / newPad * newPad;
36 byte[] newData = new byte[height * newBpl];
37 int srcIndex = 0, destIndex = 0;
38 for (int y = 0; y < height; y++) {
39 System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
40 srcIndex += bpl;
41 destIndex += newBpl;
42 }
43 return newData;
44 }
45 /**
46 * Answer the size in bytes of the file representation of the given
47 * icon
48 */
49 int iconSize(ImageData i) {
50 int shapeDataStride = (i.width * i.depth + 31) / 32 * 4;
51 int maskDataStride = (i.width + 31) / 32 * 4;
52 int dataSize = (shapeDataStride + maskDataStride) * i.height;
53 int paletteSize = i.palette.colors !is null ? i.palette.colors.length * 4 : 0;
54 return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize;
55 }
56 bool isFileFormat(LEDataInputStream stream) {
57 try {
58 byte[] header = new byte[4];
59 stream.read(header);
60 stream.unread(header);
61 return header[0] is 0 && header[1] is 0 && header[2] is 1 && header[3] is 0;
62 } catch (Exception e) {
63 return false;
64 }
65 }
66 bool isValidIcon(ImageData i) {
67 switch (i.depth) {
68 case 1:
69 case 4:
70 case 8:
71 if (i.palette.isDirect) return false;
72 int size = i.palette.colors.length;
73 return size is 2 || size is 16 || size is 32 || size is 256;
74 case 24:
75 case 32:
76 return i.palette.isDirect;
77 }
78 return false;
79 }
80 int loadFileHeader(LEDataInputStream byteStream) {
81 int[] fileHeader = new int[3];
82 try {
83 fileHeader[0] = byteStream.readShort();
84 fileHeader[1] = byteStream.readShort();
85 fileHeader[2] = byteStream.readShort();
86 } catch (IOException e) {
87 DWT.error(DWT.ERROR_IO, e);
88 }
89 if ((fileHeader[0] !is 0) || (fileHeader[1] !is 1))
90 DWT.error(DWT.ERROR_INVALID_IMAGE);
91 int numIcons = fileHeader[2];
92 if (numIcons <= 0)
93 DWT.error(DWT.ERROR_INVALID_IMAGE);
94 return numIcons;
95 }
96 int loadFileHeader(LEDataInputStream byteStream, bool hasHeader) {
97 int[] fileHeader = new int[3];
98 try {
99 if (hasHeader) {
100 fileHeader[0] = byteStream.readShort();
101 fileHeader[1] = byteStream.readShort();
102 } else {
103 fileHeader[0] = 0;
104 fileHeader[1] = 1;
105 }
106 fileHeader[2] = byteStream.readShort();
107 } catch (IOException e) {
108 DWT.error(DWT.ERROR_IO, e);
109 }
110 if ((fileHeader[0] !is 0) || (fileHeader[1] !is 1))
111 DWT.error(DWT.ERROR_INVALID_IMAGE);
112 int numIcons = fileHeader[2];
113 if (numIcons <= 0)
114 DWT.error(DWT.ERROR_INVALID_IMAGE);
115 return numIcons;
116 }
117 ImageData[] loadFromByteStream() {
118 int numIcons = loadFileHeader(inputStream);
119 int[][] headers = loadIconHeaders(numIcons);
120 ImageData[] icons = new ImageData[headers.length];
121 for (int i = 0; i < icons.length; i++) {
122 icons[i] = loadIcon(headers[i]);
123 }
124 return icons;
125 }
126 /**
127 * Load one icon from the byte stream.
128 */
129 ImageData loadIcon(int[] iconHeader) {
130 byte[] infoHeader = loadInfoHeader(iconHeader);
131 WinBMPFileFormat bmpFormat = new WinBMPFileFormat();
132 bmpFormat.inputStream = inputStream;
133 PaletteData palette = bmpFormat.loadPalette(infoHeader);
134 byte[] shapeData = bmpFormat.loadData(infoHeader);
135 int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
136 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
137 if (height < 0) height = -height;
138 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
139 infoHeader[14] = 1;
140 infoHeader[15] = 0;
141 byte[] maskData = bmpFormat.loadData(infoHeader);
142 maskData = convertPad(maskData, width, height, 1, 4, 2);
143 bitInvertData(maskData, 0, maskData.length);
144 return ImageData.internal_new(
145 width,
146 height,
147 depth,
148 palette,
149 4,
150 shapeData,
151 2,
152 maskData,
153 null,
154 -1,
155 -1,
156 DWT.IMAGE_ICO,
157 0,
158 0,
159 0,
160 0);
161 }
162 int[][] loadIconHeaders(int numIcons) {
163 int[][] headers = new int[numIcons][7];
164 try {
165 for (int i = 0; i < numIcons; i++) {
166 headers[i][0] = inputStream.read();
167 headers[i][1] = inputStream.read();
168 headers[i][2] = inputStream.readShort();
169 headers[i][3] = inputStream.readShort();
170 headers[i][4] = inputStream.readShort();
171 headers[i][5] = inputStream.readInt();
172 headers[i][6] = inputStream.readInt();
173 }
174 } catch (IOException e) {
175 DWT.error(DWT.ERROR_IO, e);
176 }
177 return headers;
178 }
179 byte[] loadInfoHeader(int[] iconHeader) {
180 int width = iconHeader[0];
181 int height = iconHeader[1];
182 int numColors = iconHeader[2]; // the number of colors is in the low byte, but the high byte must be 0
183 if (numColors is 0) numColors = 256; // this is specified: '00' represents '256' (0x100) colors
184 if ((numColors !is 2) && (numColors !is 8) && (numColors !is 16) &&
185 (numColors !is 32) && (numColors !is 256))
186 DWT.error(DWT.ERROR_INVALID_IMAGE);
187 if (inputStream.getPosition() < iconHeader[6]) {
188 // Seek to the specified offset
189 try {
190 inputStream.skip(iconHeader[6] - inputStream.getPosition());
191 } catch (IOException e) {
192 DWT.error(DWT.ERROR_IO, e);
193 return null;
194 }
195 }
196 byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize];
197 try {
198 inputStream.read(infoHeader);
199 } catch (IOException e) {
200 DWT.error(DWT.ERROR_IO, e);
201 }
202 if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) !is 1)
203 DWT.error(DWT.ERROR_INVALID_IMAGE);
204 int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
205 int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
206 int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
207 if (height is infoHeight && bitCount is 1) height /= 2;
208 if (!((width is infoWidth) && (height * 2 is infoHeight) &&
209 (bitCount is 1 || bitCount is 4 || bitCount is 8 || bitCount is 24 || bitCount is 32)))
210 DWT.error(DWT.ERROR_INVALID_IMAGE);
211 infoHeader[8] = (byte)(height & 0xFF);
212 infoHeader[9] = (byte)((height >> 8) & 0xFF);
213 infoHeader[10] = (byte)((height >> 16) & 0xFF);
214 infoHeader[11] = (byte)((height >> 24) & 0xFF);
215 return infoHeader;
216 }
217 /**
218 * Unload a single icon
219 */
220 void unloadIcon(ImageData icon) {
221 int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) +
222 ((icon.width + 31) / 32 * 4)) * icon.height;
223 try {
224 outputStream.writeInt(WinBMPFileFormat.BMPHeaderFixedSize);
225 outputStream.writeInt(icon.width);
226 outputStream.writeInt(icon.height * 2);
227 outputStream.writeShort(1);
228 outputStream.writeShort((short)icon.depth);
229 outputStream.writeInt(0);
230 outputStream.writeInt(sizeImage);
231 outputStream.writeInt(0);
232 outputStream.writeInt(0);
233 outputStream.writeInt(icon.palette.colors !is null ? icon.palette.colors.length : 0);
234 outputStream.writeInt(0);
235 } catch (IOException e) {
236 DWT.error(DWT.ERROR_IO, e);
237 }
238
239 byte[] rgbs = WinBMPFileFormat.paletteToBytes(icon.palette);
240 try {
241 outputStream.write(rgbs);
242 } catch (IOException e) {
243 DWT.error(DWT.ERROR_IO, e);
244 }
245 unloadShapeData(icon);
246 unloadMaskData(icon);
247 }
248 /**
249 * Unload the icon header for the given icon, calculating the offset.
250 */
251 void unloadIconHeader(ImageData i) {
252 int headerSize = 16;
253 int offset = headerSize + 6;
254 int iconSize = iconSize(i);
255 try {
256 outputStream.write(i.width);
257 outputStream.write(i.height);
258 outputStream.writeShort(i.palette.colors !is null ? i.palette.colors.length : 0);
259 outputStream.writeShort(0);
260 outputStream.writeShort(0);
261 outputStream.writeInt(iconSize);
262 outputStream.writeInt(offset);
263 } catch (IOException e) {
264 DWT.error(DWT.ERROR_IO, e);
265 }
266 }
267 void unloadIntoByteStream(ImageLoader loader) {
268 /* We do not currently support writing multi-image ico,
269 * so we use the first image data in the loader's array. */
270 ImageData image = loader.data[0];
271 if (!isValidIcon(image))
272 DWT.error(DWT.ERROR_INVALID_IMAGE);
273 try {
274 outputStream.writeShort(0);
275 outputStream.writeShort(1);
276 outputStream.writeShort(1);
277 } catch (IOException e) {
278 DWT.error(DWT.ERROR_IO, e);
279 }
280 unloadIconHeader(image);
281 unloadIcon(image);
282 }
283 /**
284 * Unload the mask data for an icon. The data is flipped vertically
285 * and inverted.
286 */
287 void unloadMaskData(ImageData icon) {
288 ImageData mask = icon.getTransparencyMask();
289 int bpl = (icon.width + 7) / 8;
290 int pad = mask.scanlinePad;
291 int srcBpl = (bpl + pad - 1) / pad * pad;
292 int destBpl = (bpl + 3) / 4 * 4;
293 byte[] buf = new byte[destBpl];
294 int offset = (icon.height - 1) * srcBpl;
295 byte[] data = mask.data;
296 try {
297 for (int i = 0; i < icon.height; i++) {
298 System.arraycopy(data, offset, buf, 0, bpl);
299 bitInvertData(buf, 0, bpl);
300 outputStream.write(buf, 0, destBpl);
301 offset -= srcBpl;
302 }
303 } catch (IOException e) {
304 DWT.error(DWT.ERROR_IO, e);
305 }
306 }
307 /**
308 * Unload the shape data for an icon. The data is flipped vertically.
309 */
310 void unloadShapeData(ImageData icon) {
311 int bpl = (icon.width * icon.depth + 7) / 8;
312 int pad = icon.scanlinePad;
313 int srcBpl = (bpl + pad - 1) / pad * pad;
314 int destBpl = (bpl + 3) / 4 * 4;
315 byte[] buf = new byte[destBpl];
316 int offset = (icon.height - 1) * srcBpl;
317 byte[] data = icon.data;
318 try {
319 for (int i = 0; i < icon.height; i++) {
320 System.arraycopy(data, offset, buf, 0, bpl);
321 outputStream.write(buf, 0, destBpl);
322 offset -= srcBpl;
323 }
324 } catch (IOException e) {
325 DWT.error(DWT.ERROR_IO, e);
326 }
327 }
328 }