Ejemplo n.º 1
0
int tiff_finalize(FAR struct tiff_info_s *info)
{
  struct tiff_ifdentry_s ifdentry;
  FAR uint8_t *ptr;
  size_t maxoffsets;
#ifdef CONFIG_DEBUG_GRAPHICS
  size_t total;
#endif
  off_t offset;
  int ret;
  int i;
  int j;

  /* Put all of the pieces together to create the final output file.  There
   * are three pieces:
   *
   * 1) outfile: The partial output file containing the header, IFD and strip
   *    counts. This includes the StripOffsets and StripByteCounts that need
   *    to be updated.  Size=outsize;
   * 2) tmpfile1: This contains the offsets into tmpfile3 for each strip.  The
   *    size of this file is tmp1size.  These offsets are relative to the
   *    beginning of tmpfile3 and need to be offset by outsize+tmp1size.
   * 3) tmpfile3: The strip data.  Size is tmp2size.  This is raw image data;
   *    no fixups are required.
   */

  DEBUGASSERT(info && info->outfd >= 0 && info->tmp1fd >= 0 && info->tmp2fd >= 0);
  DEBUGASSERT((info->outsize & 3) == 0 && (info->tmp1size & 3) == 0);

  /* Fix-up the count value in the StripByteCounts IFD entry in the outfile.
   * The actual number of strips was unknown at the time that the IFD entry
   * was written.
   */

  ret = tiff_readifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry);
  if (ret < 0)
    {
      goto errout;
    }

  tiff_put32(ifdentry.count, info->nstrips);

  ret = tiff_writeifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry);
  if (ret < 0)
    {
      goto errout;
    }

  /* Fix-up the count and offset values in the StripOffsets IFD entry in the
   * outfile.  The StripOffsets data will be stored immediately after the
   * outfile, hence, the correct offset is outsize.
   */

  ret = tiff_readifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry);
  if (ret < 0)
    {
      goto errout;
    }

  tiff_put32(ifdentry.count, info->nstrips);
  tiff_put32(ifdentry.offset, info->outsize);

  ret = tiff_writeifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry);
  if (ret < 0)
    {
      goto errout;
    }

  /* Rewind to the beginning of tmpfile1 */

  offset = lseek(info->tmp1fd, 0, SEEK_SET);
  if (offset == (off_t)-1)
    {
      ret = -errno;
      goto errout;
    }

  /* Seek to the end of the outfile */

  ret = lseek(info->outfd, 0, SEEK_END);
  if (offset == (off_t)-1)
    {
      ret = -errno;
      goto errout;
    }

  /* Now read strip offset data from tmpfile1, update the offsets, and write
   * the updated offsets to the outfile.  The strip data will begin at offset
   * outsize + tmp1size;
   */

  maxoffsets = info->iosize >> 2;
#ifdef CONFIG_DEBUG_GRAPHICS
  total      = 0;
#endif

  for (i = 0; i < info->nstrips; )
    {
      size_t noffsets;
      ssize_t nbytes;

      /* Read a group of up to 32-bit values */

      noffsets = info->nstrips - i;
      if (noffsets > maxoffsets)
        {
          noffsets = maxoffsets;
        }

      nbytes = tiff_read(info->tmp1fd, info->iobuffer, noffsets << 2);

      /* If an error occurs or we fail to read exactly this number of
       * bytes, then something bad happened.
       */

      if (nbytes != noffsets << 2)
        {
          goto errout;
        }

      /* Fix up the offsets */

      for (j = 0, ptr = info->iobuffer;
           j < noffsets;
           j++, ptr += 4)
        {
          uint32_t stripoff = tiff_get32(ptr);
          stripoff += (info->outsize + info->tmp1size);
          tiff_put32(ptr, stripoff);
        }

      /* Then write the corrected offsets to the outfile */

      ret = tiff_write(info->outfd, info->iobuffer, nbytes);
      if (ret < 0)
        {
          goto errout;
        }

      /* Update the count of offsets written */

      i     += noffsets;
#ifdef CONFIG_DEBUG_GRAPHICS
      total += nbytes;
#endif
    }
#ifdef CONFIG_DEBUG_GRAPHICS
  ASSERT(total == info->tmp1size);
#endif

  /* Rewind to the beginning of tmpfile2 */

  offset = lseek(info->tmp2fd, 0, SEEK_SET);
  if (offset == (off_t)-1)
    {
      ret = -errno;
      goto errout;
    }

  /* Finally, copy the tmpfile2 to the end of the outfile */

#ifdef CONFIG_DEBUG_GRAPHICS
  total = 0;
#endif
  for (;;)
    {
      ssize_t nbytes;

      /* Read a block of data from tmpfile2 */

      nbytes = tiff_read(info->tmp2fd, info->iobuffer, info->iosize);

      /* Check for tead errors and for end-of-file */

      if (nbytes < 0)
        {
          ret = (int)nbytes;
          goto errout;
        }
      else if (nbytes == 0)
        {
          break;
        }

      /* Then copy the data to the outfile */

      ret = tiff_write(info->outfd, info->iobuffer, nbytes);
      if (ret < 0)
        {
          goto errout;
        }

#ifdef CONFIG_DEBUG_GRAPHICS
      total += nbytes;
#endif
    }
#ifdef CONFIG_DEBUG_GRAPHICS
  ASSERT(total == info->tmp2size);
#endif

  /* Close all files and return success */

  tiff_cleanup(info);
  return OK;

errout:
  tiff_abort(info);
  return ret;
}
Ejemplo n.º 2
0
int tiff_initialize(FAR struct tiff_info_s *info)
{
  uint16_t val16;
#if CONFIG_DEBUG_TIFFOFFSETS
  off_t offset = 0;
#endif
  char timbuf[TIFF_DATETIME_STRLEN + 8];
  int ret = -EINVAL;

  DEBUGASSERT(info && info->outfile && info->tmpfile1 && info->tmpfile2);

  /* Open all output files */

  info->outfd = open(info->outfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
  if (info->outfd < 0)
    {
      gdbg("Failed to open %s for reading/writing: %d\n", info->outfile, errno);
      goto errout;
    }

  info->tmp1fd = open(info->tmpfile1, O_RDWR|O_CREAT|O_TRUNC, 0666);
  if (info->tmp1fd < 0)
    {
      gdbg("Failed to open %s for reading/writing: %d\n", info->tmpfile1, errno);
      goto errout;
    }

  info->tmp2fd = open(info->tmpfile1, O_RDWR|O_CREAT|O_TRUNC, 0666);
  if (info->tmp2fd < 0)
    {
      gdbg("Failed to open %s for reading/writing: %d\n", info->tmpfile1, errno);
      goto errout;
    }

  /* Make some decisions using the color format.  Only the following are
   * supported:
   */

  info->pps = info->imgwidth * info->rps;           /* Pixels per strip */
  switch (info->colorfmt)
    {
      case FB_FMT_Y1:                               /* BPP=1, monochrome, 0=black */
        info->filefmt  = &g_bilevinfo;              /* Bi-level file image file info */
        info->imgflags = IMGFLAGS_FMT_Y1;           /* Bit encoded image characteristics */
        info->bps      = (info->pps + 7) >> 3;      /* Bytes per strip */
        break;

      case FB_FMT_Y4:                               /* BPP=4, 4-bit greyscale, 0=black */
        info->filefmt  = &g_greyinfo;               /* Greyscale file image file info */
        info->imgflags = IMGFLAGS_FMT_Y4;           /* Bit encoded image characteristics */
        info->bps      = (info->pps + 1) >> 1;      /* Bytes per strip */
        break;

      case FB_FMT_Y8:                               /* BPP=8, 8-bit greyscale, 0=black */
        info->filefmt  = &g_greyinfo;               /* Greyscale file image file info */
        info->imgflags = IMGFLAGS_FMT_Y8;           /* Bit encoded image characteristics */
        info->bps      = info->pps;                 /* Bytes per strip */
        break;

      case FB_FMT_RGB16_565:                        /* BPP=16 R=6, G=6, B=5 */
        info->filefmt  = &g_rgbinfo;                /* RGB file image file info */
        info->imgflags = IMGFLAGS_FMT_RGB16_565;    /* Bit encoded image characteristics */
        info->bps      = 3 * info->pps;             /* Bytes per strip */
        break;

      case FB_FMT_RGB24:                            /* BPP=24 R=8, G=8, B=8 */
        info->filefmt  = &g_rgbinfo;                /* RGB file image file info */
        info->imgflags = IMGFLAGS_FMT_RGB24;        /* Bit encoded image characteristics */
        info->bps      = 3 *info->pps;              /* Bytes per strip */
        break;

      default:
        gdbg("Unsupported color format: %d\n", info->colorfmt);
        return -EINVAL;
    }

  /* Write the TIFF header data to the outfile:
   *
   * Header:    0    Byte Order                  "II" or "MM"
   *            2    Magic Number                42     
   *            4    1st IFD offset              10
   *            8    [2 bytes padding]
   */

  ret = tiff_putheader(info);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, TIFF_IFD_OFFSET);

  /* Write the Number of directory entries
   *
   * All formats: Offset 10 Number of Directory Entries 12
   */

  ret = tiff_putint16(info->outfd, info->filefmt->nifdentries);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 2);

  /* Write the NewSubfileType IFD entry
   *
   * All formats: Offset 12 NewSubfileType
   */

  ret = tiff_putifdentry16(info, IFD_TAG_NEWSUBFILETYPE, IFD_FIELD_LONG, 1, 0);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write ImageWidth and ImageLength
   *
   * All formats: Offset 24 ImageWidth  Number of columns is a user parameter
   *                     36 ImageLength Number of rows is a user parameter
   */

  ret = tiff_putifdentry16(info, IFD_TAG_IMAGEWIDTH, IFD_FIELD_SHORT, 1, info->imgwidth);
  if (ret == OK)
    {
      ret= tiff_putifdentry16(info, IFD_TAG_IMAGELENGTH, IFD_FIELD_SHORT, 1, info->imgheight);
    }

  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 2*SIZEOF_IFD_ENTRY);

  /* Write BitsPerSample
   *
   * Bi-level Images: None
   * Greyscale:       Offset 48 BitsPerSample (4 or 8)
   * RGB:             Offset 48 BitsPerSample (8,8,8)
   */

  tiff_checkoffs(offset, 48);
  if (IMGFLAGS_ISGREY(info->imgflags))
    {
      if (IMGFLAGS_ISGREY8(info->imgflags))
        {
          val16 = 8;
        }
      else
        {
          val16 = 4;
        }

      ret = tiff_putifdentry16(info, IFD_TAG_BITSPERSAMPLE, IFD_FIELD_SHORT, 1, val16);
      if (ret < 0)
        {
          goto errout;
        }
      tiff_offset(offset, SIZEOF_IFD_ENTRY);
    }
  else if (IMGFLAGS_ISRGB(info->imgflags))
    {
      ret = tiff_putifdentry(info, IFD_TAG_BITSPERSAMPLE, IFD_FIELD_SHORT, 3, TIFF_RGB_BPSOFFSET);
      if (ret < 0)
        {
          goto errout;
        }
      tiff_offset(offset, SIZEOF_IFD_ENTRY);
    }

  /* Write Compression:
   *
   * Bi-level Images: Offset 48 Hard-coded no compression (for now)
   * Greyscale:       Offset 60  "  " "   " "" "          " " " " "
   * RGB:             Offset 60 "  " "   " "" "          " " " " "
   */

  ret = tiff_putifdentry16(info, IFD_TAG_COMPRESSION, IFD_FIELD_SHORT, 1, TAG_COMP_NONE);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write PhotometricInterpretation:
   *
   * Bi-level Images: Offset 48 Hard-coded BlackIsZero
   * Greyscale:       Offset 72 Hard-coded BlackIsZero
   * RGB:             Offset 72 Hard-coded RGB
   */

  if (IMGFLAGS_ISRGB(info->imgflags))
    {
      val16 = TAG_PMI_RGB;
    }
  else
    {
      val16 = TAG_PMI_BLACK;
    }

  ret = tiff_putifdentry16(info, IFD_TAG_PMI, IFD_FIELD_SHORT, 1, val16);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write StripOffsets:
   *
   * Bi-level Images: Offset 72 Value determined by switch statement above
   * Greyscale:       Offset 84 Value determined by switch statement above
   * RGB:             Offset 84 Value determined by switch statement above
   */

  tiff_checkoffs(offset, info->filefmt->soifdoffset);
  ret = tiff_putifdentry(info, IFD_TAG_STRIPOFFSETS, IFD_FIELD_LONG, 0, 0);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write SamplesPerPixel
   *
   * Bi-level Images: N/A
   * Greyscale:       N/A
   * RGB:             Offset 96 Hard-coded to 3
   */

  if (IMGFLAGS_ISRGB(info->imgflags))
    {
      ret = tiff_putifdentry16(info, IFD_TAG_SAMPLESPERPIXEL, IFD_FIELD_SHORT, 1, 3);
      if (ret < 0)
        {
          goto errout;
        }
      tiff_offset(offset, SIZEOF_IFD_ENTRY);
    }

  /* Write RowsPerStrip:
   *
   * Bi-level Images: Offset  84 Value is a user parameter
   * Greyscale:       Offset  96 Value is a user parameter
   * RGB:             Offset 108 Value is a user parameter
   */

  ret = tiff_putifdentry16(info, IFD_TAG_ROWSPERSTRIP, IFD_FIELD_SHORT, 1, info->rps);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write StripByteCounts:
   *
   * Bi-level Images: Offset  96 Count determined as strips added, Value offset = 216
   * Greyscale:       Offset 108 Count determined as strips added, Value offset = 228
   * RGB:             Offset 120 Count determined as strips added, Value offset = 248
   */

  tiff_checkoffs(offset, info->filefmt->sbcifdoffset);
  ret = tiff_putifdentry(info, IFD_TAG_STRIPCOUNTS, IFD_FIELD_LONG, 0, info->filefmt->sbcoffset);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write XResolution and YResolution:
   *
   * Bi-level Images: Offset 108 and 120, Values are a user parameters
   * Greyscale:       Offset 120 and 132, Values are a user parameters
   * RGB:             Offset 132 and 144, Values are a user parameters
   */

  ret = tiff_putifdentry(info, IFD_TAG_XRESOLUTION, IFD_FIELD_RATIONAL, 1, info->filefmt->xresoffset);
  if (ret == OK)
    {
      ret = tiff_putifdentry(info, IFD_TAG_YRESOLUTION, IFD_FIELD_RATIONAL, 1, info->filefmt->yresoffset);
    }

  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 2*SIZEOF_IFD_ENTRY);

  /* Write ResolutionUnit:
   *
   * Bi-level Images: Offset 132, Hard-coded to "inches"
   * Greyscale:       Offset 144, Hard-coded to "inches"
   * RGB:             Offset 156, Hard-coded to "inches"
   */

  ret = tiff_putifdentry16(info, IFD_TAG_RESUNIT, IFD_FIELD_SHORT, 1, TAG_RESUNIT_INCH);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write Software:
   *
   * Bi-level Images: Offset 144 Count, Hard-coded "NuttX"
   * Greyscale:       Offset 156 Count, Hard-coded "NuttX"
   * RGB:             Offset 168 Count, Hard-coded "NuttX"
   */

  ret = tiff_putifdentry(info, IFD_TAG_SOFTWARE, IFD_FIELD_ASCII, TIFF_SOFTWARE_STRLEN, info->filefmt->swoffset);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write DateTime:
   *
   * Bi-level Images: Offset 156 Count, Format "YYYY:MM:DD HH:MM:SS"
   * Greyscale:       Offset 168 Count, Format "YYYY:MM:DD HH:MM:SS"
   * RGB:             Offset 180 Count, Format "YYYY:MM:DD HH:MM:SS"
   */

  ret = tiff_putifdentry(info, IFD_TAG_DATETIME, IFD_FIELD_ASCII, TIFF_DATETIME_STRLEN, info->filefmt->dateoffset);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, SIZEOF_IFD_ENTRY);

  /* Write Next IFD Offset and 2 bytes of padding:
   *
   * Bi-level Images: Offset 168, Next IFD offset
   *                  Offset 170, [2 bytes padding]
   * Greyscale:       Offset 180, Next IFD offset
   *                  Offset 182, [2 bytes padding]
   * RGB:             Offset 192, Next IFD offset
   *                  Offset 194, [2 bytes padding]
   */

  ret = tiff_putint32(info->outfd, 0);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 4);

  /* Now we begin the value section of the file */
  
  tiff_checkoffs(offset, info->filefmt->valoffset);

  /* Write the XResolution and YResolution data:
   * 
   * Bi-level Images: Offset 172 Count, Hard-coded to 300/1
   *                  Offset 180 Count, Hard-coded to 300/1
   * Greyscale:       Offset 184 Count, Hard-coded to 300/1
   *                  Offset 192 Count, Hard-coded to 300/1
   * RGB:             Offset 196 Count, Hard-coded to 300/1
   *                  Offset 204 Count, Hard-coded to 300/1
   */

  tiff_checkoffs(offset, info->filefmt->xresoffset);
  ret = tiff_putint32(info->outfd, 300);
  if (ret == OK)
    {
      ret = tiff_putint32(info->outfd, 1);
    }

  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 8);

  tiff_checkoffs(offset, info->filefmt->yresoffset);
  ret = tiff_putint32(info->outfd, 300);
  if (ret == OK)
    {
      ret = tiff_putint32(info->outfd, 1);
    }

  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 8);

  /* Write RGB BitsPerSample Data:
   *
   * Bi-level Images: N/A
   * Greyscale:       N/A
   * RGB:             Offset 212 BitsPerSample (8,8,8)
   *                  Offset 218  [2 bytes padding]
   */

  if (IMGFLAGS_ISRGB(info->imgflags))
    {
      tiff_checkoffs(offset, TIFF_RGB_BPSOFFSET);
      tiff_putint16(info->outfd, 8);
      tiff_putint16(info->outfd, 8);
      tiff_putint16(info->outfd, 8);
      tiff_putint16(info->outfd, 0);
      tiff_offset(offset, 8);
    }

  /* Write the Software string:
   *
   *
   * Bi-level Images: Offset 188, Hard-coded "NuttX"
   * Greyscale:       Offset 200, Hard-coded "NuttX"
   * RGB:             Offset 220, Hard-coded "NuttX"
   */
   
  tiff_checkoffs(offset, info->filefmt->swoffset);
  ret = tiff_putstring(info->outfd, TIFF_SOFTWARE_STRING, TIFF_SOFTWARE_STRLEN);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, TIFF_SOFTWARE_STRLEN);

  /* Write the DateTime string:
   *
   *
   * Bi-level Images: Offset 188, Format "YYYY:MM:DD HH:MM:SSS"
   * Greyscale:       Offset 200, Hard-coded "NuttX"
   * RGB:             Offset 220, Hard-coded "NuttX"
   */

  tiff_checkoffs(offset, info->filefmt->dateoffset);
  ret = tiff_datetime(timbuf, TIFF_DATETIME_STRLEN + 8);
  if (ret < 0)
    {
      goto errout;
    }

  ret = tiff_putstring(info->outfd, timbuf, TIFF_DATETIME_STRLEN);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, TIFF_DATETIME_STRLEN);

  /* Add two bytes of padding */

  ret = tiff_putint16(info->outfd, 0);
  if (ret < 0)
    {
      goto errout;
    }
  tiff_offset(offset, 2);

  /* And that should do it! */

  tiff_checkoffs(offset, info->filefmt->sbcoffset);
  info->outsize = info->filefmt->sbcoffset;
  return OK;

errout:
  tiff_abort(info);
  return ret;
}