1 81 82 package com.lowagie.text.pdf.codec; 83 84 import java.awt.color.ICC_Profile ; 85 import java.io.ByteArrayInputStream ; 86 import java.io.ByteArrayOutputStream ; 87 import java.io.DataInputStream ; 88 import java.io.IOException ; 89 import java.io.InputStream ; 90 import java.net.URL ; 91 import java.util.zip.Inflater ; 92 import java.util.zip.InflaterInputStream ; 93 94 import com.lowagie.text.ExceptionConverter; 95 import com.lowagie.text.Image; 96 import com.lowagie.text.ImgRaw; 97 import com.lowagie.text.Utilities; 98 import com.lowagie.text.pdf.ByteBuffer; 99 import com.lowagie.text.pdf.PdfArray; 100 import com.lowagie.text.pdf.PdfDictionary; 101 import com.lowagie.text.pdf.PdfLiteral; 102 import com.lowagie.text.pdf.PdfName; 103 import com.lowagie.text.pdf.PdfNumber; 104 import com.lowagie.text.pdf.PdfObject; 105 import com.lowagie.text.pdf.PdfReader; 106 import com.lowagie.text.pdf.PdfString; 107 108 114 public class PngImage { 115 116 public static final int[] PNGID = {137, 80, 78, 71, 13, 10, 26, 10}; 117 118 119 public static final String IHDR = "IHDR"; 120 121 122 public static final String PLTE = "PLTE"; 123 124 125 public static final String IDAT = "IDAT"; 126 127 128 public static final String IEND = "IEND"; 129 130 131 public static final String tRNS = "tRNS"; 132 133 134 public static final String pHYs = "pHYs"; 135 136 137 public static final String gAMA = "gAMA"; 138 139 140 public static final String cHRM = "cHRM"; 141 142 143 public static final String sRGB = "sRGB"; 144 145 146 public static final String iCCP = "iCCP"; 147 148 private static final int TRANSFERSIZE = 4096; 149 private static final int PNG_FILTER_NONE = 0; 150 private static final int PNG_FILTER_SUB = 1; 151 private static final int PNG_FILTER_UP = 2; 152 private static final int PNG_FILTER_AVERAGE = 3; 153 private static final int PNG_FILTER_PAETH = 4; 154 private static final PdfName intents[] = {PdfName.PERCEPTUAL, 155 PdfName.RELATIVECALORIMETRIC,PdfName.SATURATION,PdfName.ABSOLUTECALORIMETRIC}; 156 157 InputStream is; 158 DataInputStream dataStream; 159 int width; 160 int height; 161 int bitDepth; 162 int colorType; 163 int compressionMethod; 164 int filterMethod; 165 int interlaceMethod; 166 PdfDictionary additional = new PdfDictionary(); 167 byte image[]; 168 byte smask[]; 169 byte trans[]; 170 NewByteArrayOutputStream idat = new NewByteArrayOutputStream(); 171 int dpiX; 172 int dpiY; 173 float XYRatio; 174 boolean genBWMask; 175 boolean palShades; 176 int transRedGray = -1; 177 int transGreen = -1; 178 int transBlue = -1; 179 int inputBands; 180 int bytesPerPixel; byte colorTable[]; 182 float gamma = 1f; 183 boolean hasCHRM = false; 184 float xW, yW, xR, yR, xG, yG, xB, yB; 185 PdfName intent; 186 ICC_Profile icc_profile; 187 188 189 190 191 PngImage(InputStream is) { 192 this.is = is; 193 } 194 195 200 public static Image getImage(URL url) throws IOException { 201 InputStream is = null; 202 try { 203 is = url.openStream(); 204 Image img = getImage(is); 205 img.setUrl(url); 206 return img; 207 } 208 finally { 209 if (is != null) { 210 is.close(); 211 } 212 } 213 } 214 215 220 public static Image getImage(InputStream is) throws IOException { 221 PngImage png = new PngImage(is); 222 return png.getImage(); 223 } 224 225 230 public static Image getImage(String file) throws IOException { 231 return getImage(Utilities.toURL(file)); 232 } 233 234 239 public static Image getImage(byte data[]) throws IOException { 240 ByteArrayInputStream is = new ByteArrayInputStream (data); 241 Image img = getImage(is); 242 img.setOriginalData(data); 243 return img; 244 } 245 246 boolean checkMarker(String s) { 247 if (s.length() != 4) 248 return false; 249 for (int k = 0; k < 4; ++k) { 250 char c = s.charAt(k); 251 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) 252 return false; 253 } 254 return true; 255 } 256 257 void readPng() throws IOException { 258 for (int i = 0; i < PNGID.length; i++) { 259 if (PNGID[i] != is.read()) { 260 throw new IOException ("File is not a valid PNG."); 261 } 262 } 263 byte buffer[] = new byte[TRANSFERSIZE]; 264 while (true) { 265 int len = getInt(is); 266 String marker = getString(is); 267 if (len < 0 || !checkMarker(marker)) 268 throw new IOException ("Corrupted PNG file."); 269 if (IDAT.equals(marker)) { 270 int size; 271 while (len != 0) { 272 size = is.read(buffer, 0, Math.min(len, TRANSFERSIZE)); 273 if (size < 0) 274 return; 275 idat.write(buffer, 0, size); 276 len -= size; 277 } 278 } 279 else if (tRNS.equals(marker)) { 280 switch (colorType) { 281 case 0: 282 if (len >= 2) { 283 len -= 2; 284 int gray = getWord(is); 285 if (bitDepth == 16) 286 transRedGray = gray; 287 else 288 additional.put(PdfName.MASK, new PdfLiteral("["+gray+" "+gray+"]")); 289 } 290 break; 291 case 2: 292 if (len >= 6) { 293 len -= 6; 294 int red = getWord(is); 295 int green = getWord(is); 296 int blue = getWord(is); 297 if (bitDepth == 16) { 298 transRedGray = red; 299 transGreen = green; 300 transBlue = blue; 301 } 302 else 303 additional.put(PdfName.MASK, new PdfLiteral("["+red+" "+red+" "+green+" "+green+" "+blue+" "+blue+"]")); 304 } 305 break; 306 case 3: 307 if (len > 0) { 308 trans = new byte[len]; 309 for (int k = 0; k < len; ++k) 310 trans[k] = (byte)is.read(); 311 len = 0; 312 } 313 break; 314 } 315 Utilities.skip(is, len); 316 } 317 else if (IHDR.equals(marker)) { 318 width = getInt(is); 319 height = getInt(is); 320 321 bitDepth = is.read(); 322 colorType = is.read(); 323 compressionMethod = is.read(); 324 filterMethod = is.read(); 325 interlaceMethod = is.read(); 326 } 327 else if (PLTE.equals(marker)) { 328 if (colorType == 3) { 329 PdfArray colorspace = new PdfArray(); 330 colorspace.add(PdfName.INDEXED); 331 colorspace.add(getColorspace()); 332 colorspace.add(new PdfNumber(len / 3 - 1)); 333 ByteBuffer colortable = new ByteBuffer(); 334 while ((len--) > 0) { 335 colortable.append_i(is.read()); 336 } 337 colorspace.add(new PdfString(colorTable = colortable.toByteArray())); 338 additional.put(PdfName.COLORSPACE, colorspace); 339 } 340 else { 341 Utilities.skip(is, len); 342 } 343 } 344 else if (pHYs.equals(marker)) { 345 int dx = getInt(is); 346 int dy = getInt(is); 347 int unit = is.read(); 348 if (unit == 1) { 349 dpiX = (int)((float)dx * 0.0254f); 350 dpiY = (int)((float)dy * 0.0254f); 351 } 352 else { 353 if (dy != 0) 354 XYRatio = (float)dx / (float)dy; 355 } 356 } 357 else if (cHRM.equals(marker)) { 358 xW = (float)getInt(is) / 100000f; 359 yW = (float)getInt(is) / 100000f; 360 xR = (float)getInt(is) / 100000f; 361 yR = (float)getInt(is) / 100000f; 362 xG = (float)getInt(is) / 100000f; 363 yG = (float)getInt(is) / 100000f; 364 xB = (float)getInt(is) / 100000f; 365 yB = (float)getInt(is) / 100000f; 366 hasCHRM = !(Math.abs(xW)<0.0001f||Math.abs(yW)<0.0001f||Math.abs(xR)<0.0001f||Math.abs(yR)<0.0001f||Math.abs(xG)<0.0001f||Math.abs(yG)<0.0001f||Math.abs(xB)<0.0001f||Math.abs(yB)<0.0001f); 367 } 368 else if (sRGB.equals(marker)) { 369 int ri = is.read(); 370 intent = intents[ri]; 371 gamma = 2.2f; 372 xW = 0.3127f; 373 yW = 0.329f; 374 xR = 0.64f; 375 yR = 0.33f; 376 xG = 0.3f; 377 yG = 0.6f; 378 xB = 0.15f; 379 yB = 0.06f; 380 hasCHRM = true; 381 } 382 else if (gAMA.equals(marker)) { 383 int gm = getInt(is); 384 if (gm != 0) { 385 gamma = 100000f / (float)gm; 386 if (!hasCHRM) { 387 xW = 0.3127f; 388 yW = 0.329f; 389 xR = 0.64f; 390 yR = 0.33f; 391 xG = 0.3f; 392 yG = 0.6f; 393 xB = 0.15f; 394 yB = 0.06f; 395 hasCHRM = true; 396 } 397 } 398 } 399 else if (iCCP.equals(marker)) { 400 do { 401 --len; 402 } while (is.read() != 0); 403 is.read(); 404 --len; 405 byte icccom[] = new byte[len]; 406 int p = 0; 407 while (len > 0) { 408 int r = is.read(icccom, p, len); 409 if (r < 0) 410 throw new IOException ("Premature end of file."); 411 p += r; 412 len -= r; 413 } 414 byte iccp[] = PdfReader.FlateDecode(icccom, true); 415 icccom = null; 416 try { 417 icc_profile = ICC_Profile.getInstance(iccp); 418 } 419 catch (RuntimeException e) { 420 icc_profile = null; 421 } 422 } 423 else if (IEND.equals(marker)) { 424 break; 425 } 426 else { 427 Utilities.skip(is, len); 428 } 429 Utilities.skip(is, 4); 430 } 431 } 432 433 PdfObject getColorspace() { 434 if (icc_profile != null) { 435 if ((colorType & 2) == 0) 436 return PdfName.DEVICEGRAY; 437 else 438 return PdfName.DEVICERGB; 439 } 440 if (gamma == 1f && !hasCHRM) { 441 if ((colorType & 2) == 0) 442 return PdfName.DEVICEGRAY; 443 else 444 return PdfName.DEVICERGB; 445 } 446 else { 447 PdfArray array = new PdfArray(); 448 PdfDictionary dic = new PdfDictionary(); 449 if ((colorType & 2) == 0) { 450 if (gamma == 1f) 451 return PdfName.DEVICEGRAY; 452 array.add(PdfName.CALGRAY); 453 dic.put(PdfName.GAMMA, new PdfNumber(gamma)); 454 dic.put(PdfName.WHITEPOINT, new PdfLiteral("[1 1 1]")); 455 array.add(dic); 456 } 457 else { 458 PdfObject wp = new PdfLiteral("[1 1 1]"); 459 array.add(PdfName.CALRGB); 460 if (gamma != 1f) { 461 PdfArray gm = new PdfArray(); 462 PdfNumber n = new PdfNumber(gamma); 463 gm.add(n); 464 gm.add(n); 465 gm.add(n); 466 dic.put(PdfName.GAMMA, gm); 467 } 468 if (hasCHRM) { 469 float z = yW*((xG-xB)*yR-(xR-xB)*yG+(xR-xG)*yB); 470 float YA = yR*((xG-xB)*yW-(xW-xB)*yG+(xW-xG)*yB)/z; 471 float XA = YA*xR/yR; 472 float ZA = YA*((1-xR)/yR-1); 473 float YB = -yG*((xR-xB)*yW-(xW-xB)*yR+(xW-xR)*yB)/z; 474 float XB = YB*xG/yG; 475 float ZB = YB*((1-xG)/yG-1); 476 float YC = yB*((xR-xG)*yW-(xW-xG)*yW+(xW-xR)*yG)/z; 477 float XC = YC*xB/yB; 478 float ZC = YC*((1-xB)/yB-1); 479 float XW = XA+XB+XC; 480 float YW = 1; float ZW = ZA+ZB+ZC; 482 PdfArray wpa = new PdfArray(); 483 wpa.add(new PdfNumber(XW)); 484 wpa.add(new PdfNumber(YW)); 485 wpa.add(new PdfNumber(ZW)); 486 wp = wpa; 487 PdfArray matrix = new PdfArray(); 488 matrix.add(new PdfNumber(XA)); 489 matrix.add(new PdfNumber(YA)); 490 matrix.add(new PdfNumber(ZA)); 491 matrix.add(new PdfNumber(XB)); 492 matrix.add(new PdfNumber(YB)); 493 matrix.add(new PdfNumber(ZB)); 494 matrix.add(new PdfNumber(XC)); 495 matrix.add(new PdfNumber(YC)); 496 matrix.add(new PdfNumber(ZC)); 497 dic.put(PdfName.MATRIX, matrix); 498 } 499 dic.put(PdfName.WHITEPOINT, wp); 500 array.add(dic); 501 } 502 return array; 503 } 504 } 505 506 Image getImage() throws IOException { 507 readPng(); 508 try { 509 int pal0 = 0; 510 int palIdx = 0; 511 palShades = false; 512 if (trans != null) { 513 for (int k = 0; k < trans.length; ++k) { 514 int n = trans[k] & 0xff; 515 if (n == 0) { 516 ++pal0; 517 palIdx = k; 518 } 519 if (n != 0 && n != 255) { 520 palShades = true; 521 break; 522 } 523 } 524 } 525 if ((colorType & 4) != 0) 526 palShades = true; 527 genBWMask = (!palShades && (pal0 > 1 || transRedGray >= 0)); 528 if (!palShades && !genBWMask && pal0 == 1) { 529 additional.put(PdfName.MASK, new PdfLiteral("["+palIdx+" "+palIdx+"]")); 530 } 531 boolean needDecode = (interlaceMethod == 1) || (bitDepth == 16) || ((colorType & 4) != 0) || palShades || genBWMask; 532 switch (colorType) { 533 case 0: 534 inputBands = 1; 535 break; 536 case 2: 537 inputBands = 3; 538 break; 539 case 3: 540 inputBands = 1; 541 break; 542 case 4: 543 inputBands = 2; 544 break; 545 case 6: 546 inputBands = 4; 547 break; 548 } 549 if (needDecode) 550 decodeIdat(); 551 int components = inputBands; 552 if ((colorType & 4) != 0) 553 --components; 554 int bpc = bitDepth; 555 if (bpc == 16) 556 bpc = 8; 557 Image img; 558 if (image != null) 559 img = Image.getInstance(width, height, components, bpc, image); 560 else { 561 img = new ImgRaw(width, height, components, bpc, idat.toByteArray()); 562 img.setDeflated(true); 563 PdfDictionary decodeparms = new PdfDictionary(); 564 decodeparms.put(PdfName.BITSPERCOMPONENT, new PdfNumber(bitDepth)); 565 decodeparms.put(PdfName.PREDICTOR, new PdfNumber(15)); 566 decodeparms.put(PdfName.COLUMNS, new PdfNumber(width)); 567 decodeparms.put(PdfName.COLORS, new PdfNumber((colorType == 3 || (colorType & 2) == 0) ? 1 : 3)); 568 additional.put(PdfName.DECODEPARMS, decodeparms); 569 } 570 if (additional.get(PdfName.COLORSPACE) == null) 571 additional.put(PdfName.COLORSPACE, getColorspace()); 572 if (intent != null) 573 additional.put(PdfName.INTENT, intent); 574 if (additional.size() > 0) 575 img.setAdditional(additional); 576 if (icc_profile != null) 577 img.tagICC(icc_profile); 578 if (palShades) { 579 Image im2 = Image.getInstance(width, height, 1, 8, smask); 580 im2.makeMask(); 581 img.setImageMask(im2); 582 } 583 if (genBWMask) { 584 Image im2 = Image.getInstance(width, height, 1, 1, smask); 585 im2.makeMask(); 586 img.setImageMask(im2); 587 } 588 img.setDpi(dpiX, dpiY); 589 img.setXYRatio(XYRatio); 590 img.setOriginalType(Image.ORIGINAL_PNG); 591 return img; 592 } 593 catch (Exception e) { 594 throw new ExceptionConverter(e); 595 } 596 } 597 598 void decodeIdat() { 599 int nbitDepth = bitDepth; 600 if (nbitDepth == 16) 601 nbitDepth = 8; 602 int size = -1; 603 bytesPerPixel = (bitDepth == 16) ? 2 : 1; 604 switch (colorType) { 605 case 0: 606 size = (nbitDepth * width + 7) / 8 * height; 607 break; 608 case 2: 609 size = width * 3 * height; 610 bytesPerPixel *= 3; 611 break; 612 case 3: 613 if (interlaceMethod == 1) 614 size = (nbitDepth * width + 7) / 8 * height; 615 bytesPerPixel = 1; 616 break; 617 case 4: 618 size = width * height; 619 bytesPerPixel *= 2; 620 break; 621 case 6: 622 size = width * 3 * height; 623 bytesPerPixel *= 4; 624 break; 625 } 626 if (size >= 0) 627 image = new byte[size]; 628 if (palShades) 629 smask = new byte[width * height]; 630 else if (genBWMask) 631 smask = new byte[(width + 7) / 8 * height]; 632 ByteArrayInputStream bai = new ByteArrayInputStream (idat.getBuf(), 0, idat.size()); 633 InputStream infStream = new InflaterInputStream (bai, new Inflater ()); 634 dataStream = new DataInputStream (infStream); 635 636 if (interlaceMethod != 1) { 637 decodePass(0, 0, 1, 1, width, height); 638 } 639 else { 640 decodePass(0, 0, 8, 8, (width + 7)/8, (height + 7)/8); 641 decodePass(4, 0, 8, 8, (width + 3)/8, (height + 7)/8); 642 decodePass(0, 4, 4, 8, (width + 3)/4, (height + 3)/8); 643 decodePass(2, 0, 4, 4, (width + 1)/4, (height + 3)/4); 644 decodePass(0, 2, 2, 4, (width + 1)/2, (height + 1)/4); 645 decodePass(1, 0, 2, 2, width/2, (height + 1)/2); 646 decodePass(0, 1, 1, 2, width, height/2); 647 } 648 649 } 650 651 void decodePass( int xOffset, int yOffset, 652 int xStep, int yStep, 653 int passWidth, int passHeight) { 654 if ((passWidth == 0) || (passHeight == 0)) { 655 return; 656 } 657 658 int bytesPerRow = (inputBands*passWidth*bitDepth + 7)/8; 659 byte[] curr = new byte[bytesPerRow]; 660 byte[] prior = new byte[bytesPerRow]; 661 662 int srcY, dstY; 664 for (srcY = 0, dstY = yOffset; 665 srcY < passHeight; 666 srcY++, dstY += yStep) { 667 int filter = 0; 669 try { 670 filter = dataStream.read(); 671 dataStream.readFully(curr, 0, bytesPerRow); 672 } catch (Exception e) { 673 } 675 676 switch (filter) { 677 case PNG_FILTER_NONE: 678 break; 679 case PNG_FILTER_SUB: 680 decodeSubFilter(curr, bytesPerRow, bytesPerPixel); 681 break; 682 case PNG_FILTER_UP: 683 decodeUpFilter(curr, prior, bytesPerRow); 684 break; 685 case PNG_FILTER_AVERAGE: 686 decodeAverageFilter(curr, prior, bytesPerRow, bytesPerPixel); 687 break; 688 case PNG_FILTER_PAETH: 689 decodePaethFilter(curr, prior, bytesPerRow, bytesPerPixel); 690 break; 691 default: 692 throw new RuntimeException ("PNG filter unknown."); 694 } 695 696 processPixels(curr, xOffset, xStep, dstY, passWidth); 697 698 byte[] tmp = prior; 700 prior = curr; 701 curr = tmp; 702 } 703 } 704 705 void processPixels(byte curr[], int xOffset, int step, int y, int width) { 706 int srcX, dstX; 707 708 int out[] = getPixel(curr); 709 int sizes = 0; 710 switch (colorType) { 711 case 0: 712 case 3: 713 case 4: 714 sizes = 1; 715 break; 716 case 2: 717 case 6: 718 sizes = 3; 719 break; 720 } 721 if (image != null) { 722 dstX = xOffset; 723 int yStride = (sizes*this.width*(bitDepth == 16 ? 8 : bitDepth)+ 7)/8; 724 for (srcX = 0; srcX < width; srcX++) { 725 setPixel(image, out, inputBands * srcX, sizes, dstX, y, bitDepth, yStride); 726 dstX += step; 727 } 728 } 729 if (palShades) { 730 if ((colorType & 4) != 0) { 731 if (bitDepth == 16) { 732 for (int k = 0; k < width; ++k) 733 out[k * inputBands + sizes] >>>= 8; 734 } 735 int yStride = this.width; 736 dstX = xOffset; 737 for (srcX = 0; srcX < width; srcX++) { 738 setPixel(smask, out, inputBands * srcX + sizes, 1, dstX, y, 8, yStride); 739 dstX += step; 740 } 741 } 742 else { int yStride = this.width; 744 int v[] = new int[1]; 745 dstX = xOffset; 746 for (srcX = 0; srcX < width; srcX++) { 747 int idx = out[srcX]; 748 if (idx < trans.length) 749 v[0] = trans[idx]; 750 setPixel(smask, v, 0, 1, dstX, y, 8, yStride); 751 dstX += step; 752 } 753 } 754 } 755 else if (genBWMask) { 756 switch (colorType) { 757 case 3: { 758 int yStride = (this.width + 7) / 8; 759 int v[] = new int[1]; 760 dstX = xOffset; 761 for (srcX = 0; srcX < width; srcX++) { 762 int idx = out[srcX]; 763 if (idx < trans.length) 764 v[0] = (trans[idx] == 0 ? 1 : 0); 765 setPixel(smask, v, 0, 1, dstX, y, 1, yStride); 766 dstX += step; 767 } 768 break; 769 } 770 case 0: { 771 int yStride = (this.width + 7) / 8; 772 int v[] = new int[1]; 773 dstX = xOffset; 774 for (srcX = 0; srcX < width; srcX++) { 775 int g = out[srcX]; 776 v[0] = (g == transRedGray ? 1 : 0); 777 setPixel(smask, v, 0, 1, dstX, y, 1, yStride); 778 dstX += step; 779 } 780 break; 781 } 782 case 2: { 783 int yStride = (this.width + 7) / 8; 784 int v[] = new int[1]; 785 dstX = xOffset; 786 for (srcX = 0; srcX < width; srcX++) { 787 int markRed = inputBands * srcX; 788 v[0] = (out[markRed] == transRedGray && out[markRed + 1] == transGreen 789 && out[markRed + 2] == transBlue ? 1 : 0); 790 setPixel(smask, v, 0, 1, dstX, y, 1, yStride); 791 dstX += step; 792 } 793 break; 794 } 795 } 796 } 797 } 798 799 static int getPixel(byte image[], int x, int y, int bitDepth, int bytesPerRow) { 800 if (bitDepth == 8) { 801 int pos = bytesPerRow * y + x; 802 return image[pos] & 0xff; 803 } 804 else { 805 int pos = bytesPerRow * y + x / (8 / bitDepth); 806 int v = image[pos] >> (8 - bitDepth * (x % (8 / bitDepth))- bitDepth); 807 return v & ((1 << bitDepth) - 1); 808 } 809 } 810 811 static void setPixel(byte image[], int data[], int offset, int size, int x, int y, int bitDepth, int bytesPerRow) { 812 if (bitDepth == 8) { 813 int pos = bytesPerRow * y + size * x; 814 for (int k = 0; k < size; ++k) 815 image[pos + k] = (byte)data[k + offset]; 816 } 817 else if (bitDepth == 16) { 818 int pos = bytesPerRow * y + size * x; 819 for (int k = 0; k < size; ++k) 820 image[pos + k] = (byte)(data[k + offset] >>> 8); 821 } 822 else { 823 int pos = bytesPerRow * y + x / (8 / bitDepth); 824 int v = data[offset] << (8 - bitDepth * (x % (8 / bitDepth))- bitDepth); 825 image[pos] |= v; 826 } 827 } 828 829 int[] getPixel(byte curr[]) { 830 switch (bitDepth) { 831 case 8: { 832 int out[] = new int[curr.length]; 833 for (int k = 0; k < out.length; ++k) 834 out[k] = curr[k] & 0xff; 835 return out; 836 } 837 case 16: { 838 int out[] = new int[curr.length / 2]; 839 for (int k = 0; k < out.length; ++k) 840 out[k] = ((curr[k * 2] & 0xff) << 8) + (curr[k * 2 + 1] & 0xff); 841 return out; 842 } 843 default: { 844 int out[] = new int[curr.length * 8 / bitDepth]; 845 int idx = 0; 846 int passes = 8 / bitDepth; 847 int mask = (1 << bitDepth) - 1; 848 for (int k = 0; k < curr.length; ++k) { 849 for (int j = passes - 1; j >= 0; --j) { 850 out[idx++] = (curr[k] >>> (bitDepth * j)) & mask; 851 } 852 } 853 return out; 854 } 855 } 856 } 857 858 private static void decodeSubFilter(byte[] curr, int count, int bpp) { 859 for (int i = bpp; i < count; i++) { 860 int val; 861 862 val = curr[i] & 0xff; 863 val += curr[i - bpp] & 0xff; 864 865 curr[i] = (byte)val; 866 } 867 } 868 869 private static void decodeUpFilter(byte[] curr, byte[] prev, 870 int count) { 871 for (int i = 0; i < count; i++) { 872 int raw = curr[i] & 0xff; 873 int prior = prev[i] & 0xff; 874 875 curr[i] = (byte)(raw + prior); 876 } 877 } 878 879 private static void decodeAverageFilter(byte[] curr, byte[] prev, 880 int count, int bpp) { 881 int raw, priorPixel, priorRow; 882 883 for (int i = 0; i < bpp; i++) { 884 raw = curr[i] & 0xff; 885 priorRow = prev[i] & 0xff; 886 887 curr[i] = (byte)(raw + priorRow/2); 888 } 889 890 for (int i = bpp; i < count; i++) { 891 raw = curr[i] & 0xff; 892 priorPixel = curr[i - bpp] & 0xff; 893 priorRow = prev[i] & 0xff; 894 895 curr[i] = (byte)(raw + (priorPixel + priorRow)/2); 896 } 897 } 898 899 private static int paethPredictor(int a, int b, int c) { 900 int p = a + b - c; 901 int pa = Math.abs(p - a); 902 int pb = Math.abs(p - b); 903 int pc = Math.abs(p - c); 904 905 if ((pa <= pb) && (pa <= pc)) { 906 return a; 907 } else if (pb <= pc) { 908 return b; 909 } else { 910 return c; 911 } 912 } 913 914 private static void decodePaethFilter(byte[] curr, byte[] prev, 915 int count, int bpp) { 916 int raw, priorPixel, priorRow, priorRowPixel; 917 918 for (int i = 0; i < bpp; i++) { 919 raw = curr[i] & 0xff; 920 priorRow = prev[i] & 0xff; 921 922 curr[i] = (byte)(raw + priorRow); 923 } 924 925 for (int i = bpp; i < count; i++) { 926 raw = curr[i] & 0xff; 927 priorPixel = curr[i - bpp] & 0xff; 928 priorRow = prev[i] & 0xff; 929 priorRowPixel = prev[i - bpp] & 0xff; 930 931 curr[i] = (byte)(raw + paethPredictor(priorPixel, 932 priorRow, 933 priorRowPixel)); 934 } 935 } 936 937 static class NewByteArrayOutputStream extends ByteArrayOutputStream { 938 public byte[] getBuf() { 939 return buf; 940 } 941 } 942 943 949 950 public static final int getInt(InputStream is) throws IOException { 951 return (is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read(); 952 } 953 954 960 961 public static final int getWord(InputStream is) throws IOException { 962 return (is.read() << 8) + is.read(); 963 } 964 965 971 972 public static final String getString(InputStream is) throws IOException { 973 StringBuffer buf = new StringBuffer (); 974 for (int i = 0; i < 4; i++) { 975 buf.append((char)is.read()); 976 } 977 return buf.toString(); 978 } 979 980 } 981 | Popular Tags |