Mercurial > projects > dwt-mac
comparison dwt/internal/image/WinBMPFileFormat.d @ 34:5123b17c98ef
Ported dwt.events.*, dwt.graphics.GC, Region, dwt.internal.image.*
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sun, 14 Sep 2008 01:45:57 +0200 |
parents | e831403a80a9 |
children | d8635bb48c7c |
comparison
equal
deleted
inserted
replaced
33:965ac0a77267 | 34:5123b17c98ef |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2006 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
10 *******************************************************************************/ | 12 *******************************************************************************/ |
11 module dwt.internal.image; | 13 module dwt.internal.image.WinBMPFileFormat; |
12 | 14 |
13 | 15 import dwt.internal.image.FileFormat; |
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; | 16 import dwt.graphics.PaletteData; |
22 import dwt.graphics.Point; | 17 import dwt.graphics.Point; |
23 import dwt.graphics.RGB; | 18 import dwt.graphics.RGB; |
24 | 19 import dwt.dwthelper.ByteArrayOutputStream; |
25 public final class WinBMPFileFormat : FileFormat { | 20 import dwt.DWT; |
21 import dwt.dwthelper.utils; | |
22 | |
23 import tango.core.Exception; | |
24 | |
25 final class WinBMPFileFormat : FileFormat { | |
26 | |
26 static final int BMPFileHeaderSize = 14; | 27 static final int BMPFileHeaderSize = 14; |
27 static final int BMPHeaderFixedSize = 40; | 28 static final int BMPHeaderFixedSize = 40; |
28 int importantColors; | 29 int importantColors; |
29 Point pelsPerMeter = new Point(0, 0); | 30 Point pelsPerMeter; |
31 | |
32 public this(){ | |
33 pelsPerMeter = new Point(0, 0); | |
34 } | |
30 | 35 |
31 /** | 36 /** |
32 * Compress numBytes bytes of image data from src, storing in dest | 37 * Compress numBytes bytes of image data from src, storing in dest |
33 * (starting at 0), using the technique specified by comp. | 38 * (starting at 0), using the technique specified by comp. |
34 * If last is true, this indicates the last line of the image. | 39 * If last is true, this indicates the last line of the image. |
108 dest[dp] = 1; dp++; | 113 dest[dp] = 1; dp++; |
109 } else { | 114 } else { |
110 dest[dp] = 0; dp++; | 115 dest[dp] = 0; dp++; |
111 } | 116 } |
112 size += 2; | 117 size += 2; |
113 | 118 |
114 return size; | 119 return size; |
115 } | 120 } |
116 int compressRLE8Data(byte[] src, int srcOffset, int numBytes, byte[] dest, bool last) { | 121 int compressRLE8Data(byte[] src, int srcOffset, int numBytes, byte[] dest, bool last) { |
117 int sp = srcOffset, end = srcOffset + numBytes, dp = 0; | 122 int sp = srcOffset, end = srcOffset + numBytes, dp = 0; |
118 int size = 0, left, i, n; | 123 int size = 0, left, i, n; |
183 dest[dp] = 1; dp++; | 188 dest[dp] = 1; dp++; |
184 } else { | 189 } else { |
185 dest[dp] = 0; dp++; | 190 dest[dp] = 0; dp++; |
186 } | 191 } |
187 size += 2; | 192 size += 2; |
188 | 193 |
189 return size; | 194 return size; |
190 } | 195 } |
191 void decompressData(byte[] src, byte[] dest, int stride, int cmp) { | 196 void decompressData(byte[] src, byte[] dest, int stride, int cmp) { |
192 if (cmp is 1) { // BMP_RLE8_COMPRESSION | 197 if (cmp is 1) { // BMP_RLE8_COMPRESSION |
193 if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0) | 198 if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0) |
325 x += len; | 330 x += len; |
326 } | 331 } |
327 } | 332 } |
328 return 1; | 333 return 1; |
329 } | 334 } |
330 bool isFileFormat(LEDataInputStream stream) { | 335 override bool isFileFormat(LEDataInputStream stream) { |
331 try { | 336 try { |
332 byte[] header = new byte[18]; | 337 byte[] header = new byte[18]; |
333 stream.read(header); | 338 stream.read(header); |
334 stream.unread(header); | 339 stream.unread(header); |
335 int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24); | 340 int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24); |
387 } | 392 } |
388 if (header[0] !is 0x4D42) | 393 if (header[0] !is 0x4D42) |
389 DWT.error(DWT.ERROR_INVALID_IMAGE); | 394 DWT.error(DWT.ERROR_INVALID_IMAGE); |
390 return header; | 395 return header; |
391 } | 396 } |
392 ImageData[] loadFromByteStream() { | 397 override ImageData[] loadFromByteStream() { |
393 int[] fileHeader = loadFileHeader(); | 398 int[] fileHeader = loadFileHeader(); |
394 byte[] infoHeader = new byte[BMPHeaderFixedSize]; | 399 byte[] infoHeader = new byte[BMPHeaderFixedSize]; |
395 try { | 400 try { |
396 inputStream.read(infoHeader); | 401 inputStream.read(infoHeader); |
397 } catch (Exception e) { | 402 } catch (Exception e) { |
415 this.importantColors = (infoHeader[36] & 0xFF) | ((infoHeader[37] & 0xFF) << 8) | ((infoHeader[38] & 0xFF) << 16) | ((infoHeader[39] & 0xFF) << 24); | 420 this.importantColors = (infoHeader[36] & 0xFF) | ((infoHeader[37] & 0xFF) << 8) | ((infoHeader[38] & 0xFF) << 16) | ((infoHeader[39] & 0xFF) << 24); |
416 int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24); | 421 int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24); |
417 int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24); | 422 int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24); |
418 this.pelsPerMeter = new Point(xPelsPerMeter, yPelsPerMeter); | 423 this.pelsPerMeter = new Point(xPelsPerMeter, yPelsPerMeter); |
419 int type = (this.compression is 1 /*BMP_RLE8_COMPRESSION*/) || (this.compression is 2 /*BMP_RLE4_COMPRESSION*/) ? DWT.IMAGE_BMP_RLE : DWT.IMAGE_BMP; | 424 int type = (this.compression is 1 /*BMP_RLE8_COMPRESSION*/) || (this.compression is 2 /*BMP_RLE4_COMPRESSION*/) ? DWT.IMAGE_BMP_RLE : DWT.IMAGE_BMP; |
420 return new ImageData[] { | 425 return [ |
421 ImageData.internal_new( | 426 ImageData.internal_new( |
422 width, | 427 width, |
423 height, | 428 height, |
424 bitCount, | 429 bitCount, |
425 palette, | 430 palette, |
433 type, | 438 type, |
434 0, | 439 0, |
435 0, | 440 0, |
436 0, | 441 0, |
437 0) | 442 0) |
438 }; | 443 ]; |
439 } | 444 } |
440 PaletteData loadPalette(byte[] infoHeader) { | 445 PaletteData loadPalette(byte[] infoHeader) { |
441 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); | 446 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); |
442 if (depth <= 8) { | 447 if (depth <= 8) { |
443 int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24); | 448 int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24); |
504 } | 509 } |
505 return bytes; | 510 return bytes; |
506 } | 511 } |
507 /** | 512 /** |
508 * Unload the given image's data into the given byte stream | 513 * Unload the given image's data into the given byte stream |
509 * using the given compression strategy. | 514 * using the given compression strategy. |
510 * Answer the number of bytes written. | 515 * Answer the number of bytes written. |
511 */ | 516 */ |
512 int unloadData(ImageData image, OutputStream out, int comp) { | 517 int unloadData(ImageData image, OutputStream ostr, int comp) { |
513 int totalSize = 0; | 518 int totalSize = 0; |
514 try { | 519 try { |
515 if (comp is 0) | 520 if (comp is 0) |
516 return unloadDataNoCompression(image, out); | 521 return unloadDataNoCompression(image, ostr); |
517 int bpl = (image.width * image.depth + 7) / 8; | 522 int bpl = (image.width * image.depth + 7) / 8; |
518 int bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes | 523 int bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes |
519 int imageBpl = image.bytesPerLine; | 524 int imageBpl = image.bytesPerLine; |
520 // Compression can actually take twice as much space, in worst case | 525 // Compression can actually take twice as much space, in worst case |
521 byte[] buf = new byte[bmpBpl * 2]; | 526 byte[] buf = new byte[bmpBpl * 2]; |
525 byte[] buf2 = new byte[32768]; | 530 byte[] buf2 = new byte[32768]; |
526 int buf2Offset = 0; | 531 int buf2Offset = 0; |
527 for (int y = image.height - 1; y >= 0; y--) { | 532 for (int y = image.height - 1; y >= 0; y--) { |
528 int lineSize = compress(comp, data, srcOffset, bpl, buf, y is 0); | 533 int lineSize = compress(comp, data, srcOffset, bpl, buf, y is 0); |
529 if (buf2Offset + lineSize > buf2.length) { | 534 if (buf2Offset + lineSize > buf2.length) { |
530 out.write(buf2, 0, buf2Offset); | 535 ostr.write(buf2, 0, buf2Offset); |
531 buf2Offset = 0; | 536 buf2Offset = 0; |
532 } | 537 } |
533 System.arraycopy(buf, 0, buf2, buf2Offset, lineSize); | 538 System.arraycopy(buf, 0, buf2, buf2Offset, lineSize); |
534 buf2Offset += lineSize; | 539 buf2Offset += lineSize; |
535 totalSize += lineSize; | 540 totalSize += lineSize; |
536 srcOffset -= imageBpl; | 541 srcOffset -= imageBpl; |
537 } | 542 } |
538 if (buf2Offset > 0) | 543 if (buf2Offset > 0) |
539 out.write(buf2, 0, buf2Offset); | 544 ostr.write(buf2, 0, buf2Offset); |
540 } catch (IOException e) { | 545 } catch (IOException e) { |
541 DWT.error(DWT.ERROR_IO, e); | 546 DWT.error(DWT.ERROR_IO, e); |
542 } | 547 } |
543 return totalSize; | 548 return totalSize; |
544 } | 549 } |
545 /** | 550 /** |
546 * Prepare the given image's data for unloading into a byte stream | 551 * Prepare the given image's data for unloading into a byte stream |
547 * using no compression strategy. | 552 * using no compression strategy. |
548 * Answer the number of bytes written. | 553 * Answer the number of bytes written. |
549 */ | 554 */ |
550 int unloadDataNoCompression(ImageData image, OutputStream out) { | 555 int unloadDataNoCompression(ImageData image, OutputStream ostr) { |
551 int bmpBpl = 0; | 556 int bmpBpl = 0; |
552 try { | 557 try { |
553 int bpl = (image.width * image.depth + 7) / 8; | 558 int bpl = (image.width * image.depth + 7) / 8; |
554 bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes | 559 bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes |
555 int linesPerBuf = 32678 / bmpBpl; | 560 int linesPerBuf = 32678 / bmpBpl; |
568 buf[bufOffset + wIndex] = data[dataIndex + wIndex]; | 573 buf[bufOffset + wIndex] = data[dataIndex + wIndex]; |
569 } | 574 } |
570 bufOffset += bmpBpl; | 575 bufOffset += bmpBpl; |
571 dataIndex -= imageBpl; | 576 dataIndex -= imageBpl; |
572 } | 577 } |
573 out.write(buf, 0, bufOffset); | 578 ostr.write(buf, 0, bufOffset); |
574 } | 579 } |
575 } else { | 580 } else { |
576 for (int y = 0; y < image.height; y += linesPerBuf) { | 581 for (int y = 0; y < image.height; y += linesPerBuf) { |
577 int tmp = image.height - y; | 582 int tmp = image.height - y; |
578 int count = tmp < linesPerBuf ? tmp : linesPerBuf; | 583 int count = tmp < linesPerBuf ? tmp : linesPerBuf; |
580 for (int i = 0; i < count; i++) { | 585 for (int i = 0; i < count; i++) { |
581 System.arraycopy(data, dataIndex, buf, bufOffset, bpl); | 586 System.arraycopy(data, dataIndex, buf, bufOffset, bpl); |
582 bufOffset += bmpBpl; | 587 bufOffset += bmpBpl; |
583 dataIndex -= imageBpl; | 588 dataIndex -= imageBpl; |
584 } | 589 } |
585 out.write(buf, 0, bufOffset); | 590 ostr.write(buf, 0, bufOffset); |
586 } | 591 } |
587 } | 592 } |
588 } catch (IOException e) { | 593 } catch (IOException e) { |
589 DWT.error(DWT.ERROR_IO, e); | 594 DWT.error(DWT.ERROR_IO, e); |
590 } | 595 } |
592 } | 597 } |
593 /** | 598 /** |
594 * Unload a DeviceIndependentImage using Windows .BMP format into the given | 599 * Unload a DeviceIndependentImage using Windows .BMP format into the given |
595 * byte stream. | 600 * byte stream. |
596 */ | 601 */ |
597 void unloadIntoByteStream(ImageLoader loader) { | 602 override void unloadIntoByteStream(ImageLoader loader) { |
598 ImageData image = loader.data[0]; | 603 ImageData image = loader.data[0]; |
599 byte[] rgbs; | 604 byte[] rgbs; |
600 int numCols; | 605 int numCols; |
601 if (!((image.depth is 1) || (image.depth is 4) || (image.depth is 8) || | 606 if (!((image.depth is 1) || (image.depth is 4) || (image.depth is 8) || |
602 (image.depth is 16) || (image.depth is 24) || (image.depth is 32))) | 607 (image.depth is 16) || (image.depth is 24) || (image.depth is 32))) |
629 fileHeader[4] += rgbs.length; | 634 fileHeader[4] += rgbs.length; |
630 } | 635 } |
631 | 636 |
632 // Prepare data. This is done first so we don't have to try to rewind | 637 // Prepare data. This is done first so we don't have to try to rewind |
633 // the stream and fill in the details later. | 638 // the stream and fill in the details later. |
634 ByteArrayOutputStream out = new ByteArrayOutputStream(); | 639 ByteArrayOutputStream ostr = new ByteArrayOutputStream(); |
635 unloadData(image, out, comp); | 640 unloadData(image, ostr, comp); |
636 byte[] data = out.toByteArray(); | 641 byte[] data = ostr.toByteArray(); |
637 | 642 |
638 // Calculate file size | 643 // Calculate file size |
639 fileHeader[1] = fileHeader[4] + data.length; | 644 fileHeader[1] = fileHeader[4] + data.length; |
640 | 645 |
641 // Write the headers | 646 // Write the headers |
642 try { | 647 try { |
661 outputStream.writeInt(numCols); | 666 outputStream.writeInt(numCols); |
662 outputStream.writeInt(importantColors); | 667 outputStream.writeInt(importantColors); |
663 } catch (IOException e) { | 668 } catch (IOException e) { |
664 DWT.error(DWT.ERROR_IO, e); | 669 DWT.error(DWT.ERROR_IO, e); |
665 } | 670 } |
666 | 671 |
667 // Unload palette | 672 // Unload palette |
668 if (numCols > 0) { | 673 if (numCols > 0) { |
669 try { | 674 try { |
670 outputStream.write(rgbs); | 675 outputStream.write(rgbs); |
671 } catch (IOException e) { | 676 } catch (IOException e) { |