Changeset 6328


Ignore:
Timestamp:
05/17/10 12:58:40 (9 years ago)
Author:
melissa
Message:

Fixed a few multi-file export problems. Closes #486.

Location:
trunk/components/bio-formats/src/loci/formats
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/bio-formats/src/loci/formats/IFormatWriter.java

    r6294 r6328  
    4141   * Saves the given image to the current series in the current file. 
    4242   * 
    43    * @param no the image index, starting from 0. 
     43   * @param no the image index within the current file, starting from 0. 
    4444   * @param buf the byte array that represents the image. 
    4545   * @throws FormatException if one of the parameters is invalid. 
     
    5151   * Saves the given image tile to the current series in the current file. 
    5252   * 
    53    * @param no the image index, starting from 0. 
     53   * @param no the image index within the current file, starting from 0. 
    5454   * @param buf the byte array that represents the image tile. 
    5555   * @param x the X coordinate of the upper-left corner of the image tile. 
     
    6666   * Saves the given image plane to the current series in the current file. 
    6767   * 
    68    * @param no the image index, starting from 0. 
     68   * @param no the image index within the current file, starting from 0. 
    6969   * @param plane the image plane. 
    7070   * @throws FormatException if one of the parameters is invalid. 
     
    7676   * Saves the given image plane to the current series in the current file. 
    7777   * 
    78    * @param no the image index, starting from 0. 
     78   * @param no the image index within the current file, starting from 0. 
    7979   * @param plane the image plane. 
    8080   * @param x the X coordinate of the upper-left corner of the image tile. 
  • trunk/components/bio-formats/src/loci/formats/out/APNGWriter.java

    r6294 r6328  
    8686    } 
    8787 
    88     writePixels(no == 0 ? "IDAT" : "fdAT", buf, x, y, w, h); 
    89  
     88    writePixels(numFrames == 0 ? "IDAT" : "fdAT", buf, x, y, w, h); 
    9089    numFrames++; 
    9190  } 
     
    162161    super.close(); 
    163162    numFrames = 0; 
     163    numFramesPointer = 0; 
     164    nextSequenceNumber = 0; 
     165    littleEndian = false; 
    164166  } 
    165167 
  • trunk/components/bio-formats/src/loci/formats/out/AVIWriter.java

    r6294 r6328  
    9090  private long endPos; 
    9191  private long saveidx1Length; 
    92   private int xMod; 
    9392 
    9493  // -- Constructor -- 
     
    105104  { 
    106105    checkParams(no, buf, x, y, w, h); 
    107     MetadataRetrieve meta = getMetadataRetrieve(); 
    108     int type = 
    109       FormatTools.pixelTypeFromString(meta.getPixelsType(series).toString()); 
    110  
    111106    int nChannels = getSamplesPerPixel(); 
    112  
    113     byte[][] lut = null; 
    114  
    115     if (getColorModel() instanceof IndexColorModel) { 
    116       lut = new byte[4][256]; 
    117       IndexColorModel model = (IndexColorModel) getColorModel(); 
    118       model.getReds(lut[0]); 
    119       model.getGreens(lut[1]); 
    120       model.getBlues(lut[2]); 
    121       model.getAlphas(lut[3]); 
    122     } 
    123107 
    124108    if (!initialized[series][no]) { 
    125109      initialized[series][no] = true; 
    126       bytesPerPixel = nChannels == 2 ? 3 : nChannels; 
    127       savedbLength = new Vector<Long>(); 
    128  
    129       if (out.length() > 0) { 
    130         RandomAccessInputStream in = new RandomAccessInputStream(currentId); 
    131         in.order(true); 
    132         in.seek(FRAME_OFFSET); 
    133         planesWritten = in.readInt(); 
    134  
    135         in.seek(SAVE_FILE_SIZE); 
    136         endPos = in.readInt() + SAVE_FILE_SIZE + 4; 
    137  
    138         in.seek(SAVE_LIST2_SIZE); 
    139         idx1Pos = in.readInt() + SAVE_LIST2_SIZE + 4; 
    140         saveidx1Length = idx1Pos + 4; 
    141  
    142         in.seek(saveidx1Length + 4); 
    143         for (int z=0; z<planesWritten; z++) { 
    144           in.skipBytes(8); 
    145           savedbLength.add(in.readInt() + 4 + SAVE_MOVI); 
    146           in.skipBytes(4); 
    147         } 
    148         in.close(); 
    149         out.seek(idx1Pos); 
    150       } 
    151  
    152       out.order(true); 
    153  
    154       tDim = meta.getPixelsSizeZ(series).getValue().intValue(); 
    155       zDim = meta.getPixelsSizeT(series).getValue().intValue(); 
    156       yDim = meta.getPixelsSizeY(series).getValue().intValue(); 
    157       xDim = meta.getPixelsSizeX(series).getValue().intValue(); 
    158  
    159       xPad = 0; 
    160       xMod = xDim % 4; 
    161       if (xMod != 0) { 
    162         xPad = 4 - xMod; 
    163         xDim += xPad; 
    164       } 
    165  
    166       if (out.length() == 0) { 
    167         out.writeBytes("RIFF"); // signature 
    168         // Bytes 4 thru 7 contain the length of the file. This length does 
    169         // not include bytes 0 thru 7. 
    170         out.writeInt(0); // for now write 0 for size 
    171         out.writeBytes("AVI "); // RIFF type 
    172         // Write the first LIST chunk, which contains 
    173         // information on data decoding 
    174         out.writeBytes("LIST"); // CHUNK signature 
    175         // Write the length of the LIST CHUNK not including the first 8 bytes 
    176         // with LIST and size. Note that the end of the LIST CHUNK is followed 
    177         // by JUNK. 
    178         out.writeInt((bytesPerPixel == 1) ? 1240 : 216); 
    179         out.writeBytes("hdrl"); // CHUNK type 
    180         out.writeBytes("avih"); // Write the avih sub-CHUNK 
    181  
    182         // Write the length of the avih sub-CHUNK (38H) not including the 
    183         // the first 8 bytes for avihSignature and the length 
    184         out.writeInt(0x38); 
    185  
    186         // dwMicroSecPerFrame - Write the microseconds per frame 
    187         microSecPerFrame = (int) (1.0 / fps * 1.0e6); 
    188         out.writeInt(microSecPerFrame); 
    189  
    190         // Write the maximum data rate of the file in bytes per second 
    191         out.writeInt(0); // dwMaxBytesPerSec 
    192  
    193         out.writeInt(0); // dwReserved1 - set to 0 
    194         // dwFlags - just set the bit for AVIF_HASINDEX 
    195         out.writeInt(0x10); 
    196  
    197         // 10H AVIF_HASINDEX: The AVI file has an idx1 chunk containing 
    198         //   an index at the end of the file. For good performance, all 
    199         //   AVI files should contain an index. 
    200         // 20H AVIF_MUSTUSEINDEX: Index CHUNK, rather than the physical 
    201         // ordering of the chunks in the file, must be used to determine the 
    202         // order of the frames. 
    203         // 100H AVIF_ISINTERLEAVED: Indicates that the AVI file is interleaved. 
    204         //   This is used to read data from a CD-ROM more efficiently. 
    205         // 800H AVIF_TRUSTCKTYPE: USE CKType to find key frames 
    206         // 10000H AVIF_WASCAPTUREFILE: The AVI file is used for capturing 
    207         //   real-time video. Applications should warn the user before 
    208         //   writing over a file with this fla set because the user 
    209         //   probably defragmented this file. 
    210         // 20000H AVIF_COPYRIGHTED: The AVI file contains copyrighted data 
    211         //   and software. When, this flag is used, software should not 
    212         //   permit the data to be duplicated. 
    213  
    214         // dwTotalFrames - total frame number 
    215         out.writeInt(zDim * tDim); 
    216  
    217         // dwInitialFrames -Initial frame for interleaved files. 
    218         // Noninterleaved files should specify 0. 
    219         out.writeInt(0); 
    220  
    221         // dwStreams - number of streams in the file - here 1 video and 
    222         // zero audio. 
    223         out.writeInt(1); 
    224  
    225         // dwSuggestedBufferSize - Suggested buffer size for reading the file. 
    226         // Generally, this size should be large enough to contain the largest 
    227         // chunk in the file. 
    228         out.writeInt(0); 
    229  
    230         // dwWidth - image width in pixels 
    231         out.writeInt(xDim - xPad); 
    232         out.writeInt(yDim); // dwHeight - height in pixels 
    233  
    234         // dwReserved[4] - Microsoft says to set the following 4 values to 0. 
    235         out.writeInt(0); 
    236         out.writeInt(0); 
    237         out.writeInt(0); 
    238         out.writeInt(0); 
    239  
    240         // Write the Stream line header CHUNK 
    241         out.writeBytes("LIST"); 
    242  
    243         // Write the size of the first LIST subCHUNK not including the first 8 
    244         // bytes with LIST and size. Note that saveLIST1subSize = saveLIST1Size 
    245         // + 76, and that the length written to saveLIST1subSize is 76 less than 
    246         // the length written to saveLIST1Size. The end of the first LIST 
    247         // subCHUNK is followed by JUNK. 
    248  
    249         out.writeInt((bytesPerPixel == 1) ? 1164 : 140); 
    250         out.writeBytes("strl");   // Write the chunk type 
    251         out.writeBytes("strh"); // Write the strh sub-CHUNK 
    252         out.writeInt(56); // Write length of strh sub-CHUNK 
    253  
    254         // fccType - Write the type of data stream - here vids for video stream 
    255         out.writeBytes("vids"); 
    256  
    257         // Write DIB for Microsoft Device Independent Bitmap. 
    258         // Note: Unfortunately, at least 3 other four character codes are 
    259         // sometimes used for uncompressed AVI videos: 'RGB ', 'RAW ', 
    260         // 0x00000000 
    261         out.writeBytes("DIB "); 
    262  
    263         out.writeInt(0); // dwFlags 
    264  
    265         // 0x00000001 AVISF_DISABLED The stram data should be rendered only when 
    266         // explicitly enabled. 
    267         // 0x00010000 AVISF_VIDEO_PALCHANGES Indicates that a palette change is 
    268         // included in the AVI file. This flag warns the playback software that 
    269         // it will need to animate the palette. 
    270  
    271         // dwPriority - priority of a stream type. For example, in a file with 
    272         // multiple audio streams, the one with the highest priority might be 
    273         // the default one. 
    274         out.writeInt(0); 
    275  
    276         // dwInitialFrames - Specifies how far audio data is skewed ahead of 
    277         // video frames in interleaved files. Typically, this is about 0.75 
    278         // seconds. In interleaved files specify the number of frames in the 
    279         // file prior to the initial frame of the AVI sequence. 
    280         // Noninterleaved files should use zero. 
    281         out.writeInt(0); 
    282  
    283         // rate/scale = samples/second 
    284         out.writeInt(1); // dwScale 
    285  
    286         //  dwRate - frame rate for video streams 
    287         out.writeInt(fps); 
    288  
    289         // dwStart - this field is usually set to zero 
    290         out.writeInt(0); 
    291  
    292         // dwLength - playing time of AVI file as defined by scale and rate 
    293         // Set equal to the number of frames 
    294         out.writeInt(tDim * zDim); 
    295  
    296         // dwSuggestedBufferSize - Suggested buffer size for reading the stream. 
    297         // Typically, this contains a value corresponding to the largest chunk 
    298         // in a stream. 
    299         out.writeInt(0); 
    300  
    301         // dwQuality - encoding quality given by an integer between 0 and 
    302         // 10,000. If set to -1, drivers use the default quality value. 
    303         out.writeInt(-1); 
    304  
    305         // dwSampleSize # 
    306         // 0 if the video frames may or may not vary in size 
    307         // If 0, each sample of data(such as a video frame) must be in a 
    308         // separate chunk. If nonzero, then multiple samples of data can be 
    309         // grouped into a single chunk within the file. 
    310         out.writeInt(0); 
    311  
    312         // rcFrame - Specifies the destination rectangle for a text or video 
    313         // stream within the movie rectangle specified by the dwWidth and 
    314         // dwHeight members of the AVI main header structure. The rcFrame member 
    315         // is typically used in support of multiple video streams. Set this 
    316         // rectangle to the coordinates corresponding to the movie rectangle to 
    317         // update the whole movie rectangle. Units for this member are pixels. 
    318         // The upper-left corner of the destination rectangle is relative to the 
    319         // upper-left corner of the movie rectangle. 
    320         out.writeShort((short) 0); // left 
    321         out.writeShort((short) 0); // top 
    322         out.writeShort((short) 0); // right 
    323         out.writeShort((short) 0); // bottom 
    324  
    325         // Write the size of the stream format CHUNK not including the first 8 
    326         // bytes for strf and the size. Note that the end of the stream format 
    327         // CHUNK is followed by strn. 
    328         out.writeBytes("strf"); // Write the stream format chunk 
    329  
    330         // write the strf CHUNK size 
    331         out.writeInt((bytesPerPixel == 1) ? 1068 : 44); 
    332  
    333         // Applications should use this size to determine which BITMAPINFO 
    334         // header structure is being used. This size includes this biSize field. 
    335         // biSize- Write header size of BITMAPINFO header structure 
    336  
    337         out.writeInt(40); 
    338  
    339         // biWidth - image width in pixels 
    340         out.writeInt(xDim); 
    341  
    342         // biHeight - image height in pixels. If height is positive, the bitmap 
    343         // is a bottom up DIB and its origin is in the lower left corner. If 
    344         // height is negative, the bitmap is a top-down DIB and its origin is 
    345         // the upper left corner. This negative sign feature is supported by the 
    346         // Windows Media Player, but it is not supported by PowerPoint. 
    347         out.writeInt(yDim); 
    348  
    349         // biPlanes - number of color planes in which the data is stored 
    350         // This must be set to 1. 
    351         out.writeShort(1); 
    352  
    353         int bitsPerPixel = (bytesPerPixel == 3) ? 24 : 8; 
    354  
    355         // biBitCount - number of bits per pixel # 
    356         // 0L for BI_RGB, uncompressed data as bitmap 
    357         out.writeShort((short) bitsPerPixel); 
    358  
    359         out.writeInt(0); // biSizeImage # 
    360         out.writeInt(0); // biCompression - compression type 
    361         // biXPelsPerMeter - horizontal resolution in pixels 
    362         out.writeInt(0); 
    363         // biYPelsPerMeter - vertical resolution in pixels per meter 
    364         out.writeInt(0); 
    365  
    366         int nColors = 256; 
    367         out.writeInt(nColors); 
    368  
    369         // biClrImportant - specifies that the first x colors of the color table 
    370         // are important to the DIB. If the rest of the colors are not 
    371         // available, the image still retains its meaning in an acceptable 
    372         // manner. When this field is set to zero, all the colors are important, 
    373         // or, rather, their relative importance has not been computed. 
    374         out.writeInt(0); 
    375  
    376         // Write the LUTa.getExtents()[1] color table entries here. They are 
    377         // written: blue byte, green byte, red byte, 0 byte 
    378         if (bytesPerPixel == 1) { 
    379           if (lut != null) { 
    380             for (int i=0; i<256; i++) { 
    381               out.write(lut[2][i]); 
    382               out.write(lut[1][i]); 
    383               out.write(lut[0][i]); 
    384               out.write(lut[3][i]); 
    385             } 
    386           } 
    387           else { 
    388             byte[] lutWrite = new byte[4 * 256]; 
    389             for (int i=0; i<256; i++) { 
    390               lutWrite[4*i] = (byte) i; // blue 
    391               lutWrite[4*i+1] = (byte) i; // green 
    392               lutWrite[4*i+2] = (byte) i; // red 
    393               lutWrite[4*i+3] = 0; 
    394             } 
    395             out.write(lutWrite); 
    396           } 
    397         } 
    398  
    399         out.seek(SAVE_STRF_SIZE); 
    400         out.writeInt((int) (SAVE_STRN_POS - (SAVE_STRF_SIZE + 4))); 
    401         out.seek(SAVE_STRN_POS); 
    402  
    403         // Use strn to provide zero terminated text string describing the stream 
    404         out.writeBytes("strn"); 
    405         out.writeInt(16); // Write length of strn sub-CHUNK 
    406         out.writeBytes("FileAVI write  "); 
    407  
    408         out.seek(SAVE_LIST1_SIZE); 
    409         out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SIZE + 4))); 
    410         out.seek(SAVE_LIST1_SUBSIZE); 
    411         out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SUBSIZE + 4))); 
    412         out.seek(SAVE_JUNK_SIG); 
    413  
    414         // write a JUNK CHUNK for padding 
    415         out.writeBytes("JUNK"); 
    416         out.writeInt((int) PADDING_BYTES); 
    417         for (int i=0; i<PADDING_BYTES/2; i++) { 
    418           out.writeShort((short) 0); 
    419         } 
    420  
    421         // Write the second LIST chunk, which contains the actual data 
    422         out.writeBytes("LIST"); 
    423  
    424         out.writeInt(0);  // For now write 0 
    425         out.writeBytes("movi"); // Write CHUNK type 'movi' 
    426       } 
    427110    } 
    428111 
     
    434117    int height = buf.length / (width * bytesPerPixel); 
    435118 
     119    out.seek(idx1Pos); 
    436120    out.writeBytes(DATA_SIGNATURE); 
    437121    savedbLength.add(new Long(out.getFilePointer())); 
     
    526210  } 
    527211 
     212  // -- IFormatHandler API methods -- 
     213 
     214  /* @see loci.formats.IFormatHandler#close() */ 
     215  public void close() throws IOException { 
     216    super.close(); 
     217    planesWritten = 0; 
     218    bytesPerPixel = 0; 
     219    xDim = yDim = zDim = tDim = xPad = 0; 
     220    microSecPerFrame = 0; 
     221    savedbLength = null; 
     222    idx1Pos = 0; 
     223    endPos = 0; 
     224    saveidx1Length = 0; 
     225  } 
     226 
     227  /* @see loci.formats.IFormatHandler#setId(String) */ 
     228  public void setId(String id) throws FormatException, IOException { 
     229    super.setId(id); 
     230 
     231    savedbLength = new Vector<Long>(); 
     232 
     233    if (out.length() > 0) { 
     234      RandomAccessInputStream in = new RandomAccessInputStream(currentId); 
     235      in.order(true); 
     236      in.seek(FRAME_OFFSET); 
     237      planesWritten = in.readInt(); 
     238 
     239      in.seek(SAVE_FILE_SIZE); 
     240      endPos = in.readInt() + SAVE_FILE_SIZE + 4; 
     241 
     242      in.seek(SAVE_LIST2_SIZE); 
     243      idx1Pos = in.readInt() + SAVE_LIST2_SIZE + 4; 
     244      saveidx1Length = idx1Pos + 4; 
     245 
     246      if (planesWritten > 0) in.seek(saveidx1Length + 4); 
     247      for (int z=0; z<planesWritten; z++) { 
     248        in.skipBytes(8); 
     249        savedbLength.add(in.readInt() + 4 + SAVE_MOVI); 
     250        in.skipBytes(4); 
     251      } 
     252      in.close(); 
     253      out.seek(idx1Pos); 
     254    } 
     255 
     256    out.order(true); 
     257 
     258    MetadataRetrieve meta = getMetadataRetrieve(); 
     259    tDim = meta.getPixelsSizeZ(series).getValue().intValue(); 
     260    zDim = meta.getPixelsSizeT(series).getValue().intValue(); 
     261    yDim = meta.getPixelsSizeY(series).getValue().intValue(); 
     262    xDim = meta.getPixelsSizeX(series).getValue().intValue(); 
     263    String type = meta.getPixelsType(series).toString(); 
     264    int pixelType = FormatTools.pixelTypeFromString(type); 
     265    bytesPerPixel = FormatTools.getBytesPerPixel(pixelType); 
     266 
     267    xPad = 0; 
     268    int xMod = xDim % 4; 
     269    if (xMod != 0) { 
     270      xPad = 4 - xMod; 
     271      xDim += xPad; 
     272    } 
     273 
     274    byte[][] lut = null; 
     275 
     276    if (getColorModel() instanceof IndexColorModel) { 
     277      lut = new byte[4][256]; 
     278      IndexColorModel model = (IndexColorModel) getColorModel(); 
     279      model.getReds(lut[0]); 
     280      model.getGreens(lut[1]); 
     281      model.getBlues(lut[2]); 
     282      model.getAlphas(lut[3]); 
     283    } 
     284 
     285    if (out.length() == 0) { 
     286      out.writeBytes("RIFF"); // signature 
     287      // Bytes 4 thru 7 contain the length of the file. This length does 
     288      // not include bytes 0 thru 7. 
     289      out.writeInt(0); // for now write 0 for size 
     290      out.writeBytes("AVI "); // RIFF type 
     291      // Write the first LIST chunk, which contains 
     292      // information on data decoding 
     293      out.writeBytes("LIST"); // CHUNK signature 
     294      // Write the length of the LIST CHUNK not including the first 8 bytes 
     295      // with LIST and size. Note that the end of the LIST CHUNK is followed 
     296      // by JUNK. 
     297      out.writeInt((bytesPerPixel == 1) ? 1240 : 216); 
     298      out.writeBytes("hdrl"); // CHUNK type 
     299      out.writeBytes("avih"); // Write the avih sub-CHUNK 
     300 
     301      // Write the length of the avih sub-CHUNK (38H) not including the 
     302      // the first 8 bytes for avihSignature and the length 
     303      out.writeInt(0x38); 
     304 
     305      // dwMicroSecPerFrame - Write the microseconds per frame 
     306      microSecPerFrame = (int) (1.0 / fps * 1.0e6); 
     307      out.writeInt(microSecPerFrame); 
     308 
     309      // Write the maximum data rate of the file in bytes per second 
     310      out.writeInt(0); // dwMaxBytesPerSec 
     311 
     312      out.writeInt(0); // dwReserved1 - set to 0 
     313      // dwFlags - just set the bit for AVIF_HASINDEX 
     314      out.writeInt(0x10); 
     315 
     316      // 10H AVIF_HASINDEX: The AVI file has an idx1 chunk containing 
     317      //   an index at the end of the file. For good performance, all 
     318      //   AVI files should contain an index. 
     319      // 20H AVIF_MUSTUSEINDEX: Index CHUNK, rather than the physical 
     320      // ordering of the chunks in the file, must be used to determine the 
     321      // order of the frames. 
     322      // 100H AVIF_ISINTERLEAVED: Indicates that the AVI file is interleaved. 
     323      //   This is used to read data from a CD-ROM more efficiently. 
     324      // 800H AVIF_TRUSTCKTYPE: USE CKType to find key frames 
     325      // 10000H AVIF_WASCAPTUREFILE: The AVI file is used for capturing 
     326      //   real-time video. Applications should warn the user before 
     327      //   writing over a file with this fla set because the user 
     328      //   probably defragmented this file. 
     329      // 20000H AVIF_COPYRIGHTED: The AVI file contains copyrighted data 
     330      //   and software. When, this flag is used, software should not 
     331      //   permit the data to be duplicated. 
     332 
     333      // dwTotalFrames - total frame number 
     334      out.writeInt(0); 
     335 
     336      // dwInitialFrames -Initial frame for interleaved files. 
     337      // Noninterleaved files should specify 0. 
     338      out.writeInt(0); 
     339 
     340      // dwStreams - number of streams in the file - here 1 video and 
     341      // zero audio. 
     342      out.writeInt(1); 
     343 
     344      // dwSuggestedBufferSize - Suggested buffer size for reading the file. 
     345      // Generally, this size should be large enough to contain the largest 
     346      // chunk in the file. 
     347      out.writeInt(0); 
     348 
     349      // dwWidth - image width in pixels 
     350      out.writeInt(xDim - xPad); 
     351      out.writeInt(yDim); // dwHeight - height in pixels 
     352 
     353      // dwReserved[4] - Microsoft says to set the following 4 values to 0. 
     354      out.writeInt(0); 
     355      out.writeInt(0); 
     356      out.writeInt(0); 
     357      out.writeInt(0); 
     358 
     359      // Write the Stream line header CHUNK 
     360      out.writeBytes("LIST"); 
     361 
     362      // Write the size of the first LIST subCHUNK not including the first 8 
     363      // bytes with LIST and size. Note that saveLIST1subSize = saveLIST1Size 
     364      // + 76, and that the length written to saveLIST1subSize is 76 less than 
     365      // the length written to saveLIST1Size. The end of the first LIST 
     366      // subCHUNK is followed by JUNK. 
     367 
     368      out.writeInt((bytesPerPixel == 1) ? 1164 : 140); 
     369      out.writeBytes("strl");   // Write the chunk type 
     370      out.writeBytes("strh"); // Write the strh sub-CHUNK 
     371      out.writeInt(56); // Write length of strh sub-CHUNK 
     372 
     373      // fccType - Write the type of data stream - here vids for video stream 
     374      out.writeBytes("vids"); 
     375 
     376      // Write DIB for Microsoft Device Independent Bitmap. 
     377      // Note: Unfortunately, at least 3 other four character codes are 
     378      // sometimes used for uncompressed AVI videos: 'RGB ', 'RAW ', 
     379      // 0x00000000 
     380      out.writeBytes("DIB "); 
     381 
     382      out.writeInt(0); // dwFlags 
     383 
     384      // 0x00000001 AVISF_DISABLED The stram data should be rendered only when 
     385      // explicitly enabled. 
     386      // 0x00010000 AVISF_VIDEO_PALCHANGES Indicates that a palette change is 
     387      // included in the AVI file. This flag warns the playback software that 
     388      // it will need to animate the palette. 
     389 
     390      // dwPriority - priority of a stream type. For example, in a file with 
     391      // multiple audio streams, the one with the highest priority might be 
     392      // the default one. 
     393      out.writeInt(0); 
     394 
     395      // dwInitialFrames - Specifies how far audio data is skewed ahead of 
     396      // video frames in interleaved files. Typically, this is about 0.75 
     397      // seconds. In interleaved files specify the number of frames in the 
     398      // file prior to the initial frame of the AVI sequence. 
     399      // Noninterleaved files should use zero. 
     400      out.writeInt(0); 
     401 
     402      // rate/scale = samples/second 
     403      out.writeInt(1); // dwScale 
     404 
     405      //  dwRate - frame rate for video streams 
     406      out.writeInt(fps); 
     407 
     408      // dwStart - this field is usually set to zero 
     409      out.writeInt(0); 
     410 
     411      // dwLength - playing time of AVI file as defined by scale and rate 
     412      // Set equal to the number of frames 
     413      out.writeInt(tDim * zDim); 
     414 
     415      // dwSuggestedBufferSize - Suggested buffer size for reading the stream. 
     416      // Typically, this contains a value corresponding to the largest chunk 
     417      // in a stream. 
     418      out.writeInt(0); 
     419 
     420      // dwQuality - encoding quality given by an integer between 0 and 
     421      // 10,000. If set to -1, drivers use the default quality value. 
     422      out.writeInt(-1); 
     423 
     424      // dwSampleSize # 
     425      // 0 if the video frames may or may not vary in size 
     426      // If 0, each sample of data(such as a video frame) must be in a 
     427      // separate chunk. If nonzero, then multiple samples of data can be 
     428      // grouped into a single chunk within the file. 
     429      out.writeInt(0); 
     430 
     431      // rcFrame - Specifies the destination rectangle for a text or video 
     432      // stream within the movie rectangle specified by the dwWidth and 
     433      // dwHeight members of the AVI main header structure. The rcFrame member 
     434      // is typically used in support of multiple video streams. Set this 
     435      // rectangle to the coordinates corresponding to the movie rectangle to 
     436      // update the whole movie rectangle. Units for this member are pixels. 
     437      // The upper-left corner of the destination rectangle is relative to the 
     438      // upper-left corner of the movie rectangle. 
     439      out.writeShort((short) 0); // left 
     440      out.writeShort((short) 0); // top 
     441      out.writeShort((short) 0); // right 
     442      out.writeShort((short) 0); // bottom 
     443 
     444      // Write the size of the stream format CHUNK not including the first 8 
     445      // bytes for strf and the size. Note that the end of the stream format 
     446      // CHUNK is followed by strn. 
     447      out.writeBytes("strf"); // Write the stream format chunk 
     448 
     449      // write the strf CHUNK size 
     450      out.writeInt((bytesPerPixel == 1) ? 1068 : 44); 
     451 
     452      // Applications should use this size to determine which BITMAPINFO 
     453      // header structure is being used. This size includes this biSize field. 
     454      // biSize- Write header size of BITMAPINFO header structure 
     455 
     456      out.writeInt(40); 
     457 
     458      // biWidth - image width in pixels 
     459      out.writeInt(xDim); 
     460 
     461      // biHeight - image height in pixels. If height is positive, the bitmap 
     462      // is a bottom up DIB and its origin is in the lower left corner. If 
     463      // height is negative, the bitmap is a top-down DIB and its origin is 
     464      // the upper left corner. This negative sign feature is supported by the 
     465      // Windows Media Player, but it is not supported by PowerPoint. 
     466      out.writeInt(yDim); 
     467 
     468      // biPlanes - number of color planes in which the data is stored 
     469      // This must be set to 1. 
     470      out.writeShort(1); 
     471 
     472      int bitsPerPixel = (bytesPerPixel == 3) ? 24 : 8; 
     473 
     474      // biBitCount - number of bits per pixel # 
     475      // 0L for BI_RGB, uncompressed data as bitmap 
     476      out.writeShort((short) bitsPerPixel); 
     477 
     478      out.writeInt(0); // biSizeImage # 
     479      out.writeInt(0); // biCompression - compression type 
     480      // biXPelsPerMeter - horizontal resolution in pixels 
     481      out.writeInt(0); 
     482      // biYPelsPerMeter - vertical resolution in pixels per meter 
     483      out.writeInt(0); 
     484 
     485      int nColors = 256; 
     486      out.writeInt(nColors); 
     487 
     488      // biClrImportant - specifies that the first x colors of the color table 
     489      // are important to the DIB. If the rest of the colors are not 
     490      // available, the image still retains its meaning in an acceptable 
     491      // manner. When this field is set to zero, all the colors are important, 
     492      // or, rather, their relative importance has not been computed. 
     493      out.writeInt(0); 
     494 
     495      // Write the LUTa.getExtents()[1] color table entries here. They are 
     496      // written: blue byte, green byte, red byte, 0 byte 
     497      if (bytesPerPixel == 1) { 
     498        if (lut != null) { 
     499          for (int i=0; i<256; i++) { 
     500            out.write(lut[2][i]); 
     501            out.write(lut[1][i]); 
     502            out.write(lut[0][i]); 
     503            out.write(lut[3][i]); 
     504          } 
     505        } 
     506        else { 
     507          byte[] lutWrite = new byte[4 * 256]; 
     508          for (int i=0; i<256; i++) { 
     509            lutWrite[4*i] = (byte) i; // blue 
     510            lutWrite[4*i+1] = (byte) i; // green 
     511            lutWrite[4*i+2] = (byte) i; // red 
     512            lutWrite[4*i+3] = 0; 
     513          } 
     514          out.write(lutWrite); 
     515        } 
     516      } 
     517 
     518      out.seek(SAVE_STRF_SIZE); 
     519      out.writeInt((int) (SAVE_STRN_POS - (SAVE_STRF_SIZE + 4))); 
     520      out.seek(SAVE_STRN_POS); 
     521 
     522      // Use strn to provide zero terminated text string describing the stream 
     523      out.writeBytes("strn"); 
     524      out.writeInt(16); // Write length of strn sub-CHUNK 
     525      out.writeBytes("FileAVI write  "); 
     526 
     527      out.seek(SAVE_LIST1_SIZE); 
     528      out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SIZE + 4))); 
     529      out.seek(SAVE_LIST1_SUBSIZE); 
     530      out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SUBSIZE + 4))); 
     531      out.seek(SAVE_JUNK_SIG); 
     532 
     533      // write a JUNK CHUNK for padding 
     534      out.writeBytes("JUNK"); 
     535      out.writeInt((int) PADDING_BYTES); 
     536      for (int i=0; i<PADDING_BYTES/2; i++) { 
     537        out.writeShort((short) 0); 
     538      } 
     539 
     540      // Write the second LIST chunk, which contains the actual data 
     541      out.writeBytes("LIST"); 
     542 
     543      out.writeInt(4);  // For now write 0 
     544      out.writeBytes("movi"); // Write CHUNK type 'movi' 
     545      idx1Pos = out.getFilePointer(); 
     546    } 
     547  } 
     548 
    528549} 
  • trunk/components/bio-formats/src/loci/formats/out/ICSWriter.java

    r6294 r6328  
    4949  // -- Fields -- 
    5050 
     51  private long dimensionOffset; 
     52  private int dimensionLength; 
    5153  private long pixelOffset; 
     54  private int lastPlane = -1; 
    5255 
    5356  // -- Constructor -- 
     
    103106      } 
    104107    } 
     108    lastPlane = no; 
    105109  } 
    106110 
     
    115119  } 
    116120 
    117   /* @see loci.formats.IFormatWriter#setId(String) */ 
     121  // -- IFormatHandler API methods -- 
     122 
     123  /* @see loci.formats.IFormatHandler#setId(String) */ 
    118124  public void setId(String id) throws FormatException, IOException { 
    119125    super.setId(id); 
     
    130136      int pixelType = 
    131137        FormatTools.pixelTypeFromString(meta.getPixelsType(series).toString()); 
    132       int bytesPerPixel = FormatTools.getBytesPerPixel(pixelType); 
    133       int rgbChannels = getSamplesPerPixel(); 
    134  
    135       String order = meta.getPixelsDimensionOrder(series).toString(); 
    136       int sizeX = meta.getPixelsSizeX(series).getValue().intValue(); 
    137       int sizeY = meta.getPixelsSizeY(series).getValue().intValue(); 
    138       int z = meta.getPixelsSizeZ(series).getValue().intValue(); 
    139       int c = meta.getPixelsSizeC(series).getValue().intValue(); 
    140       int t = meta.getPixelsSizeT(series).getValue().intValue(); 
    141  
    142       StringBuffer dimOrder = new StringBuffer(); 
    143       int[] sizes = new int[6]; 
    144       int nextSize = 0; 
    145       sizes[nextSize++] = 8 * bytesPerPixel; 
    146  
    147       if (rgbChannels > 1) { 
    148         dimOrder.append("ch\t"); 
    149         sizes[nextSize++] = c; 
    150       } 
    151  
    152       for (int i=0; i<order.length(); i++) { 
    153         if (order.charAt(i) == 'X') sizes[nextSize++] = sizeX; 
    154         else if (order.charAt(i) == 'Y') sizes[nextSize++] = sizeY; 
    155         else if (order.charAt(i) == 'Z') sizes[nextSize++] = z; 
    156         else if (order.charAt(i) == 'T') sizes[nextSize++] = t; 
    157         else if (order.charAt(i) == 'C' && dimOrder.indexOf("ch") == -1) { 
    158           sizes[nextSize++] = c; 
    159           dimOrder.append("ch"); 
    160         } 
    161         if (order.charAt(i) != 'C') { 
    162           dimOrder.append(String.valueOf(order.charAt(i)).toLowerCase()); 
    163         } 
    164         dimOrder.append("\t"); 
    165       } 
    166       out.writeBytes("layout\torder\tbits\t" + dimOrder.toString() + "\n"); 
    167       out.writeBytes("layout\tsizes\t"); 
    168       for (int i=0; i<sizes.length; i++) { 
    169         out.writeBytes(sizes[i] + "\t"); 
    170         if (i == sizes.length - 1) out.writeBytes("\n"); 
    171       } 
     138 
     139      dimensionOffset = out.getFilePointer(); 
     140      int[] sizes = overwriteDimensions(meta); 
     141      dimensionLength = (int) (out.getFilePointer() - dimensionOffset); 
    172142 
    173143      boolean signed = FormatTools.isSigned(pixelType); 
     
    191161 
    192162      out.writeBytes("\nparameter\tscale\t1.000000\t"); 
    193       StringTokenizer st = new StringTokenizer(dimOrder.toString(), "\t"); 
     163      String order = meta.getPixelsDimensionOrder(series).toString(); 
    194164      StringBuffer units = new StringBuffer(); 
    195       while (st.hasMoreTokens()) { 
    196         String token = st.nextToken(); 
    197         Number value = null; 
    198         if (token.equals("x")) { 
     165      for (int i=0; i<order.length(); i++) { 
     166        char dim = order.charAt(i); 
     167        Number value = 1.0; 
     168        if (dim == 'x') { 
    199169          value = meta.getPixelsPhysicalSizeX(0); 
    200170          units.append("micrometers\t"); 
    201171        } 
    202         else if (token.equals("y")) { 
     172        else if (dim == 'y') { 
    203173          value = meta.getPixelsPhysicalSizeY(0); 
    204174          units.append("micrometers\t"); 
    205175        } 
    206         else if (token.equals("z")) { 
     176        else if (dim == 'z') { 
    207177          value = meta.getPixelsPhysicalSizeZ(0); 
    208178          units.append("micrometers\t"); 
    209179        } 
    210         else if (token.equals("t")) { 
     180        else if (dim == 't') { 
    211181          value = meta.getPixelsTimeIncrement(0); 
    212182          units.append("seconds\t"); 
    213183        } 
    214         if (value == null) out.writeBytes("1.000000\t"); 
    215         else out.writeBytes(value + "\t"); 
     184        out.writeBytes(value + "\t"); 
    216185      } 
    217186 
     
    228197  } 
    229198 
     199  /* @see loci.formats.IFormatHandler#close() */ 
     200  public void close() throws IOException { 
     201    if (lastPlane != getPlaneCount() - 1 && out != null) { 
     202      overwriteDimensions(getMetadataRetrieve()); 
     203    } 
     204 
     205    super.close(); 
     206    pixelOffset = 0; 
     207    lastPlane = -1; 
     208    dimensionOffset = 0; 
     209    dimensionLength = 0; 
     210  } 
     211 
     212  // -- Helper methods -- 
     213 
     214  private int[] overwriteDimensions(MetadataRetrieve meta) throws IOException { 
     215    out.seek(dimensionOffset); 
     216    String order = meta.getPixelsDimensionOrder(series).toString(); 
     217    int sizeX = meta.getPixelsSizeX(series).getValue().intValue(); 
     218    int sizeY = meta.getPixelsSizeY(series).getValue().intValue(); 
     219    int z = meta.getPixelsSizeZ(series).getValue().intValue(); 
     220    int c = meta.getPixelsSizeC(series).getValue().intValue(); 
     221    int t = meta.getPixelsSizeT(series).getValue().intValue(); 
     222    int pixelType = 
     223      FormatTools.pixelTypeFromString(meta.getPixelsType(series).toString()); 
     224    int bytesPerPixel = FormatTools.getBytesPerPixel(pixelType); 
     225    int rgbChannels = getSamplesPerPixel(); 
     226 
     227    if (lastPlane < 0) lastPlane = z * c * t - 1; 
     228    int[] pos = FormatTools.getZCTCoords(order, z, c, t, z * c * t, lastPlane); 
     229    lastPlane = -1; 
     230 
     231    StringBuffer dimOrder = new StringBuffer(); 
     232    int[] sizes = new int[6]; 
     233    int nextSize = 0; 
     234    sizes[nextSize++] = 8 * bytesPerPixel; 
     235 
     236    if (rgbChannels > 1) { 
     237      dimOrder.append("ch\t"); 
     238      sizes[nextSize++] = pos[1] + 1; 
     239    } 
     240 
     241    for (int i=0; i<order.length(); i++) { 
     242      if (order.charAt(i) == 'X') sizes[nextSize++] = sizeX; 
     243      else if (order.charAt(i) == 'Y') sizes[nextSize++] = sizeY; 
     244      else if (order.charAt(i) == 'Z') sizes[nextSize++] = pos[0] + 1; 
     245      else if (order.charAt(i) == 'T') sizes[nextSize++] = pos[2] + 1; 
     246      else if (order.charAt(i) == 'C' && dimOrder.indexOf("ch") == -1) { 
     247        sizes[nextSize++] = pos[1] + 1; 
     248        dimOrder.append("ch"); 
     249      } 
     250      if (order.charAt(i) != 'C') { 
     251        dimOrder.append(String.valueOf(order.charAt(i)).toLowerCase()); 
     252      } 
     253      dimOrder.append("\t"); 
     254    } 
     255    out.writeBytes("layout\torder\tbits\t" + dimOrder.toString() + "\n"); 
     256    out.writeBytes("layout\tsizes\t"); 
     257    for (int i=0; i<sizes.length; i++) { 
     258      out.writeBytes(sizes[i] + "\t"); 
     259    } 
     260    while ((out.getFilePointer() - dimensionOffset) < dimensionLength - 1) { 
     261      out.writeBytes(" "); 
     262    } 
     263    out.writeBytes("\n"); 
     264 
     265    return sizes; 
     266  } 
     267 
    230268} 
  • trunk/components/bio-formats/src/loci/formats/out/JavaWriter.java

    r6294 r6328  
    9797      writePlane(varName, (double[]) array, w, h); 
    9898    } 
    99  
    100     if (no == getPlaneCount() - 1) writeFooter(); 
    10199  } 
    102100 
     
    125123  } 
    126124 
     125  /* @see loci.formats.IFormatHandler#close() */ 
     126  public void close() throws IOException { 
     127    if (out != null) writeFooter(); 
     128    super.close(); 
     129  } 
     130 
    127131  // -- Helper methods -- 
    128132 
  • trunk/components/bio-formats/src/loci/formats/out/OMEXMLWriter.java

    r6294 r6328  
    105105  /* @see loci.formats.IFormatHandler#close() */ 
    106106  public void close() throws IOException { 
     107    if (out != null) { 
     108      out.writeBytes(xmlFragments.get(series + 1)); 
     109    } 
    107110    super.close(); 
    108111    xmlFragments = null; 
     
    149152      plane.append("</BinData>"); 
    150153      out.writeBytes(plane.toString()); 
    151     } 
    152  
    153     if (no == getPlaneCount() - 1) { 
    154       out.writeBytes(xmlFragments.get(series + 1)); 
    155154    } 
    156155  } 
  • trunk/components/bio-formats/src/loci/formats/out/QTWriter.java

    r6294 r6328  
    115115  /** Legacy QuickTime writer. */ 
    116116  protected LegacyQTWriter legacy; 
     117 
     118  private int numWritten = 0; 
    117119 
    118120  // -- Constructor -- 
     
    243245      } 
    244246    } 
     247    numWritten++; 
    245248  } 
    246249 
     
    305308    offsets = null; 
    306309    pad = 0; 
     310    numWritten = 0; 
    307311  } 
    308312 
     
    324328  private void writeFooter() throws IOException { 
    325329    out.seek(out.length()); 
    326     int numWritten = getPlaneCount(); 
    327330    MetadataRetrieve r = getMetadataRetrieve(); 
    328331    int width = r.getPixelsSizeX(series).getValue().intValue(); 
Note: See TracChangeset for help on using the changeset viewer.