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) {