Changeset 2914


Ignore:
Timestamp:
06/26/07 21:49:00 (12 years ago)
Author:
melissa
Message:

Cleaned up QuickTime reader - all codec implementations have been moved to loci.formats.codec.

Location:
trunk/loci/formats
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/formats/codec/AdobeDeflateCodec.java

    r2450 r2914  
    6464   *                         decompressor 
    6565   */ 
    66   public byte[] decompress(byte[] input) throws FormatException { 
     66  public byte[] decompress(byte[] input, Object options)  
     67    throws FormatException  
     68  { 
    6769    try { 
    6870      Inflater inf = new Inflater(false); 
  • trunk/loci/formats/codec/Base64Codec.java

    r2601 r2914  
    168168   * @throws FormatException if data is not valid Base64 data 
    169169   */ 
    170   public byte[] decompress(byte[] base64Data) throws FormatException { 
     170  public byte[] decompress(byte[] base64Data, Object options)  
     171    throws FormatException  
     172  { 
    171173    // TODO: Add checks for invalid data. 
    172174    if (base64Data.length == 0) return new byte[0]; 
  • trunk/loci/formats/codec/BaseCodec.java

    r2857 r2914  
    144144  } 
    145145 
     146  /* @see Codec#decompress(byte[]) */ 
     147  public byte[] decompress(byte[] data) throws FormatException { 
     148    return decompress(data, null); 
     149  } 
     150 
     151  /* @see Codec#decompress(byte[][]) */ 
     152  public byte[] decompress(byte[][] data) throws FormatException { 
     153    return decompress(data, null); 
     154  } 
     155 
    146156  /** 
    147157   * 2D data block decoding default implementation. 
     
    154164   *   appropriate type. 
    155165   */ 
    156   public byte[] decompress(byte[][] data) throws FormatException { 
     166  public byte[] decompress(byte[][] data, Object options)  
     167    throws FormatException  
     168  { 
    157169    int len = 0; 
    158170    for (int i = 0; i < data.length; i++) { 
     
    165177      curPos += data[i].length; 
    166178    } 
    167     return decompress(toDecompress); 
     179    return decompress(toDecompress, options); 
    168180  } 
    169181 
  • trunk/loci/formats/codec/Codec.java

    r2711 r2914  
    7979   * Decompresses a block of data. 
    8080   * 
     81   * @param data the data to be decompressed 
     82   * @param options Options to be used during decompression. 
     83   * @return the decompressed data. 
     84   * @throws FormatException If data is not valid. 
     85   */ 
     86  byte[] decompress(byte[] data, Object options) throws FormatException; 
     87 
     88  /** 
     89   * Decompresses a block of data. 
     90   * 
     91   * @param data the data to be decompressed 
     92   * @param options Options to be used during decompression. 
     93   * @return the decompressed data. 
     94   * @throws FormatException If data is not valid. 
     95   */ 
     96  byte[] decompress(byte[][] data, Object options) throws FormatException; 
     97 
     98  /** 
     99   * Decompresses a block of data. 
     100   * 
    81101   * @param data the data to be decompressed. 
    82102   * @return The decompressed data. 
  • trunk/loci/formats/codec/JPEGCodec.java

    r2857 r2914  
    6262   *                         decompressor 
    6363   */ 
    64   public byte[] decompress(byte[] input) throws FormatException { 
     64  public byte[] decompress(byte[] input, Object options) throws FormatException 
     65  { 
    6566    BufferedImage b; 
    6667    try { 
    67       b = ImageIO.read(new ByteArrayInputStream(input)); 
     68      RandomAccessStream s = new RandomAccessStream(input); 
     69      while (s.read() != (byte) 0xff || s.read() != (byte) 0xd8); 
     70      int offset = (int) s.getFilePointer() - 2; 
     71      b = ImageIO.read(new BufferedInputStream(new ByteArrayInputStream(input,  
     72        offset, input.length - offset))); 
    6873    } 
    6974    catch (IOException exc) { 
  • trunk/loci/formats/codec/LZOCodec.java

    r2450 r2914  
    6666   *                         decompressor 
    6767   */ 
    68   public byte[] decompress(byte[] src) throws FormatException { 
     68  public byte[] decompress(byte[] src, Object options) throws FormatException { 
    6969    int ip = 0; 
    7070    int op = 0; 
  • trunk/loci/formats/codec/LZWCodec.java

    r2450 r2914  
    105105   * @throws FormatException If input is not an LZW-compressed data block. 
    106106   */ 
    107   public byte[] decompress(byte[] input) throws FormatException { 
     107  public byte[] decompress(byte[] input, Object options) throws FormatException 
     108  { 
    108109    if (input == null || input.length == 0) return input; 
    109110 
  • trunk/loci/formats/codec/LuraWaveCodec.java

    r2781 r2914  
    9292  } 
    9393 
    94   /* @see Codec#decompress(byte[]) */ 
    95   public byte[] decompress(byte[] input) throws FormatException { 
     94  /* @see Codec#decompress(byte[], Object) */ 
     95  public byte[] decompress(byte[] input, Object options) throws FormatException 
     96  { 
    9697    if (noLuraWave) throw new FormatException(NO_LURAWAVE_MSG); 
    9798    licenseCode = System.getProperty(LICENSE_PROPERTY); 
  • trunk/loci/formats/codec/NikonCodec.java

    r2450 r2914  
    7070   *                         decompressor 
    7171   */ 
    72   public byte[] decompress(byte[] input) throws FormatException { 
     72  public byte[] decompress(byte[] input, Object options) throws FormatException 
     73  { 
    7374    BitWriter out = new BitWriter(input.length); 
    7475    BitBuffer bb = new BitBuffer(input); 
  • trunk/loci/formats/codec/PackbitsCodec.java

    r2450 r2914  
    6262   *                         decompressor 
    6363   */ 
    64   public byte[] decompress(byte[] input) throws FormatException { 
     64  public byte[] decompress(byte[] input, Object options) throws FormatException 
     65  { 
    6566    ByteVector output = new ByteVector(input.length); 
    6667    int pt = 0; 
  • trunk/loci/formats/in/QTReader.java

    r2857 r2914  
    2929import java.util.Vector; 
    3030import java.util.zip.*; 
    31 import javax.imageio.ImageIO; 
    3231import loci.formats.*; 
    33 import loci.formats.codec.ByteVector; 
     32import loci.formats.codec.*; 
    3433 
    3534/** 
     
    196195      !code.equals(altCodec); 
    197196 
    198     if (code.equals("jpeg") || code.equals("mjpb")) { 
    199       byte[] s = ImageTools.getBytes(openImage(no), false, no); 
    200       return s; 
    201     } 
    202  
    203     byte[] bytes = null; 
    204     if (!code.equals("rpza")) bytes = uncompress(pixs, code); 
    205     else { 
    206       bytes = rpzaUncompress(pixs, canUsePrevious ? prevPixels : null); 
    207  
     197    byte[] bytes = uncompress(pixs, code); 
     198    if (code.equals("rpza")) { 
    208199      for (int i=0; i<bytes.length; i++) { 
    209200        bytes[i] = (byte) (255 - bytes[i]); 
     
    227218    int pad = core.sizeX[0] % 4; 
    228219    pad = (4 - pad) % 4; 
     220    if (codec.equals("mjpb")) pad = 0; 
    229221 
    230222    int size = core.sizeX[0] * core.sizeY[0]; 
     
    240232    } 
    241233 
    242     if (bitsPerPixel == 40 || bitsPerPixel == 8) { 
     234    if ((bitsPerPixel == 40 || bitsPerPixel == 8) && !code.equals("mjpb")) { 
    243235      // invert the pixels 
    244236      for (int i=0; i<bytes.length; i++) { 
     
    292284    } 
    293285 
    294     int offset = ((Integer) offsets.get(no)).intValue(); 
    295     int nextOffset = pixelBytes; 
    296  
    297     scale = ((Integer) offsets.get(0)).intValue(); 
    298     offset -= scale; 
    299  
    300     if (no < offsets.size() - 1) { 
    301       nextOffset = ((Integer) offsets.get(no + 1)).intValue(); 
    302       nextOffset -= scale; 
    303     } 
    304  
    305     if ((nextOffset - offset) < 0) { 
    306       int temp = offset; 
    307       offset = nextOffset; 
    308       nextOffset = temp; 
    309     } 
    310  
    311     byte[] pixs = new byte[nextOffset - offset]; 
    312  
    313     in.seek(pixelOffset + offset); 
    314     in.read(pixs); 
    315  
    316     canUsePrevious = (prevPixels != null) && (prevPlane == no - 1); 
    317  
    318     BufferedImage b = null; 
    319  
    320     if (code.equals("jpeg")) { 
    321       b = bufferedJPEG(pixs); 
    322     } 
    323     else if (code.equals("mjpb")) { 
    324       b = mjpbUncompress(pixs); 
    325     } 
    326     else { 
    327       int bpp = bitsPerPixel / 8; 
    328       if (bpp == 3 || bpp == 4 || bpp == 5) bpp = 1; 
    329       b = ImageTools.makeImage(openBytes(no), core.sizeX[0], 
    330         core.sizeY[0], core.sizeC[0], false, bpp, core.littleEndian[0]); 
    331     } 
    332     return b; 
     286    int bpp = bitsPerPixel / 8; 
     287    if (bpp == 3 || bpp == 4 || bpp == 5) bpp = 1; 
     288    return ImageTools.makeImage(openBytes(no), core.sizeX[0], 
     289      core.sizeY[0], core.sizeC[0], false, bpp, core.littleEndian[0]); 
    333290  } 
    334291 
     
    747704    throws FormatException, IOException 
    748705  { 
    749     // JPEG and mjpb codecs handled separately, so not included in this list 
    750706    if (code.equals("raw ")) return pixs; 
    751     else if (code.equals("rle ")) return rleUncompress(pixs); 
    752     else if (code.equals("rpza")) return rpzaUncompress(pixs, null); 
    753     else { 
    754       throw new FormatException("Sorry, " + codec + " codec is not supported"); 
    755     } 
    756   } 
    757  
    758   /** 
    759    * Uncompresses an RPZA compressed image plane. Adapted from the ffmpeg 
    760    * codec - see http://ffmpeg.mplayerhq.hu 
    761    */ 
    762   private byte[] rpzaUncompress(byte[] input, byte[] rtn) 
    763     throws FormatException 
    764   { 
    765     int width = core.sizeX[0]; 
    766     int stride = core.sizeX[0]; 
    767     int rowInc = stride - 4; 
    768     int streamPtr = 0; 
    769     short opcode; 
    770     int nBlocks; 
    771     int colorA = 0, colorB; 
    772     int[] color4 = new int[4]; 
    773     int index, idx; 
    774     int ta, tb; 
    775     int rowPtr = 0, pixelPtr = 0, blockPtr = 0; 
    776     int pixelX, pixelY; 
    777     int totalBlocks; 
    778  
    779     int[] pixels = new int[width * core.sizeY[0]]; 
    780     if (rtn == null) rtn = new byte[width * core.sizeY[0] * 3]; 
    781  
    782     while (input[streamPtr] != (byte) 0xe1) streamPtr++; 
    783     streamPtr += 4; 
    784  
    785     totalBlocks = ((width + 3) / 4) * ((core.sizeY[0] + 3) / 4); 
    786  
    787     while (streamPtr < input.length) { 
    788       opcode = input[streamPtr++]; 
    789       nBlocks = (opcode & 0x1f) + 1; 
    790  
    791       if ((opcode & 0x80) == 0) { 
    792         if (streamPtr >= input.length) break; 
    793         colorA = (opcode << 8) | input[streamPtr++]; 
    794         opcode = 0; 
    795         if (streamPtr >= input.length) break; 
    796         if ((input[streamPtr] & 0x80) != 0) { 
    797           opcode = 0x20; 
    798           nBlocks = 1; 
    799         } 
    800       } 
    801  
    802       switch (opcode & 0xe0) { 
    803         case 0x80: 
    804           while (nBlocks-- > 0) { 
    805             pixelPtr += 4; 
    806             if (pixelPtr >= width) { 
    807               pixelPtr = 0; 
    808               rowPtr += stride * 4; 
    809             } 
    810             totalBlocks--; 
    811           } 
    812           break; 
    813         case 0xa0: 
    814           colorA = DataTools.bytesToInt(input, streamPtr, 2, false); 
    815           streamPtr += 2; 
    816           while (nBlocks-- > 0) { 
    817             blockPtr = rowPtr + pixelPtr; 
    818             for (pixelY=0; pixelY < 4; pixelY++) { 
    819               for (pixelX=0; pixelX < 4; pixelX++) { 
    820                 if (blockPtr >= pixels.length) break; 
    821                 pixels[blockPtr] = colorA; 
    822  
    823                 short s = (short) (pixels[blockPtr] & 0x7fff); 
    824  
    825                 rtn[blockPtr] = (byte) (255 - ((s & 0x7c00) >> 10)); 
    826                 rtn[blockPtr + pixels.length] = 
    827                   (byte) (255 - ((s & 0x3e0) >> 5)); 
    828                 rtn[blockPtr + 2*pixels.length] = (byte) (255 - (s & 0x1f)); 
    829  
    830                 blockPtr++; 
    831               } 
    832               blockPtr += rowInc; 
    833             } 
    834             pixelPtr += 4; 
    835             if (pixelPtr >= width) { 
    836               pixelPtr = 0; 
    837               rowPtr += stride * 4; 
    838             } 
    839             totalBlocks--; 
    840           } 
    841           break; 
    842         case 0xc0: 
    843           colorA = DataTools.bytesToInt(input, streamPtr, 2, false); 
    844           streamPtr += 2; 
    845         case 0x20: 
    846           colorB = DataTools.bytesToInt(input, streamPtr, 2, false); 
    847           streamPtr += 2; 
    848  
    849           color4[0] = colorB; 
    850           color4[1] = 0; 
    851           color4[2] = 0; 
    852           color4[3] = colorA; 
    853  
    854           ta = (colorA >> 10) & 0x1f; 
    855           tb = (colorB >> 10) & 0x1f; 
    856           color4[1] |= ((11*ta + 21*tb) >> 5) << 10; 
    857           color4[2] |= ((21*ta + 11*tb) >> 5) << 10; 
    858  
    859           ta = (colorA >> 5) & 0x1f; 
    860           tb = (colorB >> 5) & 0x1f; 
    861           color4[1] |= ((11*ta + 21*tb) >> 5) << 5; 
    862           color4[2] |= ((21*ta + 11*tb) >> 5) << 5; 
    863  
    864           ta = colorA & 0x1f; 
    865           tb = colorB & 0x1f; 
    866           color4[1] |= ((11*ta + 21*tb) >> 5); 
    867           color4[2] |= ((21*ta + 11*tb) >> 5); 
    868  
    869           while (nBlocks-- > 0) { 
    870             blockPtr = rowPtr + pixelPtr; 
    871             for (pixelY=0; pixelY<4; pixelY++) { 
    872               if (streamPtr >= input.length) break; 
    873               index = input[streamPtr++]; 
    874               for (pixelX=0; pixelX<4; pixelX++) { 
    875                 idx = (index >> (2*(3 - pixelX))) & 0x03; 
    876                 if (blockPtr >= pixels.length) break; 
    877                 pixels[blockPtr] = color4[idx]; 
    878  
    879                 short s = (short) (pixels[blockPtr] & 0x7fff); 
    880  
    881                 rtn[blockPtr] = (byte) (255 - ((s & 0x7c00) >> 10)); 
    882                 rtn[blockPtr + pixels.length] = 
    883                   (byte) (255 - ((s & 0x3e0) >> 5)); 
    884                 rtn[blockPtr + 2*pixels.length] = (byte) (255 - (s & 0x1f)); 
    885  
    886                 blockPtr++; 
    887               } 
    888               blockPtr += rowInc; 
    889             } 
    890             pixelPtr += 4; 
    891             if (pixelPtr >= width) { 
    892               pixelPtr = 0; 
    893               rowPtr += stride * 4; 
    894             } 
    895             totalBlocks--; 
    896           } 
    897           break; 
    898         case 0x00: 
    899           blockPtr = rowPtr + pixelPtr; 
    900           for (pixelY=0; pixelY < 4; pixelY++) { 
    901             for (pixelX=0; pixelX < 4; pixelX++) { 
    902               if ((pixelY != 0) || (pixelX != 0)) { 
    903                 colorA = DataTools.bytesToInt(input, streamPtr, 2, false); 
    904                 streamPtr += 2; 
    905               } 
    906               if (blockPtr >= pixels.length) break; 
    907               pixels[blockPtr] = colorA; 
    908  
    909               short s = (short) (pixels[blockPtr] & 0x7fff); 
    910  
    911               rtn[blockPtr] = (byte) (255 - ((s & 0x7c00) >> 10)); 
    912               rtn[blockPtr + pixels.length] = (byte) (255 - ((s & 0x3e0) >> 5)); 
    913               rtn[blockPtr + 2*pixels.length] = (byte) (255 - (s & 0x1f)); 
    914  
    915               blockPtr++; 
    916             } 
    917             blockPtr += rowInc; 
    918           } 
    919           pixelPtr += 4; 
    920           if (pixelPtr >= width) { 
    921             pixelPtr = 0; 
    922             rowPtr += stride * 4; 
    923           } 
    924           totalBlocks--; 
    925           break; 
    926       } 
    927     } 
    928  
    929     return rtn; 
    930   } 
    931  
    932   /** Uncompresses a MJPEG-B compressed image plane. */ 
    933   private BufferedImage mjpbUncompress(byte[] input) throws FormatException { 
    934     byte[] raw = null; 
    935     byte[] raw2 = null; 
    936     int pt = 16; // pointer into the compressed data 
    937  
    938     // official documentation at 
    939     // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/ 
    940     // chapter_4_section_2.html 
    941  
    942     // information on SOF, SOS, and SOD headers found at 
    943     // http://www.obrador.com/essentialjpeg/headerinfo.htm 
    944  
    945     // a brief overview for those who would rather not read the specifications: 
    946     // MJPEG-B (or Motion JPEG) is a variant of the JPEG compression standard, 
    947     // with one major difference.  In JPEG files (technically JFIF), important 
    948     // blocks are denoted by a 'marker' - the byte '0xff' followed by a byte 
    949     // identifying the type of data to follow.  According to JPEG standards, 
    950     // all '0xff' bytes in the stream of compressed pixel data are to be 
    951     // followed by a null byte (0x00), so that the reader knows not to 
    952     // interpret the '0xff' as the beginning of a marker.  MJPEG-B does not 
    953     // support markers, thus the null byte is not included after '0xff' bytes 
    954     // in the data stream.  Also, an insufficient number of quantization 
    955     // and Huffman tables are provided, so we must use the defaults obtained 
    956     // from the JPEG documentation.  Finally, MJPEG-B allows for the data to 
    957     // be spread across multiple fields, effectively forcing the reader to 
    958     // interlace the scanlines. 
    959     // 
    960     // further aside - 
    961     // http://lists.apple.com/archives/quicktime-talk/2000/Nov/msg00269.html 
    962     // contains some interesting notes on why Apple chose to define this codec 
    963  
    964     pt += 4; 
    965     if (pt >= input.length) pt = 0; 
    966  
    967     byte[] lumDcBits = null, lumAcBits = null, lumDc = null, lumAc = null; 
    968     byte[] quant = null; 
    969  
    970     // most MJPEG-B planes don't have this identifier 
    971     if (!(input[pt] != 'm' || input[pt+1] != 'j' || input[pt+2] != 'p' || 
    972       input[pt+3] != 'g') || !(input[pt-16] != 'm' || input[pt-15] != 'j' || 
    973       input[pt-14] != 'p' || input[pt-13] != 'g')) 
    974     { 
    975       int extra = 16; 
    976       if (input[pt-16] == 'm') { 
    977         pt = 4; 
    978         extra = 0; 
    979       } 
    980       pt += 4; 
    981  
    982       // number of compressed bytes (minus padding) 
    983       pt += 4; 
    984  
    985       // number of compressed bytes (including padding) 
    986       pt += 4; 
    987  
    988       // offset to second field 
    989       int offset = 
    990         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    991       pt += 4; 
    992  
    993       // offset to quantization table 
    994       int quantOffset = 
    995         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    996       pt += 4; 
    997  
    998       // offset to Huffman table 
    999       int huffmanOffset = 
    1000         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    1001       pt += 4; 
    1002  
    1003       // offset to start of frame 
    1004       int sof = 
    1005         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    1006       pt += 4; 
    1007  
    1008       // offset to start of scan 
    1009       int sos = 
    1010         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    1011       pt += 4; 
    1012  
    1013       // offset to start of data 
    1014       int sod = 
    1015         DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]) + extra; 
    1016       pt += 4; 
    1017  
    1018       // skip over the quantization table, if it exists 
    1019       if (quantOffset != 0) { 
    1020         pt = quantOffset; 
    1021         int length = DataTools.bytesToInt(input, pt, 2, core.littleEndian[0]); 
    1022         pt += 3; 
    1023         quant = new byte[length - 3]; 
    1024         System.arraycopy(input, pt, quant, 0, quant.length); 
    1025         pt += quant.length; 
    1026       } 
    1027  
    1028       // skip over the Huffman table, if it exists 
    1029       if (huffmanOffset != 0) { 
    1030         pt = huffmanOffset; 
    1031         int length = DataTools.bytesToInt(input, pt, 2, core.littleEndian[0]); 
    1032         pt += 3; 
    1033         lumDcBits = new byte[16]; 
    1034         System.arraycopy(input, pt, lumDcBits, 0, lumDcBits.length); 
    1035         pt += lumDcBits.length; 
    1036         lumDc = new byte[12]; 
    1037         System.arraycopy(input, pt, lumDc, 0, lumDc.length); 
    1038         pt += lumDc.length + 1; 
    1039         lumAcBits = new byte[16]; 
    1040         System.arraycopy(input, pt, lumAcBits, 0, lumAcBits.length); 
    1041         pt += lumAcBits.length; 
    1042         lumAc = new byte[162]; 
    1043         System.arraycopy(input, pt, lumAc, 0, lumAc.length); 
    1044         pt += lumAc.length; 
    1045       } 
    1046  
    1047       // skip to the frame header 
    1048       pt = sof; 
    1049  
    1050       // read sof header 
    1051       // we can skip over the first 7 bytes (length, bps, height, width) 
    1052       pt += 7; 
    1053  
    1054       // number of channels 
    1055       int channels = DataTools.bytesToInt(input, pt, 1, core.littleEndian[0]); 
    1056       pt++; 
    1057  
    1058       int[] sampling = new int[channels]; 
    1059       for (int i=0; i<channels; i++) { 
    1060         pt++; 
    1061         sampling[i] = DataTools.bytesToInt(input, pt, 1, core.littleEndian[0]); 
    1062         pt += 2; 
    1063       } 
    1064  
    1065       // skip to scan header 
    1066       pt = sos; 
    1067  
    1068       // we can skip over the first 3 bytes (length, number of channels) 
    1069       pt += 3; 
    1070       int[] tables = new int[channels]; 
    1071       for (int i=0; i<channels; i++) { 
    1072         pt++; 
    1073         tables[i] = DataTools.bytesToInt(input, pt, 1, core.littleEndian[0]); 
    1074         pt++; 
    1075       } 
    1076       pt += 3; 
    1077  
    1078       // now we can finally read this field's data 
    1079       pt = sod; 
    1080  
    1081       int numBytes = offset - pt; 
    1082       if (offset == 0) numBytes = input.length - pt; 
    1083       raw = new byte[numBytes]; 
    1084       System.arraycopy(input, pt, raw, 0, raw.length); 
    1085  
    1086       // get the second field 
    1087       // from the specs: 
    1088       // "Each QuickTime sample consists of two distinct compressed images, 
    1089       // each coding one field: the field with the topmost scan-line, T, and 
    1090       // the other field, B. Each field is half the height of the overall 
    1091       // image, as declared in the height field of the sample description. 
    1092       // To be precise, if the height field contains the value H, then the 
    1093       // field T has ((H+1) div 2) lines, and field B has (H div 2) lines." 
    1094  
    1095       if (offset != 0) { 
    1096         pt = offset; 
    1097  
    1098         pt += 4; // reserved = 0 
    1099         pt += 4; // 'mjpg' tag 
    1100         pt += 4; // field size 
    1101         pt += 4; // padded field size 
    1102         pt += 4; // offset to next field = 0 
    1103         pt += 4; // quantization table offset 
    1104         pt += 4; // Huffman table offset 
    1105         pt += 4; // sof offset 
    1106         pt += 4; // sos offset 
    1107  
    1108         pt += DataTools.bytesToInt(input, pt, 4, core.littleEndian[0]); 
    1109         pt -= 36; // HACK 
    1110  
    1111         numBytes = input.length - pt; 
    1112         raw2 = new byte[numBytes]; 
    1113         System.arraycopy(input, pt, raw2, 0, raw2.length); 
    1114       } 
    1115     } 
    1116  
    1117     if (raw == null) raw = input; 
    1118  
    1119     // insert zero after each byte equal to 0xff 
    1120     ByteVector b = new ByteVector(); 
    1121     for (int i=0; i<raw.length; i++) { 
    1122       b.add((byte) raw[i]); 
    1123       if (raw[i] == (byte) 0xff) { 
    1124         b.add((byte) 0x00); 
    1125       } 
    1126     } 
    1127  
    1128     if (raw2 == null) raw2 = new byte[0]; 
    1129     ByteVector b2 = new ByteVector(); 
    1130     for (int i=0; i<raw2.length; i++) { 
    1131       b2.add((byte) raw2[i]); 
    1132       if (raw2[i] == (byte) 0xff) { 
    1133         b2.add((byte) 0x00); 
    1134       } 
    1135     } 
    1136  
    1137     // assemble a fake JFIF plane 
    1138  
    1139     ByteVector v = new ByteVector(1000); 
    1140     v.add(HEADER); 
    1141  
    1142     // add quantization tables 
    1143  
    1144     v.add(new byte[] {(byte) 0xff, (byte) 0xdb}); 
    1145  
    1146     int length = 67; 
    1147     v.add((byte) ((length >>> 8) & 0xff)); 
    1148     v.add((byte) (length & 0xff)); 
    1149  
    1150     v.add((byte) 0x00); 
    1151     v.add(quant); 
    1152  
    1153     // add Huffman tables 
    1154  
    1155     v.add(new byte[] {(byte) 0xff, (byte) 0xc4}); 
    1156  
    1157     length = (lumDcBits.length + lumDc.length + 
    1158       lumAcBits.length + lumAc.length)*2 + 6; 
    1159     v.add((byte) ((length >>> 8) & 0xff)); 
    1160     v.add((byte) (length & 0xff)); 
    1161  
    1162     // the ordering of these tables matters 
    1163  
    1164     v.add((byte) 0x00); 
    1165     v.add(lumDcBits); 
    1166     v.add(lumDc); 
    1167  
    1168     v.add((byte) 0x01); 
    1169     v.add(lumDcBits); 
    1170     v.add(lumDc); 
    1171  
    1172     v.add((byte) 0x10); 
    1173     v.add(lumAcBits); 
    1174     v.add(lumAc); 
    1175  
    1176     v.add((byte) 0x11); 
    1177     v.add(lumAcBits); 
    1178     v.add(lumAc); 
    1179  
    1180     // add start-of-frame header 
    1181  
    1182     v.add((byte) 0xff); 
    1183     v.add((byte) 0xc0); 
    1184  
    1185     length = (bitsPerPixel >= 40) ? 11 : 17; 
    1186  
    1187     v.add((byte) ((length >>> 8) & 0xff)); 
    1188     v.add((byte) (length & 0xff)); 
    1189  
    1190     int fieldHeight = core.sizeY[0]; 
    1191     if (interlaced) fieldHeight /= 2; 
    1192     if (core.sizeY[0] % 2 == 1) fieldHeight++; 
    1193  
    1194     int c = bitsPerPixel == 24 ? 3 : (bitsPerPixel == 32 ? 4 : 1); 
    1195  
    1196     v.add(bitsPerPixel >= 40 ? (byte) (bitsPerPixel - 32) : 
    1197       (byte) (bitsPerPixel / c));  // bits per sample 
    1198     v.add((byte) ((fieldHeight >>> 8) & 0xff)); 
    1199     v.add((byte) (fieldHeight & 0xff)); 
    1200     v.add((byte) ((core.sizeX[0] >>> 8) & 0xff)); 
    1201     v.add((byte) (core.sizeX[0] & 0xff)); 
    1202     v.add((bitsPerPixel >= 40) ? (byte) 0x01 : (byte) 0x03); 
    1203  
    1204     // channel information 
    1205  
    1206     v.add((byte) 0x01); // channel id 
    1207     v.add((byte) 0x21); // sampling factors 
    1208     v.add((byte) 0x00); // quantization table number 
    1209  
    1210     if (bitsPerPixel < 40) { 
    1211       v.add((byte) 0x02); 
    1212       v.add((byte) 0x11); 
    1213       v.add((byte) 0x01); 
    1214       v.add((byte) 0x03); 
    1215       v.add((byte) 0x11); 
    1216       v.add((byte) 0x01); 
    1217     } 
    1218  
    1219     // add start-of-scan header 
    1220  
    1221     v.add((byte) 0xff); 
    1222     v.add((byte) 0xda); 
    1223  
    1224     length = (bitsPerPixel >= 40) ? 8 : 12; 
    1225     v.add((byte) ((length >>> 8) & 0xff)); 
    1226     v.add((byte) (length & 0xff)); 
    1227  
    1228     // number of channels 
    1229     v.add((bitsPerPixel >= 40) ? (byte) 0x01 : (byte) 0x03); 
    1230     v.add((byte) 0x01);  // channel id 
    1231     v.add((byte) 0x00);  // DC and AC table numbers 
    1232  
    1233     if (bitsPerPixel < 40) { 
    1234       v.add((byte) 0x02);  // channel id 
    1235       v.add((byte) 0x01);  // DC and AC table numbers 
    1236       v.add((byte) 0x03);  // channel id 
    1237       v.add((byte) 0x01);  // DC and AC table numbers 
    1238     } 
    1239  
    1240     v.add((byte) 0x00); 
    1241     v.add((byte) 0x3f); 
    1242     v.add((byte) 0x00); 
    1243  
    1244     // as if everything we had to do up to this point wasn't enough of a pain, 
    1245     // the MJPEG-B specifications allow for interlaced frames 
    1246     // so now we have to reorder the scanlines...*stabs self in eye* 
    1247  
    1248     if (interlaced) { 
    1249       ByteVector v2 = new ByteVector(v.size()); 
    1250       v2.add(v.toByteArray()); 
    1251  
    1252       v.add(b.toByteArray()); 
    1253       v.add((byte) 0xff); 
    1254       v.add((byte) 0xd9); 
    1255       v2.add(b2.toByteArray()); 
    1256       v2.add((byte) 0xff); 
    1257       v2.add((byte) 0xd9); 
    1258  
    1259       BufferedImage top = bufferedJPEG(v.toByteArray()); 
    1260       BufferedImage bottom = bufferedJPEG(v2.toByteArray()); 
    1261  
    1262       BufferedImage result = null; 
    1263  
    1264       /* 
    1265       if (flip) { 
    1266         result = new BufferedImage(top.getHeight() + bottom.getHeight(), 
    1267           top.getWidth(), top.getType()); 
    1268  
    1269         int topCount = 0; 
    1270         int bottomCount = 0; 
    1271  
    1272         for (int i=0; i<result.getWidth(); i++) { 
    1273           if (i % 2 == 0) { 
    1274             for (int j=0; j<result.getHeight(); j++) { 
    1275               result.setRGB((result.getWidth() - i - 1), j, 
    1276                 top.getRGB(j, topCount)); 
    1277             } 
    1278             topCount++; 
    1279           } 
    1280           else { 
    1281             for (int j=0; j<result.getHeight(); j++) { 
    1282               result.setRGB((result.getWidth() - i - 1), j, 
    1283                 bottom.getRGB(j, bottomCount)); 
    1284             } 
    1285             bottomCount++; 
    1286           } 
    1287         } 
    1288       } 
    1289       else { 
    1290       */ 
    1291       result = new BufferedImage(top.getWidth(), 
    1292         top.getHeight() + bottom.getHeight(), top.getType()); 
    1293  
    1294       int topCount = 0; 
    1295       int bottomCount = 0; 
    1296  
    1297       for (int i=0; i<result.getHeight(); i++) { 
    1298         if (i % 2 == 0) { 
    1299           for (int j=0; j<result.getWidth(); j++) { 
    1300             result.setRGB(j, i, top.getRGB(j, topCount)); 
    1301           } 
    1302           topCount++; 
    1303         } 
    1304         else { 
    1305           for (int j=0; j<result.getWidth(); j++) { 
    1306             result.setRGB(j, i, bottom.getRGB(j, bottomCount)); 
    1307           } 
    1308           bottomCount++; 
    1309         } 
    1310       } 
    1311       //} 
    1312  
    1313       return result; 
    1314     } 
    1315     else { 
    1316       v.add(b.toByteArray()); 
    1317       v.add((byte) 0xff); 
    1318       v.add((byte) 0xd9); 
    1319       return bufferedJPEG(v.toByteArray()); 
    1320     } 
    1321   } 
    1322  
    1323   /** Uncompresses a JPEG compressed image plane. */ 
    1324   private BufferedImage bufferedJPEG(byte[] input) throws FormatException { 
    1325     // some planes have a 16 byte header that needs to be removed 
    1326     if (input[0] != (byte) 0xff || input[1] != (byte) 0xd8) { 
    1327       byte[] temp = input; 
    1328       input = new byte[temp.length - 16]; 
    1329       System.arraycopy(temp, 16, input, 0, input.length); 
    1330     } 
    1331  
    1332     try { 
    1333       return ImageIO.read(new ByteArrayInputStream(input)); 
    1334     } 
    1335     catch (IOException e) { 
    1336       throw new FormatException("Invalid JPEG stream"); 
    1337     } 
    1338   } 
    1339  
    1340   /** Uncompresses a QT RLE compressed image plane. */ 
    1341   private byte[] rleUncompress(byte[] input) throws FormatException, IOException 
    1342   { 
    1343     if (input.length < 8) return prevPixels; 
    1344  
    1345     // read the 4 byte chunk length; this should equal input.length 
    1346  
    1347     // now read the header 
    1348     // if the header is 0, we uncompress the remaining bytes 
    1349     // otherwise, read extra header information to determine which 
    1350     // scanlines to uncompress 
    1351  
    1352     int header = DataTools.bytesToInt(input, 4, 2, core.littleEndian[0]); 
    1353     int off = 0; // offset into output 
    1354     int start = 0; 
    1355     int pt = 6; 
    1356     int numLines = core.sizeY[0]; 
    1357     int ebpp = bitsPerPixel / 8;  // effective bytes per pixel 
    1358     if (ebpp == 1 || ebpp == 2) ebpp *= 3; 
    1359     else if (ebpp >= 5) ebpp %= 4; 
    1360     byte[] output = new byte[core.sizeX[0] * core.sizeY[0] * ebpp]; 
    1361  
    1362     if ((header & 0x0008) == 0x0008) { 
    1363       start = DataTools.bytesToInt(input, pt, 2, core.littleEndian[0]); 
    1364       // skip 2 bytes 
    1365       pt += 4; 
    1366       numLines = DataTools.bytesToInt(input, pt, 2, core.littleEndian[0]); 
    1367       // skip 2 bytes 
    1368       pt += 4; 
    1369  
    1370       // copy appropriate lines from prevPixels 
    1371  
    1372       if (canUsePrevious) { 
    1373         for (int i=0; i<start; i++) { 
    1374           off = i * core.sizeX[0] * ebpp; 
    1375           System.arraycopy(prevPixels, off, output, off, core.sizeX[0] * ebpp); 
    1376         } 
    1377       } 
    1378       off += (core.sizeX[0] * ebpp); 
    1379  
    1380       if (canUsePrevious) { 
    1381         for (int i=(start+numLines); i<core.sizeY[0]; i++) { 
    1382           int offset = i * core.sizeX[0] * ebpp; 
    1383           System.arraycopy(prevPixels, offset, output, offset, 
    1384             core.sizeX[0] * ebpp); 
    1385         } 
    1386       } 
    1387     } 
    1388     else throw new FormatException("Unsupported header : " + header); 
    1389  
    1390     // uncompress the remaining scanlines 
    1391  
    1392     int skip = 0; // number of bytes to skip 
    1393     byte rle = 0; // RLE code 
    1394  
    1395     int rowPointer = start * (core.sizeX[0] * ebpp); 
    1396  
    1397     for (int i=0; i<numLines; i++) { 
    1398       skip = input[pt]; 
    1399       if (skip < 0) skip += 256; 
    1400  
    1401       if (canUsePrevious) { 
    1402         try { 
    1403           System.arraycopy(prevPixels, rowPointer, output, rowPointer, 
    1404             (skip-1) * ebpp); 
    1405         } 
    1406         catch (ArrayIndexOutOfBoundsException e) { } 
    1407       } 
    1408  
    1409       off = rowPointer + ((skip-1) * ebpp); 
    1410       pt++; 
    1411       while (true) { 
    1412         rle = input[pt]; 
    1413         pt++; 
    1414  
    1415         if (rle == 0) { 
    1416           skip = input[pt]; 
    1417  
    1418           if (canUsePrevious) { 
    1419             try { 
    1420               System.arraycopy(prevPixels, off, output, off, 
    1421                 (skip-1) * ebpp); 
    1422             } 
    1423             catch (ArrayIndexOutOfBoundsException e) { } 
    1424           } 
    1425  
    1426           off += ((skip-1) * ebpp); 
    1427           pt++; 
    1428         } 
    1429         else if (rle == -1) { 
    1430           // make sure we copy enough pixels to fill the line 
    1431  
    1432           if (off < (rowPointer + (core.sizeX[0] * ebpp)) && canUsePrevious) { 
    1433             System.arraycopy(prevPixels, off, output, off, 
    1434               (rowPointer + (core.sizeX[0] * ebpp)) - off); 
    1435           } 
    1436  
    1437           break; 
    1438         } 
    1439         else if (rle < -1) { 
    1440           // unpack next pixel and copy it to output -(rle) times 
    1441           for (int j=0; j<(-1*rle); j++) { 
    1442             if (off < output.length) { 
    1443               System.arraycopy(input, pt, output, off, ebpp); 
    1444               off += ebpp; 
    1445             } 
    1446             else j = (-1*rle); 
    1447           } 
    1448           pt += ebpp; 
    1449         } 
    1450         else { 
    1451           // copy (rle) pixels to output 
    1452           System.arraycopy(input, pt, output, off, rle*ebpp); 
    1453           pt += rle*ebpp; 
    1454           off += rle*ebpp; 
    1455         } 
    1456       } 
    1457       rowPointer += (core.sizeX[0] * ebpp); 
    1458     } 
    1459     return output; 
     707    else if (code.equals("rle ")) {  
     708      Object[] options = new Object[2]; 
     709      options[0] = new int[] {core.sizeX[0], core.sizeY[0],  
     710        bitsPerPixel < 40 ? bitsPerPixel / 8 : (bitsPerPixel - 32) / 8};  
     711      options[1] = canUsePrevious ? prevPixels : null; 
     712      return new QTRLECodec().decompress(pixs, options);  
     713    } 
     714    else if (code.equals("rpza")) {  
     715      int[] options = new int[2]; 
     716      options[0] = core.sizeX[0]; 
     717      options[1] = core.sizeY[0]; 
     718      return new RPZACodec().decompress(pixs, options);  
     719    } 
     720    else if (code.equals("mjpb")) {  
     721      int[] options = new int[4]; 
     722      options[0] = core.sizeX[0]; 
     723      options[1] = core.sizeY[0]; 
     724      options[2] = bitsPerPixel; 
     725      options[3] = interlaced ? 1 : 0; 
     726      return new MJPBCodec().decompress(pixs, options);  
     727    } 
     728    else if (code.equals("jpeg")) { 
     729      return new JPEGCodec().decompress(pixs); 
     730    } 
     731    else throw new FormatException("Unsupported codec : " + code);  
    1460732  } 
    1461733 
Note: See TracChangeset for help on using the changeset viewer.