home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / grfx_snd / tifflib / source / tif_writ.c < prev    next >
C/C++ Source or Header  |  1992-12-25  |  16KB  |  405 lines

  1. #pragma warn -use
  2. static char     *sccsid = "@(#)TIFF/tif_write.c 1.25, Copyright (c) Sam Leffler, Dieter Linde, "__DATE__;
  3. #pragma warn .use
  4. /*
  5.  * Copyright (c) 1988, 1990 by Sam Leffler, Oct 8 1990
  6.  * All rights reserved.
  7.  *
  8.  * This file is provided for unrestricted use provided that this legend is included on all tape media and as a part of the
  9.  * software program in whole or part.  Users may copy, modify or distribute this file at will.
  10.  *
  11.  * TIFF Library.
  12.  *
  13.  * Scanline-oriented Write Support
  14.  */
  15. #include <stdio.h>
  16. #include <assert.h>
  17. #include "tiffio.h"
  18.  
  19. #define roundup(x, y)    ((((x) + ((y) - 1)) / (y)) * (y))
  20. #define howmany(x, y)      (((x) + ((y) - 1)) / (y))
  21.  
  22. #define STRIPINCR          20                 /* expansion factor on strip array */
  23.  
  24. /****************************************************************************
  25.  * Verify file is writable and that the directory information is setup properly.  In doing the latter
  26.  * we also "freeze" the state of the directory so that important information is not changed.
  27.  */
  28. static int
  29. TIFFWriteCheck(
  30.         register TIFF    *tif,
  31.         char         module[]
  32.         )
  33. {
  34.         if (tif->tif_mode == O_RDONLY) {
  35.                    TIFFError(module, "%s: File not open for writing", tif->tif_name);
  36.                 return(0);
  37.         }
  38.  
  39.         /*
  40.          * On the first write verify all the required information has been setup and initialize any data structures that
  41.          * had to wait until directory information was set.
  42.          *
  43.          * Note that a lot of our work is assumed to remain valid because we disallow any of the important parameters
  44.          * from changing after we start writing (i.e. once TIFF_BEENWRITING is set, TIFFSetField will only allow
  45.          * the image's length to be changed).
  46.          */
  47.         if ((tif->tif_flags & TIFF_BEENWRITING) == 0) {
  48.                    if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
  49.                            TIFFError(module, "%s: Must set \"ImageWidth\" before writing data", tif->tif_name);
  50.                         return(0);
  51.                 }
  52.                 if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
  53.                         TIFFError(module, "%s: Must set \"PlanarConfiguration\" before writing data", tif->tif_name);
  54.                         return(0);
  55.                 }
  56.                 if (tif->tif_dir.td_stripoffset == NULL) {
  57.                         register TIFFDirectory    *td = &tif->tif_dir;
  58.  
  59.                         td->td_stripsperimage = (td->td_rowsperstrip == 0xffffffffL || td->td_imagelength == 0) ? 1 : howmany((long)td->td_imagelength, td->td_rowsperstrip);
  60.                         td->td_nstrips = td->td_stripsperimage;
  61.                         if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
  62.                                 td->td_nstrips *= (long)td->td_samplesperpixel;
  63.                         td->td_stripoffset = (u_long *)malloc(td->td_nstrips * sizeof(u_long));
  64.                         td->td_stripbytecount = (u_long *)malloc(td->td_nstrips * sizeof(u_long));
  65.                         if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) {
  66.                                 td->td_nstrips = 0;
  67.                                 TIFFError(module, "%s: No space for strip arrays", tif->tif_name);
  68.                                 return(0);
  69.                         }
  70.  
  71.     /*
  72.          * Place data at the end-of-file (by setting offsets to zero).
  73.          */
  74.                         bzero(td->td_stripoffset, td->td_nstrips * sizeof(u_long));
  75.                         bzero(td->td_stripbytecount, td->td_nstrips * sizeof(u_long));
  76.                         TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
  77.                         TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
  78.                 }
  79.                 tif->tif_flags |= TIFF_BEENWRITING;
  80.         }
  81.         return(1);
  82. }
  83.  
  84. /****************************************************************************
  85.  * Setup the raw data buffer used for encoding.
  86.  */
  87. static int
  88. TIFFBufferSetup(
  89.         register TIFF    *tif,
  90.         char         module[]
  91.         )
  92. {
  93.         int     scanline;
  94.  
  95.         tif->tif_scanlinesize = scanline = TIFFScanlineSize(tif);
  96.  
  97.         /*
  98.          * Make raw data buffer at least 8K.
  99.          */
  100.         if (scanline < 8 * 1024)
  101.                 scanline = 8 * 1024;
  102.         if ((tif->tif_rawdata = (u_char *)malloc(scanline)) == NULL) {
  103.                 TIFFError(module, "%s: No space for output buffer", tif->tif_name);
  104.                 return(0);
  105.         }
  106.         tif->tif_rawdatasize = (long)scanline;
  107.         tif->tif_rawcc = 0;
  108.         tif->tif_rawcp = tif->tif_rawdata;
  109.         return(1);
  110. }
  111.  
  112. /****************************************************************************
  113.  * Append the data to the specified strip.
  114.  *
  115.  * NB: We don't check that there's space in the file (i.e. that strips do not overlap).
  116.  */
  117. static int
  118. TIFFAppendToStrip(
  119.         TIFF     *tif,
  120.         u_int     strip,
  121.         void     *data,
  122.         u_int     cc
  123.         )
  124. {
  125.         static char     module[] = "TIFFAppendToStrip";
  126.         TIFFDirectory    *td = &tif->tif_dir;
  127.  
  128.         if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) {
  129.  
  130.     /*
  131.          * No current offset, set the current strip.
  132.          */
  133.                 if (td->td_stripoffset[strip] != 0) {
  134.                         if (!SeekOK(tif->tif_fd, td->td_stripoffset[strip])) {
  135.                                    TIFFError(module, "%s: Seek error at scanline %d", tif->tif_name, tif->tif_row);
  136.                                 return(0);
  137.                         }
  138.                 } 
  139.                 else
  140.                         td->td_stripoffset[strip] = lseek(tif->tif_fd, 0, L_XTND);
  141.                 tif->tif_curoff = td->td_stripoffset[strip];
  142.         }
  143.         if (!WriteOK(tif->tif_fd, data, cc)) {
  144.                    TIFFError(module, "%s: Write error at scanline %d", tif->tif_name, tif->tif_row);
  145.                 return(0);
  146.         }
  147.         tif->tif_curoff += (long)cc;
  148.         td->td_stripbytecount[strip] += (long)cc;
  149.         return(1);
  150. }
  151.  
  152. /****************************************************************************
  153.  * Internal version of TIFFFlushData that can be called by ``encodestrip routines'' w/o concern
  154.  * for infinite recursion.
  155.  */
  156. int
  157. TIFFFlushData1(
  158.         register TIFF    *tif
  159.         )
  160. {
  161.         if (tif->tif_dir.td_fillorder != tif->tif_fillorder && (tif->tif_flags & TIFF_NOBITREV) == 0)
  162.                    TIFFReverseBits((u_char *)tif->tif_rawdata, tif->tif_rawcc);
  163.         if (!TIFFAppendToStrip(tif, tif->tif_curstrip, tif->tif_rawdata, (u_int)tif->tif_rawcc))
  164.                 return(0);
  165.         tif->tif_rawcc = 0;
  166.         tif->tif_rawcp = tif->tif_rawdata;
  167.         return(1);
  168. }
  169.  
  170. /****************************************************************************
  171.  * Flush buffered data to the file.
  172.  */
  173. int
  174. TIFFFlushData(
  175.         TIFF    *tif
  176.         )
  177. {
  178.         if ((tif->tif_flags & TIFF_BEENWRITING) == 0)
  179.                 return(0);
  180.         if (tif->tif_encodestrip && !(*tif->tif_encodestrip)(tif))
  181.                 return(0);
  182.         return(TIFFFlushData1(tif));
  183. }
  184.  
  185. /****************************************************************************
  186.  * Grow the strip data structures by delta strips.
  187.  */
  188. static int
  189. TIFFGrowStrips(
  190.         TIFF    *tif,
  191.         long     delta,
  192.         char     module[]
  193.         )
  194. {
  195.         TIFFDirectory    *td = &tif->tif_dir;
  196.  
  197.         assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
  198.         td->td_stripoffset = (u_long *)realloc(td->td_stripoffset, (td->td_nstrips + delta) * sizeof(u_long));
  199.         td->td_stripbytecount = (u_long *)realloc(td->td_stripbytecount, (td->td_nstrips + delta) * sizeof(u_long));
  200.         if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) {
  201.                 td->td_nstrips = 0;
  202.                 TIFFError(module, "%s: No space to expand strip arrays", tif->tif_name);
  203.                 return(0);
  204.         }
  205.         bzero(td->td_stripoffset + td->td_nstrips, delta * sizeof(u_long));
  206.         bzero(td->td_stripbytecount + td->td_nstrips, delta * sizeof(u_long));
  207.         td->td_nstrips += delta;
  208.         return(1);
  209. }
  210.  
  211. /****************************************************************************
  212.  *
  213.  */
  214. int
  215. TIFFWriteScanline(
  216.         register TIFF    *tif,
  217.         void        *buf,
  218.         u_int         row, 
  219.         u_int        sample
  220.         )
  221. {
  222.         static char        module[] = "TIFFWriteScanline";
  223.         register TIFFDirectory     *td;
  224.         long            strip;
  225.         int             status;
  226.         int            imagegrew = 0;
  227.  
  228.         if (!TIFFWriteCheck(tif, module))
  229.                 return(-1);
  230.  
  231.         /*
  232.          * Handle delayed allocation of data buffer.  This permits it to be sized more intelligently (using
  233.          * directory information).
  234.          */
  235.         if ((tif->tif_flags & TIFF_BUFFERSETUP) == 0) {
  236.                 if (!TIFFBufferSetup(tif, module))
  237.                         return(-1);
  238.                 tif->tif_flags |= TIFF_BUFFERSETUP;
  239.         }
  240.         td = &tif->tif_dir;
  241.  
  242.         /*
  243.          * Extend image length if needed (but only for PlanarConfig=1).
  244.          */
  245.         if (row >= td->td_imagelength) {           /* extend image */
  246.                 if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
  247.                         TIFFError(tif->tif_name, "Can't change \"ImageLength\" when using separate planes");
  248.                         return(-1);
  249.                 }
  250.                 td->td_imagelength = row + 1;
  251.                 imagegrew = 1;
  252.         }
  253.  
  254.         /*
  255.          * Calculate strip and check for crossings.
  256.          */
  257.         if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
  258.                    if (sample >= td->td_samplesperpixel) {
  259.                            TIFFError(tif->tif_name, "%d: Sample out of range, max %d", sample, td->td_samplesperpixel);
  260.                         return(-1);
  261.                 }
  262.                 strip = (long)sample * td->td_stripsperimage + (long)row / td->td_rowsperstrip;
  263.         } 
  264.         else
  265.                 strip = (long)row / td->td_rowsperstrip;
  266.         if (strip != tif->tif_curstrip) {
  267.  
  268.     /*
  269.          * Changing strips -- flush any data present.
  270.          */
  271.                    if (tif->tif_rawcc > 0 && !TIFFFlushData(tif))
  272.                            return(-1);
  273.                 tif->tif_curstrip = (int)strip;
  274.  
  275.     /*
  276.          * Watch out for a growing image.  The value of strips/image will initially be 1 (since it
  277.          * can't be deduced until the imagelength is known).
  278.          */
  279.                 if (strip >= td->td_stripsperimage && imagegrew)
  280.                         td->td_stripsperimage = howmany((long)td->td_imagelength, td->td_rowsperstrip);
  281.                 tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
  282.                 if (tif->tif_stripencode && !(*tif->tif_stripencode)(tif))
  283.                            return(-1);
  284.         }
  285.  
  286.         /*
  287.          * Check strip array to make sure there's space.  We don't support dynamically growing files that
  288.          * have data organized in separate bitplanes because it's too painful.  In that case we require that
  289.          * the imagelength be set properly before the first write (so that the strips array will be fully
  290.          * allocated above).
  291.          */
  292.         if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
  293.                 return(-1);
  294.  
  295.         /*
  296.          * Ensure the write is either sequential or at the beginning of a strip (or that we can randomly
  297.          * access the data -- i.e. no encoding).
  298.          */
  299.         if (row != tif->tif_row) {
  300.                    if (tif->tif_seek) {
  301.                         if (row < tif->tif_row) {
  302.  
  303.     /*
  304.          * Moving backwards within the same strip: backup to the start and then decode
  305.          * forward (below).
  306.          */
  307.                                    tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
  308.                                 tif->tif_rawcp = tif->tif_rawdata;
  309.                         }
  310.  
  311.     /*
  312.          * Seek forward to the desired row.
  313.          */
  314.                            if (!(*tif->tif_seek)(tif, row - tif->tif_row))
  315.                                 return(-1);
  316.                         tif->tif_row = row;
  317.                 } 
  318.                 else {
  319.                         TIFFError(tif->tif_name, "Compression algorithm does not support random access");
  320.                         return(-1);
  321.                 }
  322.         }
  323.         status = (*tif->tif_encoderow)(tif, buf, tif->tif_scanlinesize);
  324.         tif->tif_row++;
  325.         return(status);
  326. }
  327.  
  328. /****************************************************************************
  329.  * Encode the supplied data and write it to the specified strip.  There must be space for the
  330.  * data; we don't check if strips overlap!
  331.  *
  332.  * NB: Image length must be setup before writing; this interface does not support automatically growing
  333.  *     the image on each write (as TIFFWriteScanline does).
  334.  */
  335. int
  336. TIFFWriteEncodedStrip(
  337.     register TIFF    *tif,
  338.         u_int         strip,
  339.         void         *data,
  340.         u_int         cc
  341.         )
  342. {
  343.         static char    module[] = "TIFFWriteEncodedStrip";
  344.  
  345.         if (!TIFFWriteCheck(tif, module))
  346.                 return(-1);
  347.         if (strip >= tif->tif_dir.td_nstrips) {
  348.                    TIFFError(module, "%s: Strip %d out of range, max %d", tif->tif_name, strip, tif->tif_dir.td_nstrips);
  349.                 return(-1);
  350.         }
  351.  
  352.         /*
  353.          * Handle delayed allocation of data buffer.  This permits it to be sized more intelligently (using
  354.          * directory information).
  355.          */
  356.         if ((tif->tif_flags & TIFF_BUFFERSETUP) == 0) {
  357.                 if (!TIFFBufferSetup(tif, module))
  358.                            return(-1);
  359.                 tif->tif_flags |= TIFF_BUFFERSETUP;
  360.         }
  361.         tif->tif_curstrip = strip;
  362.         if (tif->tif_encodestrip && !(*tif->tif_encodestrip)(tif))
  363.                 return(0);
  364.  
  365.         /*
  366.          * Note that this assumes that encoding routines can handle multiple scanlines.  All the "standard"
  367.          * ones in the library do!
  368.          */
  369.         if (!(*tif->tif_encoderow)(tif, data, cc))
  370.                 return(0);
  371.         if (tif->tif_dir.td_fillorder != tif->tif_fillorder && (tif->tif_flags & TIFF_NOBITREV) == 0)
  372.                    TIFFReverseBits((u_char *)tif->tif_rawdata, tif->tif_rawcc);
  373.         if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, (u_int)tif->tif_rawcc))
  374.                 return(-1);
  375.         tif->tif_rawcc = 0;
  376.         tif->tif_rawcp = tif->tif_rawdata;
  377.         return(cc);
  378. }
  379.  
  380. /****************************************************************************
  381.  * Write the supplied data to the specified strip.  There must be space for the data; we don't check
  382.  * if strips overlap!
  383.  *
  384.  * NB: Image length must be setup before writing; this interface does not support automatically growing
  385.  *     the image on each write (as TIFFWriteScanline does).
  386.  */
  387. int
  388. TIFFWriteRawStrip(
  389.         TIFF     *tif,
  390.         u_int     strip,
  391.         void     *data,
  392.         u_int     cc
  393.         )
  394. {
  395.         static char    module[] = "TIFFWriteRawStrip";
  396.  
  397.         if (!TIFFWriteCheck(tif, module))
  398.                 return(-1);
  399.         if (strip >= tif->tif_dir.td_nstrips) {
  400.                    TIFFError(module, "%s: Strip %d out of range, max %d", tif->tif_name, strip, tif->tif_dir.td_nstrips);
  401.                 return(-1);
  402.         }
  403.         return(TIFFAppendToStrip(tif, strip, data, cc) ? -1 : cc);
  404. }
  405.