1 81 package com.lowagie.text.pdf.codec; 82 83 import java.io.BufferedInputStream ; 84 import java.io.ByteArrayInputStream ; 85 import java.io.IOException ; 86 import java.io.InputStream ; 87 import java.net.URL ; 88 import java.util.HashMap ; 89 90 import com.lowagie.text.BadElementException; 91 import com.lowagie.text.ExceptionConverter; 92 import com.lowagie.text.Image; 93 import com.lowagie.text.ImgRaw; 94 import com.lowagie.text.Utilities; 95 import com.lowagie.text.pdf.PdfArray; 96 import com.lowagie.text.pdf.PdfDictionary; 97 import com.lowagie.text.pdf.PdfName; 98 import com.lowagie.text.pdf.PdfNumber; 99 import com.lowagie.text.pdf.PdfString; 100 101 107 public class BmpImage { 108 109 private InputStream inputStream; 111 private long bitmapFileSize; 112 private long bitmapOffset; 113 private long compression; 114 private long imageSize; 115 private byte palette[]; 116 private int imageType; 117 private int numBands; 118 private boolean isBottomUp; 119 private int bitsPerPixel; 120 private int redMask, greenMask, blueMask, alphaMask; 121 public HashMap properties = new HashMap (); 122 private long xPelsPerMeter; 123 private long yPelsPerMeter; 124 private static final int VERSION_2_1_BIT = 0; 126 private static final int VERSION_2_4_BIT = 1; 127 private static final int VERSION_2_8_BIT = 2; 128 private static final int VERSION_2_24_BIT = 3; 129 130 private static final int VERSION_3_1_BIT = 4; 131 private static final int VERSION_3_4_BIT = 5; 132 private static final int VERSION_3_8_BIT = 6; 133 private static final int VERSION_3_24_BIT = 7; 134 135 private static final int VERSION_3_NT_16_BIT = 8; 136 private static final int VERSION_3_NT_32_BIT = 9; 137 138 private static final int VERSION_4_1_BIT = 10; 139 private static final int VERSION_4_4_BIT = 11; 140 private static final int VERSION_4_8_BIT = 12; 141 private static final int VERSION_4_16_BIT = 13; 142 private static final int VERSION_4_24_BIT = 14; 143 private static final int VERSION_4_32_BIT = 15; 144 145 private static final int LCS_CALIBRATED_RGB = 0; 147 private static final int LCS_sRGB = 1; 148 private static final int LCS_CMYK = 2; 149 150 private static final int BI_RGB = 0; 152 private static final int BI_RLE8 = 1; 153 private static final int BI_RLE4 = 2; 154 private static final int BI_BITFIELDS = 3; 155 156 int width; 157 int height; 158 159 BmpImage(InputStream is, boolean noHeader, int size) throws IOException { 160 bitmapFileSize = size; 161 bitmapOffset = 0; 162 process(is, noHeader); 163 } 164 165 170 public static Image getImage(URL url) throws IOException { 171 InputStream is = null; 172 try { 173 is = url.openStream(); 174 Image img = getImage(is); 175 img.setUrl(url); 176 return img; 177 } 178 finally { 179 if (is != null) { 180 is.close(); 181 } 182 } 183 } 184 185 190 public static Image getImage(InputStream is) throws IOException { 191 return getImage(is, false, 0); 192 } 193 194 202 public static Image getImage(InputStream is, boolean noHeader, int size) throws IOException { 203 BmpImage bmp = new BmpImage(is, noHeader, size); 204 try { 205 Image img = bmp.getImage(); 206 img.setDpi((int)((double)bmp.xPelsPerMeter * 0.0254), (int)((double)bmp.yPelsPerMeter * 0.0254)); 207 img.setOriginalType(Image.ORIGINAL_BMP); 208 return img; 209 } 210 catch (BadElementException be) { 211 throw new ExceptionConverter(be); 212 } 213 } 214 215 220 public static Image getImage(String file) throws IOException { 221 return getImage(Utilities.toURL(file)); 222 } 223 224 229 public static Image getImage(byte data[]) throws IOException { 230 ByteArrayInputStream is = new ByteArrayInputStream (data); 231 Image img = getImage(is); 232 img.setOriginalData(data); 233 return img; 234 } 235 236 237 protected void process(InputStream stream, boolean noHeader) throws IOException { 238 if (noHeader || stream instanceof BufferedInputStream ) { 239 inputStream = stream; 240 } else { 241 inputStream = new BufferedInputStream (stream); 242 } 243 if (!noHeader) { 244 if (!(readUnsignedByte(inputStream) == 'B' && 246 readUnsignedByte(inputStream) == 'M')) { 247 throw new 248 RuntimeException ("Invalid magic value for BMP file."); 249 } 250 251 bitmapFileSize = readDWord(inputStream); 253 254 readWord(inputStream); 256 readWord(inputStream); 257 258 bitmapOffset = readDWord(inputStream); 260 261 } 263 long size = readDWord(inputStream); 265 266 if (size == 12) { 267 width = readWord(inputStream); 268 height = readWord(inputStream); 269 } else { 270 width = readLong(inputStream); 271 height = readLong(inputStream); 272 } 273 274 int planes = readWord(inputStream); 275 bitsPerPixel = readWord(inputStream); 276 277 properties.put("color_planes", new Integer (planes)); 278 properties.put("bits_per_pixel", new Integer (bitsPerPixel)); 279 280 numBands = 3; 283 if (bitmapOffset == 0) 284 bitmapOffset = size; 285 if (size == 12) { 286 properties.put("bmp_version", "BMP v. 2.x"); 288 289 if (bitsPerPixel == 1) { 291 imageType = VERSION_2_1_BIT; 292 } else if (bitsPerPixel == 4) { 293 imageType = VERSION_2_4_BIT; 294 } else if (bitsPerPixel == 8) { 295 imageType = VERSION_2_8_BIT; 296 } else if (bitsPerPixel == 24) { 297 imageType = VERSION_2_24_BIT; 298 } 299 300 int numberOfEntries = (int)((bitmapOffset-14-size) / 3); 302 int sizeOfPalette = numberOfEntries*3; 303 if (bitmapOffset == size) { 304 switch (imageType) { 305 case VERSION_2_1_BIT: 306 sizeOfPalette = 2 * 3; 307 break; 308 case VERSION_2_4_BIT: 309 sizeOfPalette = 16 * 3; 310 break; 311 case VERSION_2_8_BIT: 312 sizeOfPalette = 256 * 3; 313 break; 314 case VERSION_2_24_BIT: 315 sizeOfPalette = 0; 316 break; 317 } 318 bitmapOffset = size + sizeOfPalette; 319 } 320 readPalette(sizeOfPalette); 321 } else { 322 323 compression = readDWord(inputStream); 324 imageSize = readDWord(inputStream); 325 xPelsPerMeter = readLong(inputStream); 326 yPelsPerMeter = readLong(inputStream); 327 long colorsUsed = readDWord(inputStream); 328 long colorsImportant = readDWord(inputStream); 329 330 switch((int)compression) { 331 case BI_RGB: 332 properties.put("compression", "BI_RGB"); 333 break; 334 335 case BI_RLE8: 336 properties.put("compression", "BI_RLE8"); 337 break; 338 339 case BI_RLE4: 340 properties.put("compression", "BI_RLE4"); 341 break; 342 343 case BI_BITFIELDS: 344 properties.put("compression", "BI_BITFIELDS"); 345 break; 346 } 347 348 properties.put("x_pixels_per_meter", new Long (xPelsPerMeter)); 349 properties.put("y_pixels_per_meter", new Long (yPelsPerMeter)); 350 properties.put("colors_used", new Long (colorsUsed)); 351 properties.put("colors_important", new Long (colorsImportant)); 352 353 if (size == 40) { 354 switch((int)compression) { 356 357 case BI_RGB: case BI_RLE8: case BI_RLE4: 361 if (bitsPerPixel == 1) { 362 imageType = VERSION_3_1_BIT; 363 } else if (bitsPerPixel == 4) { 364 imageType = VERSION_3_4_BIT; 365 } else if (bitsPerPixel == 8) { 366 imageType = VERSION_3_8_BIT; 367 } else if (bitsPerPixel == 24) { 368 imageType = VERSION_3_24_BIT; 369 } else if (bitsPerPixel == 16) { 370 imageType = VERSION_3_NT_16_BIT; 371 redMask = 0x7C00; 372 greenMask = 0x3E0; 373 blueMask = 0x1F; 374 properties.put("red_mask", new Integer (redMask)); 375 properties.put("green_mask", new Integer (greenMask)); 376 properties.put("blue_mask", new Integer (blueMask)); 377 } else if (bitsPerPixel == 32) { 378 imageType = VERSION_3_NT_32_BIT; 379 redMask = 0x00FF0000; 380 greenMask = 0x0000FF00; 381 blueMask = 0x000000FF; 382 properties.put("red_mask", new Integer (redMask)); 383 properties.put("green_mask", new Integer (greenMask)); 384 properties.put("blue_mask", new Integer (blueMask)); 385 } 386 387 int numberOfEntries = (int)((bitmapOffset-14-size) / 4); 389 int sizeOfPalette = numberOfEntries*4; 390 if (bitmapOffset == size) { 391 switch (imageType) { 392 case VERSION_3_1_BIT: 393 sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4; 394 break; 395 case VERSION_3_4_BIT: 396 sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4; 397 break; 398 case VERSION_3_8_BIT: 399 sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4; 400 break; 401 default: 402 sizeOfPalette = 0; 403 break; 404 } 405 bitmapOffset = size + sizeOfPalette; 406 } 407 readPalette(sizeOfPalette); 408 409 properties.put("bmp_version", "BMP v. 3.x"); 410 break; 411 412 case BI_BITFIELDS: 413 414 if (bitsPerPixel == 16) { 415 imageType = VERSION_3_NT_16_BIT; 416 } else if (bitsPerPixel == 32) { 417 imageType = VERSION_3_NT_32_BIT; 418 } 419 420 redMask = (int)readDWord(inputStream); 422 greenMask = (int)readDWord(inputStream); 423 blueMask = (int)readDWord(inputStream); 424 425 properties.put("red_mask", new Integer (redMask)); 426 properties.put("green_mask", new Integer (greenMask)); 427 properties.put("blue_mask", new Integer (blueMask)); 428 429 if (colorsUsed != 0) { 430 sizeOfPalette = (int)colorsUsed*4; 432 readPalette(sizeOfPalette); 433 } 434 435 properties.put("bmp_version", "BMP v. 3.x NT"); 436 break; 437 438 default: 439 throw new 440 RuntimeException ("Invalid compression specified in BMP file."); 441 } 442 } else if (size == 108) { 443 445 properties.put("bmp_version", "BMP v. 4.x"); 446 447 redMask = (int)readDWord(inputStream); 449 greenMask = (int)readDWord(inputStream); 450 blueMask = (int)readDWord(inputStream); 451 alphaMask = (int)readDWord(inputStream); 453 long csType = readDWord(inputStream); 454 int redX = readLong(inputStream); 455 int redY = readLong(inputStream); 456 int redZ = readLong(inputStream); 457 int greenX = readLong(inputStream); 458 int greenY = readLong(inputStream); 459 int greenZ = readLong(inputStream); 460 int blueX = readLong(inputStream); 461 int blueY = readLong(inputStream); 462 int blueZ = readLong(inputStream); 463 long gammaRed = readDWord(inputStream); 464 long gammaGreen = readDWord(inputStream); 465 long gammaBlue = readDWord(inputStream); 466 467 if (bitsPerPixel == 1) { 468 imageType = VERSION_4_1_BIT; 469 } else if (bitsPerPixel == 4) { 470 imageType = VERSION_4_4_BIT; 471 } else if (bitsPerPixel == 8) { 472 imageType = VERSION_4_8_BIT; 473 } else if (bitsPerPixel == 16) { 474 imageType = VERSION_4_16_BIT; 475 if ((int)compression == BI_RGB) { 476 redMask = 0x7C00; 477 greenMask = 0x3E0; 478 blueMask = 0x1F; 479 } 480 } else if (bitsPerPixel == 24) { 481 imageType = VERSION_4_24_BIT; 482 } else if (bitsPerPixel == 32) { 483 imageType = VERSION_4_32_BIT; 484 if ((int)compression == BI_RGB) { 485 redMask = 0x00FF0000; 486 greenMask = 0x0000FF00; 487 blueMask = 0x000000FF; 488 } 489 } 490 491 properties.put("red_mask", new Integer (redMask)); 492 properties.put("green_mask", new Integer (greenMask)); 493 properties.put("blue_mask", new Integer (blueMask)); 494 properties.put("alpha_mask", new Integer (alphaMask)); 495 496 int numberOfEntries = (int)((bitmapOffset-14-size) / 4); 498 int sizeOfPalette = numberOfEntries*4; 499 if (bitmapOffset == size) { 500 switch (imageType) { 501 case VERSION_4_1_BIT: 502 sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4; 503 break; 504 case VERSION_4_4_BIT: 505 sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4; 506 break; 507 case VERSION_4_8_BIT: 508 sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4; 509 break; 510 default: 511 sizeOfPalette = 0; 512 break; 513 } 514 bitmapOffset = size + sizeOfPalette; 515 } 516 readPalette(sizeOfPalette); 517 518 switch((int)csType) { 519 case LCS_CALIBRATED_RGB: 520 properties.put("color_space", "LCS_CALIBRATED_RGB"); 522 properties.put("redX", new Integer (redX)); 523 properties.put("redY", new Integer (redY)); 524 properties.put("redZ", new Integer (redZ)); 525 properties.put("greenX", new Integer (greenX)); 526 properties.put("greenY", new Integer (greenY)); 527 properties.put("greenZ", new Integer (greenZ)); 528 properties.put("blueX", new Integer (blueX)); 529 properties.put("blueY", new Integer (blueY)); 530 properties.put("blueZ", new Integer (blueZ)); 531 properties.put("gamma_red", new Long (gammaRed)); 532 properties.put("gamma_green", new Long (gammaGreen)); 533 properties.put("gamma_blue", new Long (gammaBlue)); 534 535 throw new 537 RuntimeException ("Not implemented yet."); 538 539 case LCS_sRGB: 540 properties.put("color_space", "LCS_sRGB"); 542 break; 543 544 case LCS_CMYK: 545 properties.put("color_space", "LCS_CMYK"); 546 throw new 548 RuntimeException ("Not implemented yet."); 549 } 550 551 } else { 552 properties.put("bmp_version", "BMP v. 5.x"); 553 throw new 554 RuntimeException ("BMP version 5 not implemented yet."); 555 } 556 } 557 558 if (height > 0) { 559 isBottomUp = true; 561 } else { 562 isBottomUp = false; 564 height = Math.abs(height); 565 } 566 if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) { 568 569 numBands = 1; 570 571 572 byte r[], g[], b[]; 574 int sizep; 575 if (imageType == VERSION_2_1_BIT || 576 imageType == VERSION_2_4_BIT || 577 imageType == VERSION_2_8_BIT) { 578 579 sizep = palette.length/3; 580 581 if (sizep > 256) { 582 sizep = 256; 583 } 584 585 int off; 586 r = new byte[sizep]; 587 g = new byte[sizep]; 588 b = new byte[sizep]; 589 for (int i=0; i<sizep; i++) { 590 off = 3 * i; 591 b[i] = palette[off]; 592 g[i] = palette[off+1]; 593 r[i] = palette[off+2]; 594 } 595 } else { 596 sizep = palette.length/4; 597 598 if (sizep > 256) { 599 sizep = 256; 600 } 601 602 int off; 603 r = new byte[sizep]; 604 g = new byte[sizep]; 605 b = new byte[sizep]; 606 for (int i=0; i<sizep; i++) { 607 off = 4 * i; 608 b[i] = palette[off]; 609 g[i] = palette[off+1]; 610 r[i] = palette[off+2]; 611 } 612 } 613 614 } else if (bitsPerPixel == 16) { 615 numBands = 3; 616 } else if (bitsPerPixel == 32) { 617 numBands = alphaMask == 0 ? 3 : 4; 618 619 } else { 622 numBands = 3; 623 } 624 } 625 626 private byte[] getPalette(int group) { 627 if (palette == null) 628 return null; 629 byte np[] = new byte[palette.length / group * 3]; 630 int e = palette.length / group; 631 for (int k = 0; k < e; ++k) { 632 int src = k * group; 633 int dest = k * 3; 634 np[dest + 2] = palette[src++]; 635 np[dest + 1] = palette[src++]; 636 np[dest] = palette[src]; 637 } 638 return np; 639 } 640 641 private Image getImage() throws IOException , BadElementException { 642 byte bdata[] = null; 644 651 switch(imageType) { 653 654 case VERSION_2_1_BIT: 655 return read1Bit(3); 657 658 case VERSION_2_4_BIT: 659 return read4Bit(3); 661 662 case VERSION_2_8_BIT: 663 return read8Bit(3); 665 666 case VERSION_2_24_BIT: 667 bdata = new byte[width * height * 3]; 669 read24Bit(bdata); 670 return new ImgRaw(width, height, 3, 8, bdata); 671 672 case VERSION_3_1_BIT: 673 return read1Bit(4); 675 676 case VERSION_3_4_BIT: 677 switch((int)compression) { 678 case BI_RGB: 679 return read4Bit(4); 680 681 case BI_RLE4: 682 return readRLE4(); 683 684 default: 685 throw new 686 RuntimeException ("Invalid compression specified for BMP file."); 687 } 688 689 case VERSION_3_8_BIT: 690 switch((int)compression) { 691 case BI_RGB: 692 return read8Bit(4); 693 694 case BI_RLE8: 695 return readRLE8(); 696 697 default: 698 throw new 699 RuntimeException ("Invalid compression specified for BMP file."); 700 } 701 702 case VERSION_3_24_BIT: 703 bdata = new byte[width * height * 3]; 705 read24Bit(bdata); 706 return new ImgRaw(width, height, 3, 8, bdata); 707 708 case VERSION_3_NT_16_BIT: 709 return read1632Bit(false); 710 711 case VERSION_3_NT_32_BIT: 712 return read1632Bit(true); 713 714 case VERSION_4_1_BIT: 715 return read1Bit(4); 716 717 case VERSION_4_4_BIT: 718 switch((int)compression) { 719 720 case BI_RGB: 721 return read4Bit(4); 722 723 case BI_RLE4: 724 return readRLE4(); 725 726 default: 727 throw new 728 RuntimeException ("Invalid compression specified for BMP file."); 729 } 730 731 case VERSION_4_8_BIT: 732 switch((int)compression) { 733 734 case BI_RGB: 735 return read8Bit(4); 736 737 case BI_RLE8: 738 return readRLE8(); 739 740 default: 741 throw new 742 RuntimeException ("Invalid compression specified for BMP file."); 743 } 744 745 case VERSION_4_16_BIT: 746 return read1632Bit(false); 747 748 case VERSION_4_24_BIT: 749 bdata = new byte[width * height * 3]; 750 read24Bit(bdata); 751 return new ImgRaw(width, height, 3, 8, bdata); 752 753 case VERSION_4_32_BIT: 754 return read1632Bit(true); 755 } 756 return null; 757 } 758 759 private Image indexedModel(byte bdata[], int bpc, int paletteEntries) throws BadElementException { 760 Image img = new ImgRaw(width, height, 1, bpc, bdata); 761 PdfArray colorspace = new PdfArray(); 762 colorspace.add(PdfName.INDEXED); 763 colorspace.add(PdfName.DEVICERGB); 764 byte np[] = getPalette(paletteEntries); 765 int len = np.length; 766 colorspace.add(new PdfNumber(len / 3 - 1)); 767 colorspace.add(new PdfString(np)); 768 PdfDictionary ad = new PdfDictionary(); 769 ad.put(PdfName.COLORSPACE, colorspace); 770 img.setAdditional(ad); 771 return img; 772 } 773 774 private void readPalette(int sizeOfPalette) throws IOException { 775 if (sizeOfPalette == 0) { 776 return; 777 } 778 779 palette = new byte[sizeOfPalette]; 780 int bytesRead = 0; 781 while (bytesRead < sizeOfPalette) { 782 int r = inputStream.read(palette, bytesRead, sizeOfPalette - bytesRead); 783 if (r < 0) { 784 throw new RuntimeException ("incomplete palette"); 785 } 786 bytesRead += r; 787 } 788 properties.put("palette", palette); 789 } 790 791 private Image read1Bit(int paletteEntries) throws IOException , BadElementException { 793 byte bdata[] = new byte[((width + 7) / 8) * height]; 794 int padding = 0; 795 int bytesPerScanline = (int)Math.ceil((double)width/8.0); 796 797 int remainder = bytesPerScanline % 4; 798 if (remainder != 0) { 799 padding = 4 - remainder; 800 } 801 802 int imSize = (bytesPerScanline + padding) * height; 803 804 byte values[] = new byte[imSize]; 806 int bytesRead = 0; 807 while (bytesRead < imSize) { 808 bytesRead += inputStream.read(values, bytesRead, 809 imSize - bytesRead); 810 } 811 812 if (isBottomUp) { 813 814 817 for (int i=0; i<height; i++) { 818 System.arraycopy(values, 819 imSize - (i+1)*(bytesPerScanline + padding), 820 bdata, 821 i*bytesPerScanline, bytesPerScanline); 822 } 823 } else { 824 825 for (int i=0; i<height; i++) { 826 System.arraycopy(values, 827 i * (bytesPerScanline + padding), 828 bdata, 829 i * bytesPerScanline, 830 bytesPerScanline); 831 } 832 } 833 return indexedModel(bdata, 1, paletteEntries); 834 } 835 836 private Image read4Bit(int paletteEntries) throws IOException , BadElementException { 838 byte bdata[] = new byte[((width + 1) / 2) * height]; 839 840 int padding = 0; 842 843 int bytesPerScanline = (int)Math.ceil((double)width/2.0); 844 int remainder = bytesPerScanline % 4; 845 if (remainder != 0) { 846 padding = 4 - remainder; 847 } 848 849 int imSize = (bytesPerScanline + padding) * height; 850 851 byte values[] = new byte[imSize]; 853 int bytesRead = 0; 854 while (bytesRead < imSize) { 855 bytesRead += inputStream.read(values, bytesRead, 856 imSize - bytesRead); 857 } 858 859 if (isBottomUp) { 860 861 for (int i=0; i<height; i++) { 864 System.arraycopy(values, 865 imSize - (i+1)*(bytesPerScanline + padding), 866 bdata, 867 i*bytesPerScanline, 868 bytesPerScanline); 869 } 870 } else { 871 for (int i=0; i<height; i++) { 872 System.arraycopy(values, 873 i * (bytesPerScanline + padding), 874 bdata, 875 i * bytesPerScanline, 876 bytesPerScanline); 877 } 878 } 879 return indexedModel(bdata, 4, paletteEntries); 880 } 881 882 private Image read8Bit(int paletteEntries) throws IOException , BadElementException { 884 byte bdata[] = new byte[width * height]; 885 int padding = 0; 887 888 int bitsPerScanline = width * 8; 890 if ( bitsPerScanline%32 != 0) { 891 padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline; 892 padding = (int)Math.ceil(padding/8.0); 893 } 894 895 int imSize = (width + padding) * height; 896 897 byte values[] = new byte[imSize]; 899 int bytesRead = 0; 900 while (bytesRead < imSize) { 901 bytesRead += inputStream.read(values, bytesRead, imSize - bytesRead); 902 } 903 904 if (isBottomUp) { 905 906 for (int i=0; i<height; i++) { 909 System.arraycopy(values, 910 imSize - (i+1) * (width + padding), 911 bdata, 912 i * width, 913 width); 914 } 915 } else { 916 for (int i=0; i<height; i++) { 917 System.arraycopy(values, 918 i * (width + padding), 919 bdata, 920 i * width, 921 width); 922 } 923 } 924 return indexedModel(bdata, 8, paletteEntries); 925 } 926 927 private void read24Bit(byte[] bdata) { 929 int padding = 0; 931 932 int bitsPerScanline = width * 24; 934 if ( bitsPerScanline%32 != 0) { 935 padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline; 936 padding = (int)Math.ceil(padding/8.0); 937 } 938 939 940 int imSize = ((width * 3 + 3) / 4 * 4) * height; 941 byte values[] = new byte[imSize]; 943 try { 944 int bytesRead = 0; 945 while (bytesRead < imSize) { 946 int r = inputStream.read(values, bytesRead, 947 imSize - bytesRead); 948 if (r < 0) 949 break; 950 bytesRead += r; 951 } 952 } catch (IOException ioe) { 953 throw new ExceptionConverter(ioe); 954 } 955 956 int l=0, count; 957 958 if (isBottomUp) { 959 int max = width*height*3-1; 960 961 count = -padding; 962 for (int i=0; i<height; i++) { 963 l = max - (i+1)*width*3 + 1; 964 count += padding; 965 for (int j=0; j<width; j++) { 966 bdata[l + 2] = values[count++]; 967 bdata[l + 1] = values[count++]; 968 bdata[l] = values[count++]; 969 l += 3; 970 } 971 } 972 } else { 973 count = -padding; 974 for (int i=0; i<height; i++) { 975 count += padding; 976 for (int j=0; j<width; j++) { 977 bdata[l + 2] = values[count++]; 978 bdata[l + 1] = values[count++]; 979 bdata[l] = values[count++]; 980 l += 3; 981 } 982 } 983 } 984 } 985 986 private int findMask(int mask) { 987 int k = 0; 988 for (; k < 32; ++k) { 989 if ((mask & 1) == 1) 990 break; 991 mask >>>= 1; 992 } 993 return mask; 994 } 995 996 private int findShift(int mask) { 997 int k = 0; 998 for (; k < 32; ++k) { 999 if ((mask & 1) == 1) 1000 break; 1001 mask >>>= 1; 1002 } 1003 return k; 1004 } 1005 1006 private Image read1632Bit(boolean is32) throws IOException , BadElementException { 1007 1008 int red_mask = findMask(redMask); 1009 int red_shift = findShift(redMask); 1010 int red_factor = red_mask + 1; 1011 int green_mask = findMask(greenMask); 1012 int green_shift = findShift(greenMask); 1013 int green_factor = green_mask + 1; 1014 int blue_mask = findMask(blueMask); 1015 int blue_shift = findShift(blueMask); 1016 int blue_factor = blue_mask + 1; 1017 byte bdata[] = new byte[width * height * 3]; 1018 int padding = 0; 1020 1021 if (!is32) { 1022 int bitsPerScanline = width * 16; 1024 if ( bitsPerScanline%32 != 0) { 1025 padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline; 1026 padding = (int)Math.ceil(padding/8.0); 1027 } 1028 } 1029 1030 int imSize = (int)imageSize; 1031 if (imSize == 0) { 1032 imSize = (int)(bitmapFileSize - bitmapOffset); 1033 } 1034 1035 int l=0; 1036 int v; 1037 if (isBottomUp) { 1038 for (int i=height - 1; i >= 0; --i) { 1039 l = width * 3 * i; 1040 for (int j=0; j<width; j++) { 1041 if (is32) 1042 v = (int)readDWord(inputStream); 1043 else 1044 v = readWord(inputStream); 1045 bdata[l++] = (byte)(((v >>> red_shift) & red_mask) * 256 / red_factor); 1046 bdata[l++] = (byte)(((v >>> green_shift) & green_mask) * 256 / green_factor); 1047 bdata[l++] = (byte)(((v >>> blue_shift) & blue_mask) * 256 / blue_factor); 1048 } 1049 for (int m=0; m<padding; m++) { 1050 inputStream.read(); 1051 } 1052 } 1053 } else { 1054 for (int i=0; i<height; i++) { 1055 for (int j=0; j<width; j++) { 1056 if (is32) 1057 v = (int)readDWord(inputStream); 1058 else 1059 v = readWord(inputStream); 1060 bdata[l++] = (byte)(((v >>> red_shift) & red_mask) * 256 / red_factor); 1061 bdata[l++] = (byte)(((v >>> green_shift) & green_mask) * 256 / green_factor); 1062 bdata[l++] = (byte)(((v >>> blue_shift) & blue_mask) * 256 / blue_factor); 1063 } 1064 for (int m=0; m<padding; m++) { 1065 inputStream.read(); 1066 } 1067 } 1068 } 1069 return new ImgRaw(width, height, 3, 8, bdata); 1070 } 1071 1072 private Image readRLE8() throws IOException , BadElementException { 1073 1074 int imSize = (int)imageSize; 1076 if (imSize == 0) { 1077 imSize = (int)(bitmapFileSize - bitmapOffset); 1078 } 1079 1080 byte values[] = new byte[imSize]; 1082 int bytesRead = 0; 1083 while (bytesRead < imSize) { 1084 bytesRead += inputStream.read(values, bytesRead, 1085 imSize - bytesRead); 1086 } 1087 1088 byte val[] = decodeRLE(true, values); 1090 1091 imSize = width * height; 1093 1094 if (isBottomUp) { 1095 1096 byte temp[] = new byte[val.length]; 1100 int bytesPerScanline = width; 1101 for (int i=0; i<height; i++) { 1102 System.arraycopy(val, 1103 imSize - (i+1)*(bytesPerScanline), 1104 temp, 1105 i*bytesPerScanline, bytesPerScanline); 1106 } 1107 val = temp; 1108 } 1109 return indexedModel(val, 8, 4); 1110 } 1111 1112 private Image readRLE4() throws IOException , BadElementException { 1113 1114 int imSize = (int)imageSize; 1116 if (imSize == 0) { 1117 imSize = (int)(bitmapFileSize - bitmapOffset); 1118 } 1119 1120 byte values[] = new byte[imSize]; 1122 int bytesRead = 0; 1123 while (bytesRead < imSize) { 1124 bytesRead += inputStream.read(values, bytesRead, 1125 imSize - bytesRead); 1126 } 1127 1128 byte val[] = decodeRLE(false, values); 1130 1131 if (isBottomUp) { 1133 1134 byte inverted[] = val; 1135 val = new byte[width * height]; 1136 int l = 0, index, lineEnd; 1137 1138 for (int i = height-1; i >= 0; i--) { 1139 index = i * width; 1140 lineEnd = l + width; 1141 while(l != lineEnd) { 1142 val[l++] = inverted[index++]; 1143 } 1144 } 1145 } 1146 int stride = ((width + 1) / 2); 1147 byte bdata[] = new byte[stride * height]; 1148 int ptr = 0; 1149 int sh = 0; 1150 for (int h = 0; h < height; ++h) { 1151 for (int w = 0; w < width; ++w) { 1152 if ((w & 1) == 0) 1153 bdata[sh + w / 2] = (byte)(val[ptr++] << 4); 1154 else 1155 bdata[sh + w / 2] |= (byte)(val[ptr++] & 0x0f); 1156 } 1157 sh += stride; 1158 } 1159 return indexedModel(bdata, 4, 4); 1160 } 1161 1162 private byte[] decodeRLE(boolean is8, byte values[]) { 1163 byte val[] = new byte[width * height]; 1164 try { 1165 int ptr = 0; 1166 int x = 0; 1167 int q = 0; 1168 for (int y = 0; y < height && ptr < values.length;) { 1169 int count = values[ptr++] & 0xff; 1170 if (count != 0) { 1171 int bt = values[ptr++] & 0xff; 1173 if (is8) { 1174 for (int i = count; i != 0; --i) { 1175 val[q++] = (byte)bt; 1176 } 1177 } 1178 else { 1179 for (int i = 0; i < count; ++i) { 1180 val[q++] = (byte)((i & 1) == 1 ? (bt & 0x0f) : ((bt >>> 4) & 0x0f)); 1181 } 1182 } 1183 x += count; 1184 } 1185 else { 1186 count = values[ptr++] & 0xff; 1188 if (count == 1) 1189 break; 1190 switch (count) { 1191 case 0: 1192 x = 0; 1193 ++y; 1194 q = y * width; 1195 break; 1196 case 2: 1197 x += values[ptr++] & 0xff; 1199 y += values[ptr++] & 0xff; 1200 q = y * width + x; 1201 break; 1202 default: 1203 if (is8) { 1205 for (int i = count; i != 0; --i) 1206 val[q++] = (byte)(values[ptr++] & 0xff); 1207 } 1208 else { 1209 int bt = 0; 1210 for (int i = 0; i < count; ++i) { 1211 if ((i & 1) == 0) 1212 bt = values[ptr++] & 0xff; 1213 val[q++] = (byte)((i & 1) == 1 ? (bt & 0x0f) : ((bt >>> 4) & 0x0f)); 1214 } 1215 } 1216 x += count; 1217 if (is8) { 1219 if ((count & 1) == 1) 1220 ++ptr; 1221 } 1222 else { 1223 if ((count & 3) == 1 || (count & 3) == 2) 1224 ++ptr; 1225 } 1226 break; 1227 } 1228 } 1229 } 1230 } 1231 catch (RuntimeException e) { 1232 } 1234 1235 return val; 1236 } 1237 1238 1240 private int readUnsignedByte(InputStream stream) throws IOException { 1242 return (stream.read() & 0xff); 1243 } 1244 1245 private int readUnsignedShort(InputStream stream) throws IOException { 1247 int b1 = readUnsignedByte(stream); 1248 int b2 = readUnsignedByte(stream); 1249 return ((b2 << 8) | b1) & 0xffff; 1250 } 1251 1252 private int readShort(InputStream stream) throws IOException { 1254 int b1 = readUnsignedByte(stream); 1255 int b2 = readUnsignedByte(stream); 1256 return (b2 << 8) | b1; 1257 } 1258 1259 private int readWord(InputStream stream) throws IOException { 1261 return readUnsignedShort(stream); 1262 } 1263 1264 private long readUnsignedInt(InputStream stream) throws IOException { 1266 int b1 = readUnsignedByte(stream); 1267 int b2 = readUnsignedByte(stream); 1268 int b3 = readUnsignedByte(stream); 1269 int b4 = readUnsignedByte(stream); 1270 long l = (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); 1271 return l & 0xffffffff; 1272 } 1273 1274 private int readInt(InputStream stream) throws IOException { 1276 int b1 = readUnsignedByte(stream); 1277 int b2 = readUnsignedByte(stream); 1278 int b3 = readUnsignedByte(stream); 1279 int b4 = readUnsignedByte(stream); 1280 return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1; 1281 } 1282 1283 private long readDWord(InputStream stream) throws IOException { 1285 return readUnsignedInt(stream); 1286 } 1287 1288 private int readLong(InputStream stream) throws IOException { 1290 return readInt(stream); 1291 } 1292} 1293 | Popular Tags |