image_io_tiff.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:16k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: image_io_tiff.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:41:46  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: image_io_tiff.cpp,v 1000.4 2004/06/01 19:41:46 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Mike DiCuccio
  35.  *
  36.  * File Description:
  37.  *    CImageIOTiff -- interface class for reading/writing TIFF files
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include "image_io_tiff.hpp"
  41. #include <corelib/ncbifile.hpp>
  42. #include <util/image/image.hpp>
  43. #include <util/image/image_exception.hpp>
  44. #ifdef HAVE_LIBTIFF
  45. //
  46. //
  47. // LIBTIFF functions
  48. //
  49. //
  50. #include <tiffio.h>
  51. BEGIN_NCBI_SCOPE
  52. //
  53. // TIFFlib error / warning handlers
  54. //
  55. static void s_TiffReadErrorHandler(const char* module, const char* fmt,
  56.                                    va_list args)
  57. {
  58.     string msg("Error reading TIFF image: ");
  59.     msg += module;
  60.     msg += ": ";
  61.     msg += NStr::FormatVarargs(fmt, args);
  62.     NCBI_THROW(CImageException, eReadError, msg);
  63. }
  64. static void s_TiffWriteErrorHandler(const char* module, const char* fmt,
  65.                                     va_list args)
  66. {
  67.     string msg("Error writing TIFF image: ");
  68.     msg += module;
  69.     msg += ": ";
  70.     msg += NStr::FormatVarargs(fmt, args);
  71.     NCBI_THROW(CImageException, eWriteError, msg);
  72. }
  73. static void s_TiffWarningHandler(const char* module, const char* fmt,
  74.                                  va_list args)
  75. {
  76.     string msg = module;
  77.     msg += ": ";
  78.     msg += NStr::FormatVarargs(fmt, args);
  79.     LOG_POST(Warning << "Warning reading TIFF image: " << msg);
  80. }
  81. //
  82. // TIFFLib i/o handlers
  83. //
  84. static tsize_t s_TIFFReadHandler(thandle_t handle, tdata_t data, tsize_t len)
  85. {
  86.     CNcbiIfstream* istr = reinterpret_cast<CNcbiIfstream*>(handle);
  87.     if (istr) {
  88.         istr->read(reinterpret_cast<char*>(data), len);
  89.         return istr->gcount();
  90.     }
  91.     return 0;
  92. }
  93. static tsize_t s_TIFFWriteHandler(thandle_t handle, tdata_t data, tsize_t len)
  94. {
  95.     std::ofstream* ostr = reinterpret_cast<std::ofstream*>(handle);
  96.     if (ostr) {
  97.         ostr->write(reinterpret_cast<char*>(data), len);
  98.         if (*ostr) {
  99.             return len;
  100.         }
  101.     }
  102.     return -1;
  103. }
  104. // dummy i/o handler.  TIFFLib tries to read from files opened for writing
  105. static tsize_t s_TIFFDummyIOHandler(thandle_t, tdata_t, tsize_t)
  106. {
  107.     return -1;
  108. }
  109. static toff_t s_TIFFSeekHandler(thandle_t handle, toff_t offset,
  110.                                 int whence)
  111. {
  112.     CNcbiIfstream* istr = reinterpret_cast<CNcbiIfstream*>(handle);
  113.     if (istr) {
  114.         switch (whence) {
  115.         case SEEK_SET:
  116.             istr->seekg(offset, ios::beg);
  117.             break;
  118.         case SEEK_CUR:
  119.             istr->seekg(offset, ios::cur);
  120.             break;
  121.         case SEEK_END:
  122.             istr->seekg(offset, ios::end);
  123.             break;
  124.         }
  125.         return istr->tellg() - CT_POS_TYPE(0);
  126.     }
  127.     return (toff_t)-1;
  128. }
  129. static int s_TIFFCloseHandler(thandle_t handle)
  130. {
  131.     std::ofstream* ostr = reinterpret_cast<std::ofstream*>(handle);
  132.     if (ostr) {
  133.         ostr->flush();
  134.         if ( !*ostr ) {
  135.             return -1;
  136.         }
  137.     }
  138.     return 0;
  139. }
  140. static toff_t s_TIFFSizeHandler(thandle_t handle)
  141. {
  142.     toff_t offs = 0;
  143.     CNcbiIfstream* istr = reinterpret_cast<CNcbiIfstream*>(handle);
  144.     if (istr) {
  145.         CT_POS_TYPE curr_pos = istr->tellg();
  146.         istr->seekg(0, ios::end);
  147.         offs = istr->tellg() - CT_POS_TYPE(0);
  148.         istr->seekg(curr_pos);
  149.     }
  150.     return offs;
  151. }
  152. static int s_TIFFMapFileHandler(thandle_t, tdata_t*, toff_t*)
  153. {
  154.     return -1;
  155. }
  156. static void s_TIFFUnmapFileHandler(thandle_t, tdata_t, toff_t)
  157. {
  158. }
  159. //
  160. // ReadImage()
  161. // read an image in TIFF format.  This uses a fairly inefficient read, in that
  162. // the data, once read, must be copied into the actual image.  This is largely
  163. // the result of a reliance on a particular function (TIFFReadRGBAImage()); the
  164. // implementation details may change at a future date to use a more efficient
  165. // read mechanism
  166. //
  167. CImage* CImageIOTiff::ReadImage(CNcbiIstream& istr)
  168. {
  169.     TIFF*            tiff             = NULL;
  170.     uint32*          raster           = NULL;
  171.     TIFFErrorHandler old_err_handler  = NULL;
  172.     TIFFErrorHandler old_warn_handler = NULL;
  173.     CRef<CImage> image;
  174.     try {
  175.         old_err_handler  = TIFFSetErrorHandler(&s_TiffReadErrorHandler);
  176.         old_warn_handler = TIFFSetWarningHandler(&s_TiffWarningHandler);
  177.         // open our file
  178.         tiff = TIFFClientOpen("", "rm",
  179.                               reinterpret_cast<thandle_t>(&istr),
  180.                               s_TIFFReadHandler,
  181.                               s_TIFFDummyIOHandler,
  182.                               s_TIFFSeekHandler,
  183.                               s_TIFFCloseHandler,
  184.                               s_TIFFSizeHandler,
  185.                               s_TIFFMapFileHandler,
  186.                               s_TIFFUnmapFileHandler);
  187.         if ( !tiff ) {
  188.             NCBI_THROW(CImageException, eReadError,
  189.                        "CImageIOTiff::ReadImage(): error opening file ");
  190.         }
  191.         // extract the size parameters
  192.         int width  = 0;
  193.         int height = 0;
  194.         int depth  = 0;
  195.         TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH,  &width);
  196.         TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);
  197.         TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &depth);
  198.         if (depth != 1  &&  depth != 3  &&  depth != 4) {
  199.             string msg("CImageIOTiff::ReadImage(): unhandled image depth: ");
  200.             msg += NStr::IntToString(depth);
  201.             NCBI_THROW(CImageException, eReadError, msg);
  202.         }
  203.         // NB: we treat single plane images as RGB
  204.         if (depth == 1) {
  205.             depth = 3;
  206.         }
  207.         // allocate a temporary buffer for the image
  208.         raster = (uint32*)_TIFFmalloc(width * height * sizeof(uint32));
  209.         if ( !TIFFReadRGBAImage(tiff, width, height, raster, 1) ) {
  210.             _TIFFfree(raster);
  211.             NCBI_THROW(CImageException, eReadError,
  212.                        "CImageIOTiff::ReadImage(): error reading file");
  213.         }
  214.         // now we need to copy this data and pack it appropriately
  215.         // according to the TIFFRGBAImage man page, TIFFRGBAImage and
  216.         // TIFFReadRGBAImage create the image in *RASTER* format - i.e.,
  217.         // with (0, 0) being the lower-left corner, not the upper-left
  218.         // corner as everyone else in the world expects
  219.         image = new CImage(width, height, depth);
  220.         unsigned char* data = image->SetData();
  221.         for (size_t j = 0;  j < height;  ++j) {
  222.             // implicit inversion
  223.             size_t from_idx_base = j * width;
  224.             size_t to_idx_base   = (height - j - 1) * width;
  225.             size_t i;
  226.             switch (depth) {
  227.             case 3:
  228.                 for (i = 0;  i < width;  ++i) {
  229.                     size_t from_idx = from_idx_base + i;
  230.                     size_t to_idx   = to_idx_base + i;
  231.                     // TIFFReadRGBAImage() returns data in ABGR image,
  232.                     // packed as a 32-bit value, so we need to pick this
  233.                     // apart here
  234.                     uint32 pixel = raster[from_idx];
  235.                     data[3 * to_idx + 0] = TIFFGetR(pixel);
  236.                     data[3 * to_idx + 1] = TIFFGetG(pixel);
  237.                     data[3 * to_idx + 2] = TIFFGetB(pixel);
  238.                 }
  239.                 break;
  240.             case 4:
  241.                 for (i = 0;  i < width;  ++i) {
  242.                     size_t from_idx = from_idx_base + i;
  243.                     size_t to_idx   = to_idx_base + i;
  244.                     // TIFFReadRGBAImage() returns data in ABGR image,
  245.                     // packed as a 32-bit value, so we need to pick this
  246.                     // apart here
  247.                     uint32 pixel = raster[from_idx];
  248.                     data[4 * to_idx + 0] = TIFFGetR(pixel);
  249.                     data[4 * to_idx + 1] = TIFFGetG(pixel);
  250.                     data[4 * to_idx + 2] = TIFFGetB(pixel);
  251.                     data[4 * to_idx + 3] = TIFFGetA(pixel);
  252.                 }
  253.                 break;
  254.             }
  255.         }
  256.         // clean-up
  257.         _TIFFfree(raster);
  258.         TIFFClose(tiff);
  259.     }
  260.     catch (...) {
  261.         if (raster) {
  262.             _TIFFfree(raster);
  263.             raster = NULL;
  264.         }
  265.         if (tiff) {
  266.             TIFFClose(tiff);
  267.             tiff = NULL;
  268.         }
  269.         TIFFSetErrorHandler(old_err_handler);
  270.         TIFFSetWarningHandler(old_warn_handler);
  271.         // throw to a higher level
  272.         throw;
  273.     }
  274.     TIFFSetErrorHandler(old_err_handler);
  275.     TIFFSetWarningHandler(old_warn_handler);
  276.     return image.Release();
  277. }
  278. //
  279. // ReadImage()
  280. // read a sub-image from a file.  We use a brain-dead implementation that reads
  281. // the whole image in, then subsets it.  This may change in the future.
  282. //
  283. CImage* CImageIOTiff::ReadImage(CNcbiIstream& istr,
  284.                                 size_t x, size_t y, size_t w, size_t h)
  285. {
  286.     CRef<CImage> image(ReadImage(istr));
  287.     return image->GetSubImage(x, y, w, h);
  288. }
  289. //
  290. // WriteImage()
  291. // write an image to a file in TIFF format
  292. //
  293. void CImageIOTiff::WriteImage(const CImage& image, CNcbiOstream& ostr,
  294.                               CImageIO::ECompress)
  295. {
  296.     TIFF* tiff = NULL;
  297.     TIFFErrorHandler old_err_handler = NULL;
  298.     TIFFErrorHandler old_warn_handler = NULL;
  299.     try {
  300.         if ( !image.GetData() ) {
  301.             NCBI_THROW(CImageException, eWriteError,
  302.                        "CImageIOTiff::WriteImage(): cannot write empty image");
  303.         }
  304.         old_err_handler  = TIFFSetErrorHandler(&s_TiffWriteErrorHandler);
  305.         old_warn_handler = TIFFSetWarningHandler(&s_TiffWarningHandler);
  306.         // open our file
  307.         //ostr.open(file.c_str(), ios::out|ios::binary);
  308.         tiff = TIFFClientOpen("", "wm",
  309.                               reinterpret_cast<thandle_t>(&ostr),
  310.                               s_TIFFDummyIOHandler,
  311.                               s_TIFFWriteHandler,
  312.                               s_TIFFSeekHandler,
  313.                               s_TIFFCloseHandler,
  314.                               s_TIFFSizeHandler,
  315.                               s_TIFFMapFileHandler,
  316.                               s_TIFFUnmapFileHandler);
  317.         if ( !tiff ) {
  318.             NCBI_THROW(CImageException, eWriteError,
  319.                        "CImageIOTiff::WriteImage(): cannot write file");
  320.         }
  321.         // set a bunch of standard fields, defining our image dimensions
  322.         TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH,        image.GetWidth());
  323.         TIFFSetField(tiff, TIFFTAG_IMAGELENGTH,       image.GetHeight());
  324.         TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE,     8);
  325.         TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL,   image.GetDepth());
  326.         TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP,      image.GetHeight());
  327.         // TIFF options
  328.         TIFFSetField(tiff, TIFFTAG_COMPRESSION,   COMPRESSION_DEFLATE);
  329.         TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC,   PHOTOMETRIC_RGB);
  330.         TIFFSetField(tiff, TIFFTAG_FILLORDER,     FILLORDER_MSB2LSB);
  331.         TIFFSetField(tiff, TIFFTAG_PLANARCONFIG,  PLANARCONFIG_CONTIG);
  332.         // write our information
  333.         TIFFWriteEncodedStrip(tiff, 0,
  334.                               const_cast<void*>
  335.                               (reinterpret_cast<const void*> (image.GetData())),
  336.                               image.GetWidth() * image.GetHeight() * image.GetDepth());
  337.         TIFFClose(tiff);
  338.         TIFFSetErrorHandler(old_err_handler);
  339.         TIFFSetWarningHandler(old_warn_handler);
  340.     }
  341.     catch (...) {
  342.         // close our file and wipe it from the system
  343.         if (tiff) {
  344.             TIFFClose(tiff);
  345.             tiff = NULL;
  346.         }
  347.         // restore the standard error handlers
  348.         TIFFSetErrorHandler  (old_err_handler);
  349.         TIFFSetWarningHandler(old_warn_handler);
  350.         throw;
  351.     }
  352. }
  353. //
  354. // WriteImage()
  355. // write a sub-image to a file in TIFF format.  This uses a brain-dead
  356. // implementation in that we subset the image first, then write the sub-image
  357. // out.
  358. //
  359. void CImageIOTiff::WriteImage(const CImage& image, CNcbiOstream& ostr,
  360.                               size_t x, size_t y, size_t w, size_t h,
  361.                               CImageIO::ECompress compress)
  362. {
  363.     CRef<CImage> subimage(image.GetSubImage(x, y, w, h));
  364.     WriteImage(*subimage, ostr, compress);
  365. }
  366. END_NCBI_SCOPE
  367. #else // !HAVE_LIBTIFF
  368. //
  369. // LIBTIFF functionality not included - we stub out the various needed
  370. // functions
  371. //
  372. BEGIN_NCBI_SCOPE
  373. CImage* CImageIOTiff::ReadImage(CNcbiIstream&)
  374. {
  375.     NCBI_THROW(CImageException, eUnsupported,
  376.                "CImageIOTiff::ReadImage(): TIFF format not supported");
  377. }
  378. CImage* CImageIOTiff::ReadImage(CNcbiIstream&,
  379.                                 size_t, size_t, size_t, size_t)
  380. {
  381.     NCBI_THROW(CImageException, eUnsupported,
  382.                "CImageIOTiff::ReadImage(): TIFF format not supported");
  383. }
  384. void CImageIOTiff::WriteImage(const CImage&, CNcbiOstream&,
  385.                               CImageIO::ECompress)
  386. {
  387.     NCBI_THROW(CImageException, eUnsupported,
  388.                "CImageIOTiff::WriteImage(): TIFF format not supported");
  389. }
  390. void CImageIOTiff::WriteImage(const CImage&, CNcbiOstream&,
  391.                               size_t, size_t, size_t, size_t,
  392.                               CImageIO::ECompress)
  393. {
  394.     NCBI_THROW(CImageException, eUnsupported,
  395.                "CImageIOTiff::WriteImage(): TIFF format not supported");
  396. }
  397. END_NCBI_SCOPE
  398. #endif  // HAVE_LIBTIFF
  399. /*
  400.  * ===========================================================================
  401.  * $Log: image_io_tiff.cpp,v $
  402.  * Revision 1000.4  2004/06/01 19:41:46  gouriano
  403.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  404.  *
  405.  * Revision 1.9  2004/05/17 21:07:58  gorelenk
  406.  * Added include of PCH ncbi_pch.hpp
  407.  *
  408.  * Revision 1.8  2004/02/19 22:57:57  ucko
  409.  * Accommodate stricter implementations of CT_POS_TYPE.
  410.  *
  411.  * Revision 1.7  2003/12/19 20:58:29  dicuccio
  412.  * Added special case: single-channel TIFF images -> interpret as RGB
  413.  *
  414.  * Revision 1.6  2003/12/18 13:50:15  dicuccio
  415.  * Fixed image reversal bug: TIFFReadRGBAImage() reads the image in raster-order,
  416.  * not image-order.  Fixed setting of correct depth on image read.
  417.  *
  418.  * Revision 1.5  2003/12/16 16:16:55  dicuccio
  419.  * Fixed compiler warnings
  420.  *
  421.  * Revision 1.4  2003/12/16 15:49:37  dicuccio
  422.  * Large re-write of image handling.  Added improved error-handling and support
  423.  * for streams-based i/o (via hooks into each client library).
  424.  *
  425.  * Revision 1.3  2003/12/12 17:49:04  dicuccio
  426.  * Intercept libtiff error messages and translate them into LOG_POST()/exception
  427.  * where appropriate
  428.  *
  429.  * Revision 1.2  2003/11/03 15:19:57  dicuccio
  430.  * Added optional compression parameter
  431.  *
  432.  * Revision 1.1  2003/06/03 15:17:13  dicuccio
  433.  * Initial revision of image library
  434.  *
  435.  * ===========================================================================
  436.  */