KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > internal > image > WinICOFileFormat


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 package org.eclipse.swt.internal.image;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.graphics.*;
16 import java.io.*;
17
18 final class WinICOFileFormat extends FileFormat {
19     
20 byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
21     // Destructively bit invert data in the given byte array.
22
for (int i = startIndex; i < endIndex; i++) {
23         data[i] = (byte)(255 - data[i - startIndex]);
24     }
25     return data;
26 }
27
28 static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
29     if (pad == newPad) return data;
30     int stride = (width * depth + 7) / 8;
31     int bpl = (stride + (pad - 1)) / pad * pad;
32     int newBpl = (stride + (newPad - 1)) / newPad * newPad;
33     byte[] newData = new byte[height * newBpl];
34     int srcIndex = 0, destIndex = 0;
35     for (int y = 0; y < height; y++) {
36         System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
37         srcIndex += bpl;
38         destIndex += newBpl;
39     }
40     return newData;
41 }
42 /**
43  * Answer the size in bytes of the file representation of the given
44  * icon
45  */

46 int iconSize(ImageData i) {
47     int shapeDataStride = (i.width * i.depth + 31) / 32 * 4;
48     int maskDataStride = (i.width + 31) / 32 * 4;
49     int dataSize = (shapeDataStride + maskDataStride) * i.height;
50     int paletteSize = i.palette.colors != null ? i.palette.colors.length * 4 : 0;
51     return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize;
52 }
53 boolean isFileFormat(LEDataInputStream stream) {
54     try {
55         byte[] header = new byte[4];
56         stream.read(header);
57         stream.unread(header);
58         return header[0] == 0 && header[1] == 0 && header[2] == 1 && header[3] == 0;
59     } catch (Exception JavaDoc e) {
60         return false;
61     }
62 }
63 boolean isValidIcon(ImageData i) {
64     switch (i.depth) {
65         case 1:
66         case 4:
67         case 8:
68             if (i.palette.isDirect) return false;
69             int size = i.palette.colors.length;
70             return size == 2 || size == 16 || size == 32 || size == 256;
71         case 24:
72         case 32:
73             return i.palette.isDirect;
74     }
75     return false;
76 }
77 int loadFileHeader(LEDataInputStream byteStream) {
78     int[] fileHeader = new int[3];
79     try {
80         fileHeader[0] = byteStream.readShort();
81         fileHeader[1] = byteStream.readShort();
82         fileHeader[2] = byteStream.readShort();
83     } catch (IOException e) {
84         SWT.error(SWT.ERROR_IO, e);
85     }
86     if ((fileHeader[0] != 0) || (fileHeader[1] != 1))
87         SWT.error(SWT.ERROR_INVALID_IMAGE);
88     int numIcons = fileHeader[2];
89     if (numIcons <= 0)
90         SWT.error(SWT.ERROR_INVALID_IMAGE);
91     return numIcons;
92 }
93 int loadFileHeader(LEDataInputStream byteStream, boolean hasHeader) {
94     int[] fileHeader = new int[3];
95     try {
96         if (hasHeader) {
97             fileHeader[0] = byteStream.readShort();
98             fileHeader[1] = byteStream.readShort();
99         } else {
100             fileHeader[0] = 0;
101             fileHeader[1] = 1;
102         }
103         fileHeader[2] = byteStream.readShort();
104     } catch (IOException e) {
105         SWT.error(SWT.ERROR_IO, e);
106     }
107     if ((fileHeader[0] != 0) || (fileHeader[1] != 1))
108         SWT.error(SWT.ERROR_INVALID_IMAGE);
109     int numIcons = fileHeader[2];
110     if (numIcons <= 0)
111         SWT.error(SWT.ERROR_INVALID_IMAGE);
112     return numIcons;
113 }
114 ImageData[] loadFromByteStream() {
115     int numIcons = loadFileHeader(inputStream);
116     int[][] headers = loadIconHeaders(numIcons);
117     ImageData[] icons = new ImageData[headers.length];
118     for (int i = 0; i < icons.length; i++) {
119         icons[i] = loadIcon(headers[i]);
120     }
121     return icons;
122 }
123 /**
124  * Load one icon from the byte stream.
125  */

126 ImageData loadIcon(int[] iconHeader) {
127     byte[] infoHeader = loadInfoHeader(iconHeader);
128     WinBMPFileFormat bmpFormat = new WinBMPFileFormat();
129     bmpFormat.inputStream = inputStream;
130     PaletteData palette = bmpFormat.loadPalette(infoHeader);
131     byte[] shapeData = bmpFormat.loadData(infoHeader);
132     int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
133     int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
134     if (height < 0) height = -height;
135     int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
136     infoHeader[14] = 1;
137     infoHeader[15] = 0;
138     byte[] maskData = bmpFormat.loadData(infoHeader);
139     maskData = convertPad(maskData, width, height, 1, 4, 2);
140     bitInvertData(maskData, 0, maskData.length);
141     return ImageData.internal_new(
142         width,
143         height,
144         depth,
145         palette,
146         4,
147         shapeData,
148         2,
149         maskData,
150         null,
151         -1,
152         -1,
153         SWT.IMAGE_ICO,
154         0,
155         0,
156         0,
157         0);
158 }
159 int[][] loadIconHeaders(int numIcons) {
160     int[][] headers = new int[numIcons][7];
161     try {
162         for (int i = 0; i < numIcons; i++) {
163             headers[i][0] = inputStream.read();
164             headers[i][1] = inputStream.read();
165             headers[i][2] = inputStream.readShort();
166             headers[i][3] = inputStream.readShort();
167             headers[i][4] = inputStream.readShort();
168             headers[i][5] = inputStream.readInt();
169             headers[i][6] = inputStream.readInt();
170         }
171     } catch (IOException e) {
172         SWT.error(SWT.ERROR_IO, e);
173     }
174     return headers;
175 }
176 byte[] loadInfoHeader(int[] iconHeader) {
177     int width = iconHeader[0];
178     int height = iconHeader[1];
179     int numColors = iconHeader[2]; // the number of colors is in the low byte, but the high byte must be 0
180
if (numColors == 0) numColors = 256; // this is specified: '00' represents '256' (0x100) colors
181
if ((numColors != 2) && (numColors != 8) && (numColors != 16) &&
182         (numColors != 32) && (numColors != 256))
183         SWT.error(SWT.ERROR_INVALID_IMAGE);
184     if (inputStream.getPosition() < iconHeader[6]) {
185         // Seek to the specified offset
186
try {
187             inputStream.skip(iconHeader[6] - inputStream.getPosition());
188         } catch (IOException e) {
189             SWT.error(SWT.ERROR_IO, e);
190             return null;
191         }
192     }
193     byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize];
194     try {
195         inputStream.read(infoHeader);
196     } catch (IOException e) {
197         SWT.error(SWT.ERROR_IO, e);
198     }
199     if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) != 1)
200         SWT.error(SWT.ERROR_INVALID_IMAGE);
201     int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
202     int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
203     int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
204     if (height == infoHeight && bitCount == 1) height /= 2;
205     if (!((width == infoWidth) && (height * 2 == infoHeight) &&
206         (bitCount == 1 || bitCount == 4 || bitCount == 8 || bitCount == 24 || bitCount == 32)))
207             SWT.error(SWT.ERROR_INVALID_IMAGE);
208     infoHeader[8] = (byte)(height & 0xFF);
209     infoHeader[9] = (byte)((height >> 8) & 0xFF);
210     infoHeader[10] = (byte)((height >> 16) & 0xFF);
211     infoHeader[11] = (byte)((height >> 24) & 0xFF);
212     return infoHeader;
213 }
214 /**
215  * Unload a single icon
216  */

217 void unloadIcon(ImageData icon) {
218     int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) +
219         ((icon.width + 31) / 32 * 4)) * icon.height;
220     try {
221         outputStream.writeInt(WinBMPFileFormat.BMPHeaderFixedSize);
222         outputStream.writeInt(icon.width);
223         outputStream.writeInt(icon.height * 2);
224         outputStream.writeShort(1);
225         outputStream.writeShort((short)icon.depth);
226         outputStream.writeInt(0);
227         outputStream.writeInt(sizeImage);
228         outputStream.writeInt(0);
229         outputStream.writeInt(0);
230         outputStream.writeInt(icon.palette.colors != null ? icon.palette.colors.length : 0);
231         outputStream.writeInt(0);
232     } catch (IOException e) {
233         SWT.error(SWT.ERROR_IO, e);
234     }
235     
236     byte[] rgbs = WinBMPFileFormat.paletteToBytes(icon.palette);
237     try {
238         outputStream.write(rgbs);
239     } catch (IOException e) {
240         SWT.error(SWT.ERROR_IO, e);
241     }
242     unloadShapeData(icon);
243     unloadMaskData(icon);
244 }
245 /**
246  * Unload the icon header for the given icon, calculating the offset.
247  */

248 void unloadIconHeader(ImageData i) {
249     int headerSize = 16;
250     int offset = headerSize + 6;
251     int iconSize = iconSize(i);
252     try {
253         outputStream.write(i.width);
254         outputStream.write(i.height);
255         outputStream.writeShort(i.palette.colors != null ? i.palette.colors.length : 0);
256         outputStream.writeShort(0);
257         outputStream.writeShort(0);
258         outputStream.writeInt(iconSize);
259         outputStream.writeInt(offset);
260     } catch (IOException e) {
261         SWT.error(SWT.ERROR_IO, e);
262     }
263 }
264 void unloadIntoByteStream(ImageLoader loader) {
265     /* We do not currently support writing multi-image ico,
266      * so we use the first image data in the loader's array. */

267     ImageData image = loader.data[0];
268     if (!isValidIcon(image))
269         SWT.error(SWT.ERROR_INVALID_IMAGE);
270     try {
271         outputStream.writeShort(0);
272         outputStream.writeShort(1);
273         outputStream.writeShort(1);
274     } catch (IOException e) {
275         SWT.error(SWT.ERROR_IO, e);
276     }
277     unloadIconHeader(image);
278     unloadIcon(image);
279 }
280 /**
281  * Unload the mask data for an icon. The data is flipped vertically
282  * and inverted.
283  */

284 void unloadMaskData(ImageData icon) {
285     ImageData mask = icon.getTransparencyMask();
286     int bpl = (icon.width + 7) / 8;
287     int pad = mask.scanlinePad;
288     int srcBpl = (bpl + pad - 1) / pad * pad;
289     int destBpl = (bpl + 3) / 4 * 4;
290     byte[] buf = new byte[destBpl];
291     int offset = (icon.height - 1) * srcBpl;
292     byte[] data = mask.data;
293     try {
294         for (int i = 0; i < icon.height; i++) {
295             System.arraycopy(data, offset, buf, 0, bpl);
296             bitInvertData(buf, 0, bpl);
297             outputStream.write(buf, 0, destBpl);
298             offset -= srcBpl;
299         }
300     } catch (IOException e) {
301         SWT.error(SWT.ERROR_IO, e);
302     }
303 }
304 /**
305  * Unload the shape data for an icon. The data is flipped vertically.
306  */

307 void unloadShapeData(ImageData icon) {
308     int bpl = (icon.width * icon.depth + 7) / 8;
309     int pad = icon.scanlinePad;
310     int srcBpl = (bpl + pad - 1) / pad * pad;
311     int destBpl = (bpl + 3) / 4 * 4;
312     byte[] buf = new byte[destBpl];
313     int offset = (icon.height - 1) * srcBpl;
314     byte[] data = icon.data;
315     try {
316         for (int i = 0; i < icon.height; i++) {
317             System.arraycopy(data, offset, buf, 0, bpl);
318             outputStream.write(buf, 0, destBpl);
319             offset -= srcBpl;
320         }
321     } catch (IOException e) {
322         SWT.error(SWT.ERROR_IO, e);
323     }
324 }
325 }
326
Popular Tags