1 18 package org.apache.batik.ext.awt.image.codec.tiff; 19 20 import java.awt.Rectangle ; 21 import java.awt.color.ColorSpace ; 22 import java.awt.image.BufferedImage ; 23 import java.awt.image.ColorModel ; 24 import java.awt.image.ComponentSampleModel ; 25 import java.awt.image.DataBuffer ; 26 import java.awt.image.DataBufferByte ; 27 import java.awt.image.IndexColorModel ; 28 import java.awt.image.MultiPixelPackedSampleModel ; 29 import java.awt.image.Raster ; 30 import java.awt.image.RenderedImage ; 31 import java.awt.image.SampleModel ; 32 import java.awt.image.WritableRaster ; 33 import java.io.ByteArrayOutputStream ; 34 import java.io.File ; 35 import java.io.FileInputStream ; 36 import java.io.IOException ; 37 import java.io.OutputStream ; 38 import java.io.RandomAccessFile ; 39 import java.util.ArrayList ; 40 import java.util.Iterator ; 41 import java.util.SortedSet ; 42 import java.util.TreeSet ; 43 import java.util.zip.Deflater ; 44 45 import org.apache.batik.ext.awt.image.codec.ImageEncodeParam; 46 import org.apache.batik.ext.awt.image.codec.ImageEncoderImpl; 47 import org.apache.batik.ext.awt.image.codec.SeekableOutputStream; 48 49 import com.sun.image.codec.jpeg.JPEGEncodeParam; 50 import com.sun.image.codec.jpeg.JPEGQTable; 51 52 57 public class TIFFImageEncoder extends ImageEncoderImpl { 58 59 private static final int TIFF_UNSUPPORTED = -1; 61 private static final int TIFF_BILEVEL_WHITE_IS_ZERO = 0; 62 private static final int TIFF_BILEVEL_BLACK_IS_ZERO = 1; 63 private static final int TIFF_GRAY = 2; 64 private static final int TIFF_PALETTE = 3; 65 private static final int TIFF_RGB = 4; 66 private static final int TIFF_CMYK = 5; 67 private static final int TIFF_YCBCR = 6; 68 private static final int TIFF_CIELAB = 7; 69 private static final int TIFF_GENERIC = 8; 70 71 private static final int COMP_NONE = 1; 73 private static final int COMP_JPEG_TTN2 = 7; 74 private static final int COMP_PACKBITS = 32773; 75 private static final int COMP_DEFLATE = 32946; 76 77 private static final int TIFF_JPEG_TABLES = 347; 79 private static final int TIFF_YCBCR_SUBSAMPLING = 530; 80 private static final int TIFF_YCBCR_POSITIONING = 531; 81 private static final int TIFF_REF_BLACK_WHITE = 532; 82 83 private static final int EXTRA_SAMPLE_UNSPECIFIED = 0; 85 private static final int EXTRA_SAMPLE_ASSOCIATED_ALPHA = 1; 86 private static final int EXTRA_SAMPLE_UNASSOCIATED_ALPHA = 2; 87 88 private static final int DEFAULT_ROWS_PER_STRIP = 8; 90 91 public TIFFImageEncoder(OutputStream output, ImageEncodeParam param) { 92 super(output, param); 93 if (this.param == null) { 94 this.param = new TIFFEncodeParam(); 95 } 96 } 97 98 102 public void encode(RenderedImage im) throws IOException { 103 writeFileHeader(); 105 106 TIFFEncodeParam encodeParam = (TIFFEncodeParam)param; 108 109 Iterator iter = encodeParam.getExtraImages(); 110 if(iter != null) { 111 int ifdOffset = 8; 112 RenderedImage nextImage = im; 113 TIFFEncodeParam nextParam = encodeParam; 114 boolean hasNext; 115 do { 116 hasNext = iter.hasNext(); 117 ifdOffset = encode(nextImage, nextParam, ifdOffset, !hasNext); 118 if(hasNext) { 119 Object obj = iter.next(); 120 if(obj instanceof RenderedImage ) { 121 nextImage = (RenderedImage )obj; 122 nextParam = encodeParam; 123 } else if(obj instanceof Object []) { 124 Object [] o = (Object [])obj; 125 nextImage = (RenderedImage )o[0]; 126 nextParam = (TIFFEncodeParam)o[1]; 127 } 128 } 129 } while(hasNext); 130 } else { 131 encode(im, encodeParam, 8, true); 132 } 133 } 134 135 private int encode(RenderedImage im, TIFFEncodeParam encodeParam, 136 int ifdOffset, boolean isLast) throws IOException { 137 int compression = encodeParam.getCompression(); 139 140 boolean isTiled = encodeParam.getWriteTiled(); 142 143 int minX = im.getMinX(); 145 int minY = im.getMinY(); 146 int width = im.getWidth(); 147 int height = im.getHeight(); 148 149 SampleModel sampleModel = im.getSampleModel(); 151 152 int sampleSize[] = sampleModel.getSampleSize(); 154 for(int i = 1; i < sampleSize.length; i++) { 155 if(sampleSize[i] != sampleSize[0]) { 156 throw new Error ("TIFFImageEncoder0"); 157 } 158 } 159 160 int numBands = sampleModel.getNumBands(); 162 if((sampleSize[0] == 1 || sampleSize[0] == 4) && numBands != 1) { 163 throw new Error ("TIFFImageEncoder1"); 164 } 165 166 int dataType = sampleModel.getDataType(); 168 switch(dataType) { 169 case DataBuffer.TYPE_BYTE: 170 if(sampleSize[0] != 1 && sampleSize[0] == 4 && 171 sampleSize[0] != 8) { 172 throw new Error ("TIFFImageEncoder2"); 173 } 174 break; 175 case DataBuffer.TYPE_SHORT: 176 case DataBuffer.TYPE_USHORT: 177 if(sampleSize[0] != 16) { 178 throw new Error ("TIFFImageEncoder3"); 179 } 180 break; 181 case DataBuffer.TYPE_INT: 182 case DataBuffer.TYPE_FLOAT: 183 if(sampleSize[0] != 32) { 184 throw new Error ("TIFFImageEncoder4"); 185 } 186 break; 187 default: 188 throw new Error ("TIFFImageEncoder5"); 189 } 190 191 boolean dataTypeIsShort = 192 dataType == DataBuffer.TYPE_SHORT || 193 dataType == DataBuffer.TYPE_USHORT; 194 195 ColorModel colorModel = im.getColorModel(); 196 if (colorModel != null && 197 colorModel instanceof IndexColorModel && 198 dataType != DataBuffer.TYPE_BYTE) { 199 throw new Error ("TIFFImageEncoder6"); 201 } 202 IndexColorModel icm = null; 203 int sizeOfColormap = 0; 204 char colormap[] = null; 205 206 int imageType = TIFF_UNSUPPORTED; 208 int numExtraSamples = 0; 209 int extraSampleType = EXTRA_SAMPLE_UNSPECIFIED; 210 if(colorModel instanceof IndexColorModel ) { icm = (IndexColorModel )colorModel; 212 int mapSize = icm.getMapSize(); 213 214 if(sampleSize[0] == 1 && numBands == 1) { 216 if (mapSize != 2) { 217 throw new IllegalArgumentException ( 218 "TIFFImageEncoder7"); 219 } 220 221 byte r[] = new byte[mapSize]; 222 icm.getReds(r); 223 byte g[] = new byte[mapSize]; 224 icm.getGreens(g); 225 byte b[] = new byte[mapSize]; 226 icm.getBlues(b); 227 228 if ((r[0] & 0xff) == 0 && 229 (r[1] & 0xff) == 255 && 230 (g[0] & 0xff) == 0 && 231 (g[1] & 0xff) == 255 && 232 (b[0] & 0xff) == 0 && 233 (b[1] & 0xff) == 255) { 234 235 imageType = TIFF_BILEVEL_BLACK_IS_ZERO; 236 237 } else if ((r[0] & 0xff) == 255 && 238 (r[1] & 0xff) == 0 && 239 (g[0] & 0xff) == 255 && 240 (g[1] & 0xff) == 0 && 241 (b[0] & 0xff) == 255 && 242 (b[1] & 0xff) == 0) { 243 244 imageType = TIFF_BILEVEL_WHITE_IS_ZERO; 245 246 } else { 247 imageType = TIFF_PALETTE; 248 } 249 250 } else if(numBands == 1) { imageType = TIFF_PALETTE; 253 } 254 } else if(colorModel == null) { 255 256 if(sampleSize[0] == 1 && numBands == 1) { imageType = TIFF_BILEVEL_BLACK_IS_ZERO; 258 } else { imageType = TIFF_GENERIC; 260 if(numBands > 1) { 261 numExtraSamples = numBands - 1; 262 } 263 } 264 265 } else { ColorSpace colorSpace = colorModel.getColorSpace(); 267 268 switch(colorSpace.getType()) { 269 case ColorSpace.TYPE_CMYK: 270 imageType = TIFF_CMYK; 271 break; 272 case ColorSpace.TYPE_GRAY: 273 imageType = TIFF_GRAY; 274 break; 275 case ColorSpace.TYPE_Lab: 276 imageType = TIFF_CIELAB; 277 break; 278 case ColorSpace.TYPE_RGB: 279 if(compression == COMP_JPEG_TTN2 && 280 encodeParam.getJPEGCompressRGBToYCbCr()) { 281 imageType = TIFF_YCBCR; 282 } else { 283 imageType = TIFF_RGB; 284 } 285 break; 286 case ColorSpace.TYPE_YCbCr: 287 imageType = TIFF_YCBCR; 288 break; 289 default: 290 imageType = TIFF_GENERIC; break; 292 } 293 294 if(imageType == TIFF_GENERIC) { 295 numExtraSamples = numBands - 1; 296 } else if(numBands > 1) { 297 numExtraSamples = numBands - colorSpace.getNumComponents(); 298 } 299 300 if(numExtraSamples == 1 && colorModel.hasAlpha()) { 301 extraSampleType = colorModel.isAlphaPremultiplied() ? 302 EXTRA_SAMPLE_ASSOCIATED_ALPHA : 303 EXTRA_SAMPLE_UNASSOCIATED_ALPHA; 304 } 305 } 306 307 if(imageType == TIFF_UNSUPPORTED) { 308 throw new Error ("TIFFImageEncoder8"); 309 } 310 311 if(compression == COMP_JPEG_TTN2) { 313 if(imageType == TIFF_PALETTE) { 314 throw new Error ("TIFFImageEncoder11"); 315 } else if(!(sampleSize[0] == 8 && 316 (imageType == TIFF_GRAY || 317 imageType == TIFF_RGB || 318 imageType == TIFF_YCBCR))) { 319 throw new Error ("TIFFImageEncoder9"); 320 } 321 } 322 323 int photometricInterpretation = -1; 324 switch (imageType) { 325 326 case TIFF_BILEVEL_WHITE_IS_ZERO: 327 photometricInterpretation = 0; 328 break; 329 330 case TIFF_BILEVEL_BLACK_IS_ZERO: 331 photometricInterpretation = 1; 332 break; 333 334 case TIFF_GRAY: 335 case TIFF_GENERIC: 336 photometricInterpretation = 1; 338 break; 339 340 case TIFF_PALETTE: 341 photometricInterpretation = 3; 342 343 icm = (IndexColorModel )colorModel; 344 sizeOfColormap = icm.getMapSize(); 345 346 byte r[] = new byte[sizeOfColormap]; 347 icm.getReds(r); 348 byte g[] = new byte[sizeOfColormap]; 349 icm.getGreens(g); 350 byte b[] = new byte[sizeOfColormap]; 351 icm.getBlues(b); 352 353 int redIndex = 0, greenIndex = sizeOfColormap; 354 int blueIndex = 2 * sizeOfColormap; 355 colormap = new char[sizeOfColormap * 3]; 356 for (int i=0; i<sizeOfColormap; i++) { 357 colormap[redIndex++] = (char)(((r[i] << 8) | r[i]) & 0xffff); 358 colormap[greenIndex++] = (char)(((g[i] << 8) | g[i]) & 0xffff); 359 colormap[blueIndex++] = (char)(((b[i] << 8) | b[i]) & 0xffff); 360 } 361 362 sizeOfColormap *= 3; 363 364 break; 365 366 case TIFF_RGB: 367 photometricInterpretation = 2; 368 break; 369 370 case TIFF_CMYK: 371 photometricInterpretation = 5; 372 break; 373 374 case TIFF_YCBCR: 375 photometricInterpretation = 6; 376 break; 377 378 case TIFF_CIELAB: 379 photometricInterpretation = 8; 380 break; 381 382 default: 383 throw new Error ("TIFFImageEncoder8"); 384 } 385 386 int tileWidth; 388 int tileHeight; 389 if(isTiled) { 390 tileWidth = encodeParam.getTileWidth() > 0 ? 391 encodeParam.getTileWidth() : im.getTileWidth(); 392 tileHeight = encodeParam.getTileHeight() > 0 ? 393 encodeParam.getTileHeight() : im.getTileHeight(); 394 } else { 395 tileWidth = width; 396 397 tileHeight = encodeParam.getTileHeight() > 0 ? 398 encodeParam.getTileHeight() : DEFAULT_ROWS_PER_STRIP; 399 } 400 401 JPEGEncodeParam jep = null; 403 if(compression == COMP_JPEG_TTN2) { 404 jep = encodeParam.getJPEGEncodeParam(); 406 407 int maxSubH = jep.getHorizontalSubsampling(0); 409 int maxSubV = jep.getVerticalSubsampling(0); 410 for(int i = 1; i < numBands; i++) { 411 int subH = jep.getHorizontalSubsampling(i); 412 if(subH > maxSubH) { 413 maxSubH = subH; 414 } 415 int subV = jep.getVerticalSubsampling(i); 416 if(subV > maxSubV) { 417 maxSubV = subV; 418 } 419 } 420 421 int factorV = 8*maxSubV; 422 tileHeight = 423 (int)((float)tileHeight/(float)factorV + 0.5F)*factorV; 424 if(tileHeight < factorV) { 425 tileHeight = factorV; 426 } 427 428 if(isTiled) { 429 int factorH = 8*maxSubH; 430 tileWidth = 431 (int)((float)tileWidth/(float)factorH + 0.5F)*factorH; 432 if(tileWidth < factorH) { 433 tileWidth = factorH; 434 } 435 } 436 } 437 438 int numTiles; 439 if(isTiled) { 440 numTiles = 442 ((width + tileWidth - 1)/tileWidth) * 443 ((height + tileHeight - 1)/tileHeight); 444 } else { 445 numTiles = (int)Math.ceil((double)height/(double)tileHeight); 446 } 447 448 long tileByteCounts[] = new long[numTiles]; 449 450 long bytesPerRow = 451 (long)Math.ceil((sampleSize[0] / 8.0) * tileWidth * numBands); 452 453 long bytesPerTile = bytesPerRow * tileHeight; 454 455 for (int i=0; i<numTiles; i++) { 456 tileByteCounts[i] = bytesPerTile; 457 } 458 459 if(!isTiled) { 460 long lastStripRows = height - (tileHeight * (numTiles-1)); 462 tileByteCounts[numTiles-1] = lastStripRows * bytesPerRow; 463 } 464 465 long totalBytesOfData = bytesPerTile * (numTiles - 1) + 466 tileByteCounts[numTiles-1]; 467 468 long tileOffsets[] = new long[numTiles]; 471 472 485 SortedSet fields = new TreeSet (); 487 488 fields.add(new TIFFField(TIFFImageDecoder.TIFF_IMAGE_WIDTH, 490 TIFFField.TIFF_LONG, 1, 491 new long[] {width})); 492 493 fields.add(new TIFFField(TIFFImageDecoder.TIFF_IMAGE_LENGTH, 495 TIFFField.TIFF_LONG, 1, 496 new long[] {height})); 497 498 char [] shortSampleSize = new char[numBands]; 499 for (int i=0; i<numBands; i++) 500 shortSampleSize[i] = (char)sampleSize[i]; 501 fields.add(new TIFFField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE, 502 TIFFField.TIFF_SHORT, numBands, 503 shortSampleSize)); 504 505 fields.add(new TIFFField(TIFFImageDecoder.TIFF_COMPRESSION, 506 TIFFField.TIFF_SHORT, 1, 507 new char[] {(char)compression})); 508 509 fields.add( 510 new TIFFField(TIFFImageDecoder.TIFF_PHOTOMETRIC_INTERPRETATION, 511 TIFFField.TIFF_SHORT, 1, 512 new char[] {(char)photometricInterpretation})); 513 514 if(!isTiled) { 515 fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_OFFSETS, 516 TIFFField.TIFF_LONG, numTiles, 517 tileOffsets)); 518 } 519 520 fields.add(new TIFFField(TIFFImageDecoder.TIFF_SAMPLES_PER_PIXEL, 521 TIFFField.TIFF_SHORT, 1, 522 new char[] {(char)numBands})); 523 524 if(!isTiled) { 525 fields.add(new TIFFField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP, 526 TIFFField.TIFF_LONG, 1, 527 new long[] {tileHeight})); 528 529 fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS, 530 TIFFField.TIFF_LONG, numTiles, 531 tileByteCounts)); 532 } 533 534 if (colormap != null) { 535 fields.add(new TIFFField(TIFFImageDecoder.TIFF_COLORMAP, 536 TIFFField.TIFF_SHORT, sizeOfColormap, 537 colormap)); 538 } 539 540 if(isTiled) { 541 fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_WIDTH, 542 TIFFField.TIFF_LONG, 1, 543 new long[] {tileWidth})); 544 545 fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_LENGTH, 546 TIFFField.TIFF_LONG, 1, 547 new long[] {tileHeight})); 548 549 fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_OFFSETS, 550 TIFFField.TIFF_LONG, numTiles, 551 tileOffsets)); 552 553 fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_BYTE_COUNTS, 554 TIFFField.TIFF_LONG, numTiles, 555 tileByteCounts)); 556 } 557 558 if(numExtraSamples > 0) { 559 char[] extraSamples = new char[numExtraSamples]; 560 for(int i = 0; i < numExtraSamples; i++) { 561 extraSamples[i] = (char)extraSampleType; 562 } 563 fields.add(new TIFFField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES, 564 TIFFField.TIFF_SHORT, numExtraSamples, 565 extraSamples)); 566 } 567 568 if(dataType != DataBuffer.TYPE_BYTE) { 570 char[] sampleFormat = new char[numBands]; 572 if(dataType == DataBuffer.TYPE_FLOAT) { 573 sampleFormat[0] = 3; 574 } else if(dataType == DataBuffer.TYPE_USHORT) { 575 sampleFormat[0] = 1; 576 } else { 577 sampleFormat[0] = 2; 578 } 579 for(int b = 1; b < numBands; b++) { 580 sampleFormat[b] = sampleFormat[0]; 581 } 582 fields.add(new TIFFField(TIFFImageDecoder.TIFF_SAMPLE_FORMAT, 583 TIFFField.TIFF_SHORT, numBands, 584 sampleFormat)); 585 586 } 592 593 com.sun.image.codec.jpeg.JPEGEncodeParam jpegEncodeParam = null; 595 com.sun.image.codec.jpeg.JPEGImageEncoder jpegEncoder = null; 596 int jpegColorID = 0; 597 598 if(compression == COMP_JPEG_TTN2) { 599 600 jpegColorID = 602 com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_UNKNOWN; 603 switch(imageType) { 604 case TIFF_GRAY: 605 case TIFF_PALETTE: 606 jpegColorID = 607 com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_GRAY; 608 break; 609 case TIFF_RGB: 610 jpegColorID = 611 com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_RGB; 612 break; 613 case TIFF_YCBCR: 614 jpegColorID = 615 com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_YCbCr; 616 break; 617 } 618 619 Raster tile00 = im.getTile(0, 0); 621 jpegEncodeParam = 622 com.sun.image.codec.jpeg.JPEGCodec.getDefaultJPEGEncodeParam( 623 tile00, jpegColorID); 624 625 modifyEncodeParam(jep, jpegEncodeParam, numBands); 626 627 jpegEncodeParam.setImageInfoValid(false); 629 jpegEncodeParam.setTableInfoValid(true); 630 ByteArrayOutputStream tableStream = 631 new ByteArrayOutputStream (); 632 jpegEncoder = 633 com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder( 634 tableStream, 635 jpegEncodeParam); 636 jpegEncoder.encode(tile00); 637 byte[] tableData = tableStream.toByteArray(); 638 fields.add(new TIFFField(TIFF_JPEG_TABLES, 639 TIFFField.TIFF_UNDEFINED, 640 tableData.length, 641 tableData)); 642 643 jpegEncoder = null; 645 } 646 647 if(imageType == TIFF_YCBCR) { 648 char subsampleH = 1; 651 char subsampleV = 1; 652 653 if(compression == COMP_JPEG_TTN2) { 655 subsampleH = (char)jep.getHorizontalSubsampling(0); 657 subsampleV = (char)jep.getVerticalSubsampling(0); 658 for(int i = 1; i < numBands; i++) { 659 char subH = (char)jep.getHorizontalSubsampling(i); 660 if(subH > subsampleH) { 661 subsampleH = subH; 662 } 663 char subV = (char)jep.getVerticalSubsampling(i); 664 if(subV > subsampleV) { 665 subsampleV = subV; 666 } 667 } 668 } 669 670 fields.add(new TIFFField(TIFF_YCBCR_SUBSAMPLING, 671 TIFFField.TIFF_SHORT, 2, 672 new char[] {subsampleH, subsampleV})); 673 674 675 fields.add(new TIFFField(TIFF_YCBCR_POSITIONING, 677 TIFFField.TIFF_SHORT, 1, 678 new int[] {compression == COMP_JPEG_TTN2 ? 679 1 : 2})); 680 681 long[][] refbw; 683 if(compression == COMP_JPEG_TTN2) { 684 refbw = 685 new long[][] { {0, 1}, {255, 1}, {128, 1}, {255, 1}, {128, 1}, {255, 1} 687 }; 688 } else { 689 refbw = 690 new long[][] { {15, 1}, {235, 1}, {128, 1}, {240, 1}, {128, 1}, {240, 1} 692 }; 693 } 694 fields.add(new TIFFField(TIFF_REF_BLACK_WHITE, 695 TIFFField.TIFF_RATIONAL, 6, 696 refbw)); 697 } 698 699 702 TIFFField[] extraFields = encodeParam.getExtraFields(); 704 if(extraFields != null) { 705 ArrayList extantTags = new ArrayList (fields.size()); 706 Iterator fieldIter = fields.iterator(); 707 while(fieldIter.hasNext()) { 708 TIFFField fld = (TIFFField)fieldIter.next(); 709 extantTags.add(new Integer (fld.getTag())); 710 } 711 712 int numExtraFields = extraFields.length; 713 for(int i = 0; i < numExtraFields; i++) { 714 TIFFField fld = extraFields[i]; 715 Integer tagValue = new Integer (fld.getTag()); 716 if(!extantTags.contains(tagValue)) { 717 fields.add(fld); 718 extantTags.add(tagValue); 719 } 720 } 721 } 722 723 725 int dirSize = getDirectorySize(fields); 729 730 tileOffsets[0] = ifdOffset + dirSize; 733 734 743 OutputStream outCache = null; 744 byte[] compressBuf = null; 745 File tempFile = null; 746 747 int nextIFDOffset = 0; 748 boolean skipByte = false; 749 750 Deflater deflater = null; 751 boolean jpegRGBToYCbCr = false; 752 753 if(compression == COMP_NONE) { 754 int numBytesPadding = 0; 759 if(sampleSize[0] == 16 && tileOffsets[0] % 2 != 0) { 760 numBytesPadding = 1; 761 tileOffsets[0]++; 762 } else if(sampleSize[0] == 32 && tileOffsets[0] % 4 != 0) { 763 numBytesPadding = (int)(4 - tileOffsets[0] % 4); 764 tileOffsets[0] += numBytesPadding; 765 } 766 767 for (int i = 1; i < numTiles; i++) { 769 tileOffsets[i] = tileOffsets[i-1] + tileByteCounts[i-1]; 770 } 771 772 if(!isLast) { 773 nextIFDOffset = (int)(tileOffsets[0] + totalBytesOfData); 775 776 if ((nextIFDOffset&0x01) != 0) { 778 nextIFDOffset++; 779 skipByte = true; 780 } 781 } 782 783 writeDirectory(ifdOffset, fields, nextIFDOffset); 785 786 if(numBytesPadding != 0) { 789 for(int padding = 0; padding < numBytesPadding; padding++) { 790 output.write((byte)0); 791 } 792 } 793 } else { 794 797 if((output instanceof SeekableOutputStream)) { 798 ((SeekableOutputStream)output).seek(tileOffsets[0]); 800 } else { 801 outCache = output; 803 804 try { 805 tempFile = File.createTempFile("jai-SOS-", ".tmp"); 807 tempFile.deleteOnExit(); 808 RandomAccessFile raFile = 809 new RandomAccessFile (tempFile, "rw"); 810 output = new SeekableOutputStream(raFile); 811 812 } catch(Exception e) { 814 output = new ByteArrayOutputStream ((int)totalBytesOfData); 816 } 817 } 818 819 int bufSize = 0; 820 switch(compression) { 821 case COMP_PACKBITS: 822 bufSize = (int)(bytesPerTile + 823 ((bytesPerRow+127)/128)*tileHeight); 824 break; 825 case COMP_JPEG_TTN2: 826 bufSize = 0; 827 828 if(imageType == TIFF_YCBCR && 830 colorModel != null && 831 colorModel.getColorSpace().getType() == 832 ColorSpace.TYPE_RGB) { 833 jpegRGBToYCbCr = true; 834 } 835 case COMP_DEFLATE: 836 bufSize = (int)bytesPerTile; 837 deflater = new Deflater (encodeParam.getDeflateLevel()); 838 break; 839 default: 840 bufSize = 0; 841 } 842 if(bufSize != 0) { 843 compressBuf = new byte[bufSize]; 844 } 845 } 846 847 849 int[] pixels = null; 851 float[] fpixels = null; 852 853 boolean checkContiguous = 855 ((sampleSize[0] == 1 && 856 sampleModel instanceof MultiPixelPackedSampleModel && 857 dataType == DataBuffer.TYPE_BYTE) || 858 (sampleSize[0] == 8 && 859 sampleModel instanceof ComponentSampleModel )); 860 861 byte[] bpixels = null; 864 if(compression != COMP_JPEG_TTN2) { 865 if(dataType == DataBuffer.TYPE_BYTE) { 866 bpixels = new byte[tileHeight * tileWidth * numBands]; 867 } else if(dataTypeIsShort) { 868 bpixels = new byte[2 * tileHeight * tileWidth * numBands]; 869 } else if(dataType == DataBuffer.TYPE_INT || 870 dataType == DataBuffer.TYPE_FLOAT) { 871 bpixels = new byte[4 * tileHeight * tileWidth * numBands]; 872 } 873 } 874 875 int lastRow = minY + height; 877 int lastCol = minX + width; 878 int tileNum = 0; 879 for (int row = minY; row < lastRow; row += tileHeight) { 880 int rows = isTiled ? 881 tileHeight : Math.min(tileHeight, lastRow - row); 882 int size = rows * tileWidth * numBands; 883 884 for(int col = minX; col < lastCol; col += tileWidth) { 885 Raster src = 887 im.getData(new Rectangle (col, row, tileWidth, rows)); 888 889 boolean useDataBuffer = false; 890 if(compression != COMP_JPEG_TTN2) { if(checkContiguous) { 892 if(sampleSize[0] == 8) { ComponentSampleModel csm = 894 (ComponentSampleModel )src.getSampleModel(); 895 int[] bankIndices = csm.getBankIndices(); 896 int[] bandOffsets = csm.getBandOffsets(); 897 int pixelStride = csm.getPixelStride(); 898 int lineStride = csm.getScanlineStride(); 899 900 if(pixelStride != numBands || 901 lineStride != bytesPerRow) { 902 useDataBuffer = false; 903 } else { 904 useDataBuffer = true; 905 for(int i = 0; 906 useDataBuffer && i < numBands; 907 i++) { 908 if(bankIndices[i] != 0 || 909 bandOffsets[i] != i) { 910 useDataBuffer = false; 911 } 912 } 913 } 914 } else { MultiPixelPackedSampleModel mpp = 916 (MultiPixelPackedSampleModel )src.getSampleModel(); 917 if(mpp.getNumBands() == 1 && 918 mpp.getDataBitOffset() == 0 && 919 mpp.getPixelBitStride() == 1) { 920 useDataBuffer = true; 921 } 922 } 923 } 924 925 if(!useDataBuffer) { 926 if(dataType == DataBuffer.TYPE_FLOAT) { 927 fpixels = src.getPixels(col, row, tileWidth, rows, 928 fpixels); 929 } else { 930 pixels = src.getPixels(col, row, tileWidth, rows, 931 pixels); 932 } 933 } 934 } 935 936 int index; 937 938 int pixel = 0; 939 int k = 0; 940 switch(sampleSize[0]) { 941 942 case 1: 943 944 if(useDataBuffer) { 945 byte[] btmp = 946 ((DataBufferByte )src.getDataBuffer()).getData(); 947 MultiPixelPackedSampleModel mpp = 948 (MultiPixelPackedSampleModel )src.getSampleModel(); 949 int lineStride = mpp.getScanlineStride(); 950 int inOffset = 951 mpp.getOffset(col - 952 src.getSampleModelTranslateX(), 953 row - 954 src.getSampleModelTranslateY()); 955 if(lineStride == (int)bytesPerRow) { 956 System.arraycopy(btmp, inOffset, 957 bpixels, 0, 958 (int)bytesPerRow*rows); 959 } else { 960 int outOffset = 0; 961 for(int j = 0; j < rows; j++) { 962 System.arraycopy(btmp, inOffset, 963 bpixels, outOffset, 964 (int)bytesPerRow); 965 inOffset += lineStride; 966 outOffset += (int)bytesPerRow; 967 } 968 } 969 } else { 970 index = 0; 971 972 for (int i=0; i<rows; i++) { 974 975 for (int j=0; j<tileWidth/8; j++) { 977 978 pixel = 979 (pixels[index++] << 7) | 980 (pixels[index++] << 6) | 981 (pixels[index++] << 5) | 982 (pixels[index++] << 4) | 983 (pixels[index++] << 3) | 984 (pixels[index++] << 2) | 985 (pixels[index++] << 1) | 986 pixels[index++]; 987 bpixels[k++] = (byte)pixel; 988 } 989 990 if (tileWidth%8 > 0) { 992 pixel = 0; 993 for (int j=0; j<tileWidth%8; j++) { 994 pixel |= (pixels[index++] << (7 - j)); 995 } 996 bpixels[k++] = (byte)pixel; 997 } 998 } 999 } 1000 1001 if(compression == COMP_NONE) { 1002 output.write(bpixels, 0, rows * ((tileWidth+7)/8)); 1003 } else if(compression == COMP_PACKBITS) { 1004 int numCompressedBytes = 1005 compressPackBits(bpixels, rows, 1006 (int)bytesPerRow, 1007 compressBuf); 1008 tileByteCounts[tileNum++] = numCompressedBytes; 1009 output.write(compressBuf, 0, numCompressedBytes); 1010 } else if(compression == COMP_DEFLATE) { 1011 int numCompressedBytes = 1012 deflate(deflater, bpixels, compressBuf); 1013 tileByteCounts[tileNum++] = numCompressedBytes; 1014 output.write(compressBuf, 0, numCompressedBytes); 1015 } 1016 1017 break; 1018 1019 case 4: 1020 1021 index = 0; 1022 1023 for (int i=0; i<rows; i++) { 1025 1026 for (int j=0; j<tileWidth/2; j++) { 1029 pixel = (pixels[index++] << 4) | pixels[index++]; 1030 bpixels[k++] = (byte)pixel; 1031 } 1032 1033 if ((tileWidth % 2) == 1) { 1035 pixel = pixels[index++] << 4; 1036 bpixels[k++] = (byte)pixel; 1037 } 1038 } 1039 1040 if(compression == COMP_NONE) { 1041 output.write(bpixels, 0, rows * ((tileWidth+1)/2)); 1042 } else if(compression == COMP_PACKBITS) { 1043 int numCompressedBytes = 1044 compressPackBits(bpixels, rows, 1045 (int)bytesPerRow, 1046 compressBuf); 1047 tileByteCounts[tileNum++] = numCompressedBytes; 1048 output.write(compressBuf, 0, numCompressedBytes); 1049 } else if(compression == COMP_DEFLATE) { 1050 int numCompressedBytes = 1051 deflate(deflater, bpixels, compressBuf); 1052 tileByteCounts[tileNum++] = numCompressedBytes; 1053 output.write(compressBuf, 0, numCompressedBytes); 1054 } 1055 break; 1056 1057 case 8: 1058 1059 if(compression != COMP_JPEG_TTN2) { 1060 if(useDataBuffer) { 1061 byte[] btmp = 1062 ((DataBufferByte )src.getDataBuffer()).getData(); 1063 ComponentSampleModel csm = 1064 (ComponentSampleModel )src.getSampleModel(); 1065 int inOffset = 1066 csm.getOffset(col - 1067 src.getSampleModelTranslateX(), 1068 row - 1069 src.getSampleModelTranslateY()); 1070 int lineStride = csm.getScanlineStride(); 1071 if(lineStride == (int)bytesPerRow) { 1072 System.arraycopy(btmp, 1073 inOffset, 1074 bpixels, 0, 1075 (int)bytesPerRow*rows); 1076 } else { 1077 int outOffset = 0; 1078 for(int j = 0; j < rows; j++) { 1079 System.arraycopy(btmp, inOffset, 1080 bpixels, outOffset, 1081 (int)bytesPerRow); 1082 inOffset += lineStride; 1083 outOffset += (int)bytesPerRow; 1084 } 1085 } 1086 } else { 1087 for (int i = 0; i < size; i++) { 1088 bpixels[i] = (byte)pixels[i]; 1089 } 1090 } 1091 } 1092 1093 if(compression == COMP_NONE) { 1094 output.write(bpixels, 0, size); 1095 } else if(compression == COMP_PACKBITS) { 1096 int numCompressedBytes = 1097 compressPackBits(bpixels, rows, 1098 (int)bytesPerRow, 1099 compressBuf); 1100 tileByteCounts[tileNum++] = numCompressedBytes; 1101 output.write(compressBuf, 0, numCompressedBytes); 1102 } else if(compression == COMP_JPEG_TTN2) { 1103 long startPos = getOffset(output); 1104 1105 if(jpegEncoder == null || 1109 jpegEncodeParam.getWidth() != src.getWidth() || 1110 jpegEncodeParam.getHeight() != src.getHeight()) { 1111 1112 jpegEncodeParam = 1113 com.sun.image.codec.jpeg.JPEGCodec. 1114 getDefaultJPEGEncodeParam(src, jpegColorID); 1115 1116 modifyEncodeParam(jep, jpegEncodeParam, 1117 numBands); 1118 1119 jpegEncoder = 1120 com.sun.image.codec.jpeg.JPEGCodec. 1121 createJPEGEncoder(output, jpegEncodeParam); 1122 } 1123 1124 if(jpegRGBToYCbCr) { 1125 WritableRaster wRas = null; 1126 if(src instanceof WritableRaster ) { 1127 wRas = (WritableRaster )src; 1128 } else { 1129 wRas = src.createCompatibleWritableRaster(); 1130 wRas.setRect(src); 1131 } 1132 1133 if (wRas.getMinX() != 0 || wRas.getMinY() != 0) { 1134 wRas = 1135 wRas.createWritableTranslatedChild(0, 0); 1136 } 1137 BufferedImage bi = 1138 new BufferedImage (colorModel, wRas, 1139 false, null); 1140 jpegEncoder.encode(bi); 1141 } else { 1142 jpegEncoder.encode(src.createTranslatedChild(0, 1143 0)); 1144 } 1145 1146 long endPos = getOffset(output); 1147 tileByteCounts[tileNum++] = (int)(endPos - startPos); 1148 } else if(compression == COMP_DEFLATE) { 1149 int numCompressedBytes = 1150 deflate(deflater, bpixels, compressBuf); 1151 tileByteCounts[tileNum++] = numCompressedBytes; 1152 output.write(compressBuf, 0, numCompressedBytes); 1153 } 1154 break; 1155 1156 case 16: 1157 1158 int ls = 0; 1159 for (int i = 0; i < size; i++) { 1160 short value = (short)pixels[i]; 1161 bpixels[ls++] = (byte)((value & 0xff00) >> 8); 1162 bpixels[ls++] = (byte)(value & 0x00ff); 1163 } 1164 1165 if(compression == COMP_NONE) { 1166 output.write(bpixels, 0, size*2); 1167 } else if(compression == COMP_PACKBITS) { 1168 int numCompressedBytes = 1169 compressPackBits(bpixels, rows, 1170 (int)bytesPerRow, 1171 compressBuf); 1172 tileByteCounts[tileNum++] = numCompressedBytes; 1173 output.write(compressBuf, 0, numCompressedBytes); 1174 } else if(compression == COMP_DEFLATE) { 1175 int numCompressedBytes = 1176 deflate(deflater, bpixels, compressBuf); 1177 tileByteCounts[tileNum++] = numCompressedBytes; 1178 output.write(compressBuf, 0, numCompressedBytes); 1179 } 1180 break; 1181 1182 case 32: 1183 if(dataType == DataBuffer.TYPE_INT) { 1184 int li = 0; 1185 for (int i = 0; i < size; i++) { 1186 int value = pixels[i]; 1187 bpixels[li++] = (byte)((value & 0xff000000) >> 24); 1188 bpixels[li++] = (byte)((value & 0x00ff0000) >> 16); 1189 bpixels[li++] = (byte)((value & 0x0000ff00) >> 8); 1190 bpixels[li++] = (byte)(value & 0x000000ff); 1191 } 1192 } else { int lf = 0; 1194 for (int i = 0; i < size; i++) { 1195 int value = Float.floatToIntBits(fpixels[i]); 1196 bpixels[lf++] = (byte)((value & 0xff000000) >> 24); 1197 bpixels[lf++] = (byte)((value & 0x00ff0000) >> 16); 1198 bpixels[lf++] = (byte)((value & 0x0000ff00) >> 8); 1199 bpixels[lf++] = (byte)(value & 0x000000ff); 1200 } 1201 } 1202 if(compression == COMP_NONE) { 1203 output.write(bpixels, 0, size*4); 1204 } else if(compression == COMP_PACKBITS) { 1205 int numCompressedBytes = 1206 compressPackBits(bpixels, rows, 1207 (int)bytesPerRow, 1208 compressBuf); 1209 tileByteCounts[tileNum++] = numCompressedBytes; 1210 output.write(compressBuf, 0, numCompressedBytes); 1211 } else if(compression == COMP_DEFLATE) { 1212 int numCompressedBytes = 1213 deflate(deflater, bpixels, compressBuf); 1214 tileByteCounts[tileNum++] = numCompressedBytes; 1215 output.write(compressBuf, 0, numCompressedBytes); 1216 } 1217 break; 1218 1219 } 1220 } 1221 } 1222 1223 if(compression == COMP_NONE) { 1224 if(skipByte) { 1226 output.write((byte)0); 1227 } 1228 } else { 1229 int totalBytes = 0; 1231 for (int i=1; i<numTiles; i++) { 1232 int numBytes = (int)tileByteCounts[i-1]; 1233 totalBytes += numBytes; 1234 tileOffsets[i] = tileOffsets[i-1] + numBytes; 1235 } 1236 totalBytes += (int)tileByteCounts[numTiles-1]; 1237 1238 nextIFDOffset = isLast ? 1239 0 : ifdOffset + dirSize + totalBytes; 1240 if ((nextIFDOffset&0x01) != 0) { 1241 nextIFDOffset++; 1242 skipByte = true; 1243 } 1244 1245 if(outCache == null) { 1246 1248 if(skipByte) { 1250 output.write((byte)0); 1251 } 1252 1253 SeekableOutputStream sos = (SeekableOutputStream)output; 1254 1255 long savePos = sos.getFilePointer(); 1257 1258 sos.seek(ifdOffset); 1260 writeDirectory(ifdOffset, fields, nextIFDOffset); 1261 1262 sos.seek(savePos); 1264 } else if(tempFile != null) { 1265 1266 1268 FileInputStream fileStream = new FileInputStream (tempFile); 1270 1271 output.close(); 1273 1274 output = outCache; 1276 1277 writeDirectory(ifdOffset, fields, nextIFDOffset); 1279 1280 byte[] copyBuffer = new byte[8192]; 1282 int bytesCopied = 0; 1283 while(bytesCopied < totalBytes) { 1284 int bytesRead = fileStream.read(copyBuffer); 1285 if(bytesRead == -1) { 1286 break; 1287 } 1288 output.write(copyBuffer, 0, bytesRead); 1289 bytesCopied += bytesRead; 1290 } 1291 1292 fileStream.close(); 1294 tempFile.delete(); 1295 1296 if(skipByte) { 1298 output.write((byte)0); 1299 } 1300 } else if(output instanceof ByteArrayOutputStream ) { 1301 1302 1304 ByteArrayOutputStream memoryStream = 1305 (ByteArrayOutputStream )output; 1306 1307 output = outCache; 1309 1310 writeDirectory(ifdOffset, fields, nextIFDOffset); 1312 1313 memoryStream.writeTo(output); 1315 1316 if(skipByte) { 1318 output.write((byte)0); 1319 } 1320 } else { 1321 throw new IllegalStateException (); 1323 } 1324 } 1325 1326 1327 return nextIFDOffset; 1328 } 1329 1330 1333 private int getDirectorySize(SortedSet fields) { 1334 int numEntries = fields.size(); 1336 1337 int dirSize = 2 + numEntries*12 + 4; 1339 1340 Iterator iter = fields.iterator(); 1342 while(iter.hasNext()) { 1343 TIFFField field = (TIFFField)iter.next(); 1345 1346 int valueSize = field.getCount()*sizeOfType[field.getType()]; 1348 1349 if(valueSize > 4) { 1351 dirSize += valueSize; 1352 } 1353 } 1354 1355 return dirSize; 1356 } 1357 1358 private void writeFileHeader() throws IOException { 1359 1361 output.write('M'); 1363 output.write('M'); 1364 1365 output.write(0); 1367 output.write(42); 1368 1369 writeLong(8); 1371 } 1372 1373 private void writeDirectory(int thisIFDOffset, SortedSet fields, 1374 int nextIFDOffset) 1375 throws IOException { 1376 1377 int numEntries = fields.size(); 1379 1380 long offsetBeyondIFD = thisIFDOffset + 12 * numEntries + 4 + 2; 1381 ArrayList tooBig = new ArrayList (); 1382 1383 writeUnsignedShort(numEntries); 1385 1386 Iterator iter = fields.iterator(); 1387 while(iter.hasNext()) { 1388 1389 TIFFField field = (TIFFField)iter.next(); 1391 1392 int tag = field.getTag(); 1394 writeUnsignedShort(tag); 1395 1396 int type = field.getType(); 1398 writeUnsignedShort(type); 1399 1400 int count = field.getCount(); 1403 int valueSize = getValueSize(field); 1404 writeLong(type == TIFFField.TIFF_ASCII ? valueSize : count); 1405 1406 if (valueSize > 4) { 1408 1409 writeLong(offsetBeyondIFD); 1411 offsetBeyondIFD += valueSize; 1412 tooBig.add(field); 1413 1414 } else { 1415 1416 writeValuesAsFourBytes(field); 1417 } 1418 1419 } 1420 1421 writeLong(nextIFDOffset); 1423 1424 for (int i = 0; i < tooBig.size(); i++) { 1426 writeValues((TIFFField)tooBig.get(i)); 1427 } 1428 } 1429 1430 1433 private static final int getValueSize(TIFFField field) { 1434 int type = field.getType(); 1435 int count = field.getCount(); 1436 int valueSize = 0; 1437 if(type == TIFFField.TIFF_ASCII) { 1438 for(int i = 0; i < count; i++) { 1439 byte[] stringBytes = field.getAsString(i).getBytes(); 1440 valueSize += stringBytes.length; 1441 if(stringBytes[stringBytes.length-1] != (byte)0) { 1442 valueSize++; 1443 } 1444 } 1445 } else { 1446 valueSize = count * sizeOfType[type]; 1447 } 1448 return valueSize; 1449 } 1450 1451 private static final int[] sizeOfType = { 1452 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; 1466 1467 private void writeValuesAsFourBytes(TIFFField field) throws IOException { 1468 1469 int dataType = field.getType(); 1470 int count = field.getCount(); 1471 1472 switch (dataType) { 1473 1474 case TIFFField.TIFF_BYTE: 1476 byte bytes[] = field.getAsBytes(); 1477 if (count > 4) count =4; 1478 for (int i=0; i<count; i++) 1479 output.write(bytes[i]); 1480 1481 for (int i = 0; i < (4 - count); i++) 1482 output.write(0); 1483 break; 1484 1485 case TIFFField.TIFF_SHORT: 1487 char chars[] = field.getAsChars(); 1488 if (count > 2) count=2; 1489 for (int i=0; i<count; i++) 1490 writeUnsignedShort(chars[i]); 1491 for (int i = 0; i < (2 - count); i++) 1492 writeUnsignedShort(0); 1493 1494 break; 1495 1496 case TIFFField.TIFF_LONG: 1498 long longs[] = field.getAsLongs(); 1499 1500 for (int i=0; i<count; i++) { 1501 writeLong(longs[i]); 1502 } 1503 break; 1504 } 1505 1506 } 1507 1508 private void writeValues(TIFFField field) throws IOException { 1509 1510 int dataType = field.getType(); 1511 int count = field.getCount(); 1512 1513 switch (dataType) { 1514 1515 case TIFFField.TIFF_BYTE: 1517 case TIFFField.TIFF_SBYTE: 1518 case TIFFField.TIFF_UNDEFINED: 1519 byte bytes[] = field.getAsBytes(); 1520 for (int i=0; i<count; i++) { 1521 output.write(bytes[i]); 1522 } 1523 break; 1524 1525 case TIFFField.TIFF_SHORT: 1527 char chars[] = field.getAsChars(); 1528 for (int i=0; i<count; i++) { 1529 writeUnsignedShort(chars[i]); 1530 } 1531 break; 1532 case TIFFField.TIFF_SSHORT: 1533 short shorts[] = field.getAsShorts(); 1534 for (int i=0; i<count; i++) { 1535 writeUnsignedShort(shorts[i]); 1536 } 1537 break; 1538 1539 case TIFFField.TIFF_LONG: 1541 case TIFFField.TIFF_SLONG: 1542 long longs[] = field.getAsLongs(); 1543 for (int i=0; i<count; i++) { 1544 writeLong(longs[i]); 1545 } 1546 break; 1547 1548 case TIFFField.TIFF_FLOAT: 1549 float[] floats = field.getAsFloats(); 1550 for (int i=0; i<count; i++) { 1551 int intBits = Float.floatToIntBits(floats[i]); 1552 writeLong(intBits); 1553 } 1554 break; 1555 1556 case TIFFField.TIFF_DOUBLE: 1557 double[] doubles = field.getAsDoubles(); 1558 for (int i=0; i<count; i++) { 1559 long longBits = Double.doubleToLongBits(doubles[i]); 1560 writeLong(longBits >>> 32); 1561 writeLong(longBits & 0xffffffff); 1562 } 1563 break; 1564 1565 case TIFFField.TIFF_RATIONAL: 1566 case TIFFField.TIFF_SRATIONAL: 1567 long rationals[][] = field.getAsRationals(); 1568 for (int i=0; i<count; i++) { 1569 writeLong(rationals[i][0]); 1570 writeLong(rationals[i][1]); 1571 } 1572 break; 1573 1574 case TIFFField.TIFF_ASCII: 1575 for (int i=0; i<count; i++) { 1576 byte[] stringBytes = field.getAsString(i).getBytes(); 1577 output.write(stringBytes); 1578 if(stringBytes[stringBytes.length-1] != (byte)0) { 1579 output.write((byte)0); 1580 } 1581 } 1582 break; 1583 1584 default: 1585 throw new Error ("TIFFImageEncoder10"); 1586 1587 } 1588 1589 } 1590 1591 private void writeUnsignedShort(int s) throws IOException { 1594 output.write((s & 0xff00) >>> 8); 1595 output.write(s & 0x00ff); 1596 } 1597 1598 private void writeLong(long l) throws IOException { 1599 output.write( (int)((l & 0xff000000) >>> 24)); 1600 output.write( (int)((l & 0x00ff0000) >>> 16)); 1601 output.write( (int)((l & 0x0000ff00) >>> 8)); 1602 output.write( ((int)l & 0x000000ff)); 1603 } 1604 1605 1609 private long getOffset(OutputStream out) throws IOException { 1610 if(out instanceof ByteArrayOutputStream ) { 1611 return ((ByteArrayOutputStream )out).size(); 1612 } else if(out instanceof SeekableOutputStream) { 1613 return ((SeekableOutputStream)out).getFilePointer(); 1614 } else { 1615 throw new IllegalStateException (); 1617 } 1618 } 1619 1620 1623 private static int compressPackBits(byte[] data, int numRows, 1624 int bytesPerRow, byte[] compData) { 1625 int inOffset = 0; 1626 int outOffset = 0; 1627 1628 for(int i = 0; i < numRows; i++) { 1629 outOffset = packBits(data, inOffset, bytesPerRow, 1630 compData, outOffset); 1631 inOffset += bytesPerRow; 1632 } 1633 1634 return outOffset; 1635 } 1636 1637 1642 private static int packBits(byte[] input, int inOffset, int inCount, 1643 byte[] output, int outOffset) { 1644 int inMax = inOffset + inCount - 1; 1645 int inMaxMinus1 = inMax - 1; 1646 1647 while(inOffset <= inMax) { 1648 int run = 1; 1649 byte replicate = input[inOffset]; 1650 while(run < 127 && inOffset < inMax && 1651 input[inOffset] == input[inOffset+1]) { 1652 run++; 1653 inOffset++; 1654 } 1655 if(run > 1) { 1656 inOffset++; 1657 output[outOffset++] = (byte)(-(run - 1)); 1658 output[outOffset++] = replicate; 1659 } 1660 1661 run = 0; 1662 int saveOffset = outOffset; 1663 while(run < 128 && 1664 ((inOffset < inMax && 1665 input[inOffset] != input[inOffset+1]) || 1666 (inOffset < inMaxMinus1 && 1667 input[inOffset] != input[inOffset+2]))) { 1668 run++; 1669 output[++outOffset] = input[inOffset++]; 1670 } 1671 if(run > 0) { 1672 output[saveOffset] = (byte)(run - 1); 1673 outOffset++; 1674 } 1675 1676 if(inOffset == inMax) { 1677 if(run > 0 && run < 128) { 1678 output[saveOffset]++; 1679 output[outOffset++] = input[inOffset++]; 1680 } else { 1681 output[outOffset++] = (byte)0; 1682 output[outOffset++] = input[inOffset++]; 1683 } 1684 } 1685 } 1686 1687 return outOffset; 1688 } 1689 1690 private static int deflate(Deflater deflater, 1691 byte[] inflated, byte[] deflated) { 1692 deflater.setInput(inflated); 1693 deflater.finish(); 1694 int numCompressedBytes = deflater.deflate(deflated); 1695 deflater.reset(); 1696 return numCompressedBytes; 1697 } 1698 1699 private static void modifyEncodeParam(JPEGEncodeParam src, 1700 JPEGEncodeParam dst, 1701 int nbands) { 1702 dst.setDensityUnit (src.getDensityUnit()); 1703 dst.setXDensity (src.getXDensity()); 1704 dst.setYDensity (src.getYDensity()); 1705 dst.setRestartInterval(src.getRestartInterval()); 1706 for (int i=0; i<4; i++) { 1707 JPEGQTable tbl = src.getQTable(i); 1708 if (tbl != null) 1709 dst.setQTable(i, tbl); 1710 } 1711 } 1712} 1713 1714 | Popular Tags |