comparison dwt/internal/image/OS2BMPFileFormat.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, 2005 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.ByteArrayOutputStream;
15 import java.io.IOException;
16 import java.io.OutputStream;
17
18 import dwt.DWT;
19 import dwt.graphics.ImageData;
20 import dwt.graphics.ImageLoader;
21 import dwt.graphics.PaletteData;
22 import dwt.graphics.RGB;
23
24 public final class OS2BMPFileFormat : FileFormat {
25 static final int BMPFileHeaderSize = 14;
26 static final int BMPHeaderFixedSize = 12;
27 int width, height, bitCount;
28
29 bool isFileFormat(LEDataInputStream stream) {
30 try {
31 byte[] header = new byte[18];
32 stream.read(header);
33 stream.unread(header);
34 int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24);
35 return header[0] is 0x42 && header[1] is 0x4D && infoHeaderSize is BMPHeaderFixedSize;
36 } catch (Exception e) {
37 return false;
38 }
39 }
40 byte[] loadData(byte[] infoHeader) {
41 int stride = (width * bitCount + 7) / 8;
42 stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple
43 byte[] data = loadData(infoHeader, stride);
44 flipScanLines(data, stride, height);
45 return data;
46 }
47 byte[] loadData(byte[] infoHeader, int stride) {
48 int dataSize = height * stride;
49 byte[] data = new byte[dataSize];
50 try {
51 if (inputStream.read(data) !is dataSize)
52 DWT.error(DWT.ERROR_INVALID_IMAGE);
53 } catch (IOException e) {
54 DWT.error(DWT.ERROR_IO, e);
55 }
56 return data;
57 }
58 int[] loadFileHeader() {
59 int[] header = new int[5];
60 try {
61 header[0] = inputStream.readShort();
62 header[1] = inputStream.readInt();
63 header[2] = inputStream.readShort();
64 header[3] = inputStream.readShort();
65 header[4] = inputStream.readInt();
66 } catch (IOException e) {
67 DWT.error(DWT.ERROR_IO, e);
68 }
69 if (header[0] !is 0x4D42)
70 DWT.error(DWT.ERROR_INVALID_IMAGE);
71 return header;
72 }
73 ImageData[] loadFromByteStream() {
74 int[] fileHeader = loadFileHeader();
75 byte[] infoHeader = new byte[BMPHeaderFixedSize];
76 try {
77 inputStream.read(infoHeader);
78 } catch (Exception e) {
79 DWT.error(DWT.ERROR_IO, e);
80 }
81 width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8);
82 height = (infoHeader[6] & 0xFF) | ((infoHeader[7] & 0xFF) << 8);
83 bitCount = (infoHeader[10] & 0xFF) | ((infoHeader[11] & 0xFF) << 8);
84 PaletteData palette = loadPalette(infoHeader);
85 if (inputStream.getPosition() < fileHeader[4]) {
86 // Seek to the specified offset
87 try {
88 inputStream.skip(fileHeader[4] - inputStream.getPosition());
89 } catch (IOException e) {
90 DWT.error(DWT.ERROR_IO, e);
91 }
92 }
93 byte[] data = loadData(infoHeader);
94 int type = DWT.IMAGE_OS2_BMP;
95 return new ImageData[] {
96 ImageData.internal_new(
97 width,
98 height,
99 bitCount,
100 palette,
101 4,
102 data,
103 0,
104 null,
105 null,
106 -1,
107 -1,
108 type,
109 0,
110 0,
111 0,
112 0)
113 };
114 }
115 PaletteData loadPalette(byte[] infoHeader) {
116 if (bitCount <= 8) {
117 int numColors = 1 << bitCount;
118 byte[] buf = new byte[numColors * 3];
119 try {
120 if (inputStream.read(buf) !is buf.length)
121 DWT.error(DWT.ERROR_INVALID_IMAGE);
122 } catch (IOException e) {
123 DWT.error(DWT.ERROR_IO, e);
124 }
125 return paletteFromBytes(buf, numColors);
126 }
127 if (bitCount is 16) return new PaletteData(0x7C00, 0x3E0, 0x1F);
128 if (bitCount is 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000);
129 return new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
130 }
131 PaletteData paletteFromBytes(byte[] bytes, int numColors) {
132 int bytesOffset = 0;
133 RGB[] colors = new RGB[numColors];
134 for (int i = 0; i < numColors; i++) {
135 colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF,
136 bytes[bytesOffset + 1] & 0xFF,
137 bytes[bytesOffset] & 0xFF);
138 bytesOffset += 3;
139 }
140 return new PaletteData(colors);
141 }
142 /**
143 * Answer a byte array containing the BMP representation of
144 * the given device independent palette.
145 */
146 static byte[] paletteToBytes(PaletteData pal) {
147 int n = pal.colors is null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256);
148 byte[] bytes = new byte[n * 3];
149 int offset = 0;
150 for (int i = 0; i < n; i++) {
151 RGB col = pal.colors[i];
152 bytes[offset] = (byte)col.blue;
153 bytes[offset + 1] = (byte)col.green;
154 bytes[offset + 2] = (byte)col.red;
155 offset += 3;
156 }
157 return bytes;
158 }
159 /**
160 * Unload the given image's data into the given byte stream.
161 * Answer the number of bytes written.
162 */
163 int unloadData(ImageData image, OutputStream out) {
164 int bmpBpl = 0;
165 try {
166 int bpl = (image.width * image.depth + 7) / 8;
167 bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes
168 int linesPerBuf = 32678 / bmpBpl;
169 byte[] buf = new byte[linesPerBuf * bmpBpl];
170 byte[] data = image.data;
171 int imageBpl = image.bytesPerLine;
172 int dataIndex = imageBpl * (image.height - 1); // Start at last line
173 if (image.depth is 16) {
174 for (int y = 0; y < image.height; y += linesPerBuf) {
175 int count = image.height - y;
176 if (linesPerBuf < count) count = linesPerBuf;
177 int bufOffset = 0;
178 for (int i = 0; i < count; i++) {
179 for (int wIndex = 0; wIndex < bpl; wIndex += 2) {
180 buf[bufOffset + wIndex + 1] = data[dataIndex + wIndex + 1];
181 buf[bufOffset + wIndex] = data[dataIndex + wIndex];
182 }
183 bufOffset += bmpBpl;
184 dataIndex -= imageBpl;
185 }
186 out.write(buf, 0, bufOffset);
187 }
188 } else {
189 for (int y = 0; y < image.height; y += linesPerBuf) {
190 int tmp = image.height - y;
191 int count = tmp < linesPerBuf ? tmp : linesPerBuf;
192 int bufOffset = 0;
193 for (int i = 0; i < count; i++) {
194 System.arraycopy(data, dataIndex, buf, bufOffset, bpl);
195 bufOffset += bmpBpl;
196 dataIndex -= imageBpl;
197 }
198 out.write(buf, 0, bufOffset);
199 }
200 }
201 } catch (IOException e) {
202 DWT.error(DWT.ERROR_IO, e);
203 }
204 return bmpBpl * image.height;
205 }
206 /**
207 * Unload a DeviceIndependentImage using Windows .BMP format into the given
208 * byte stream.
209 */
210 void unloadIntoByteStream(ImageLoader loader) {
211 ImageData image = loader.data[0];
212 byte[] rgbs;
213 int numCols;
214 if (!((image.depth is 1) || (image.depth is 4) || (image.depth is 8) ||
215 (image.depth is 16) || (image.depth is 24) || (image.depth is 32)))
216 DWT.error(DWT.ERROR_UNSUPPORTED_DEPTH);
217 PaletteData pal = image.palette;
218 if ((image.depth is 16) || (image.depth is 24) || (image.depth is 32)) {
219 if (!pal.isDirect)
220 DWT.error(DWT.ERROR_INVALID_IMAGE);
221 numCols = 0;
222 rgbs = null;
223 } else {
224 if (pal.isDirect)
225 DWT.error(DWT.ERROR_INVALID_IMAGE);
226 numCols = pal.colors.length;
227 rgbs = paletteToBytes(pal);
228 }
229 // Fill in file header, except for bfsize, which is done later.
230 int headersSize = BMPFileHeaderSize + BMPHeaderFixedSize;
231 int[] fileHeader = new int[5];
232 fileHeader[0] = 0x4D42; // Signature
233 fileHeader[1] = 0; // File size - filled in later
234 fileHeader[2] = 0; // Reserved 1
235 fileHeader[3] = 0; // Reserved 2
236 fileHeader[4] = headersSize; // Offset to data
237 if (rgbs !is null) {
238 fileHeader[4] += rgbs.length;
239 }
240
241 // Prepare data. This is done first so we don't have to try to rewind
242 // the stream and fill in the details later.
243 ByteArrayOutputStream out = new ByteArrayOutputStream();
244 unloadData(image, out);
245 byte[] data = out.toByteArray();
246
247 // Calculate file size
248 fileHeader[1] = fileHeader[4] + data.length;
249
250 // Write the headers
251 try {
252 outputStream.writeShort(fileHeader[0]);
253 outputStream.writeInt(fileHeader[1]);
254 outputStream.writeShort(fileHeader[2]);
255 outputStream.writeShort(fileHeader[3]);
256 outputStream.writeInt(fileHeader[4]);
257 } catch (IOException e) {
258 DWT.error(DWT.ERROR_IO, e);
259 }
260 try {
261 outputStream.writeInt(BMPHeaderFixedSize);
262 outputStream.writeShort(image.width);
263 outputStream.writeShort(image.height);
264 outputStream.writeShort(1);
265 outputStream.writeShort((short)image.depth);
266 } catch (IOException e) {
267 DWT.error(DWT.ERROR_IO, e);
268 }
269
270 // Unload palette
271 if (numCols > 0) {
272 try {
273 outputStream.write(rgbs);
274 } catch (IOException e) {
275 DWT.error(DWT.ERROR_IO, e);
276 }
277 }
278
279 // Unload the data
280 try {
281 outputStream.write(data);
282 } catch (IOException e) {
283 DWT.error(DWT.ERROR_IO, e);
284 }
285 }
286 void flipScanLines(byte[] data, int stride, int height) {
287 int i1 = 0;
288 int i2 = (height - 1) * stride;
289 for (int i = 0; i < height / 2; i++) {
290 for (int index = 0; index < stride; index++) {
291 byte b = data[index + i1];
292 data[index + i1] = data[index + i2];
293 data[index + i2] = b;
294 }
295 i1 += stride;
296 i2 -= stride;
297 }
298 }
299
300 }