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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: image_io_gif.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:41:27  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: image_io_gif.cpp,v 1000.3 2004/06/01 19:41:27 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.  *    CImageIOGif -- interface class for reading/writing CompuServ GIF files
  38.  */
  39. //
  40. // we include gif_lib.h first because of a conflict with windows.h
  41. // (DrawText() is both a giflib function and a Win32 GDI function)
  42. //
  43. #include <ncbi_pch.hpp>
  44. #include <ncbiconf.h>
  45. #ifdef HAVE_LIBGIF
  46. // alas, poor giflib... it isn't extern'ed
  47. extern "C" {
  48. #  include <gif_lib.h>
  49.     /// !@#$%^ libunfig mis-spelled the prototype in their header,
  50.     /// so we must add it here
  51.     GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc);
  52. };
  53. #endif
  54. #include "image_io_gif.hpp"
  55. #include <util/image/image.hpp>
  56. #include <util/image/image_exception.hpp>
  57. #ifdef HAVE_LIBGIF
  58. //
  59. //
  60. // LIBGIF support
  61. //
  62. //
  63. BEGIN_NCBI_SCOPE
  64. static int s_GifRead(GifFileType* file, GifByteType* data, int len)
  65. {
  66.     CNcbiIstream* istr = reinterpret_cast<CNcbiIstream*>(file->UserData);
  67.     if (istr) {
  68.         istr->read(reinterpret_cast<char*>(data), len);
  69.         return istr->gcount();
  70.     }
  71.     return -1;
  72. }
  73. static int s_GifWrite(GifFileType* file, const GifByteType* data, int len)
  74. {
  75.     CNcbiOstream* ostr = reinterpret_cast<CNcbiOstream*>(file->UserData);
  76.     if (ostr) {
  77.         ostr->write(reinterpret_cast<const char*>(data), len);
  78.         if ( *ostr ) {
  79.             return len;
  80.         }
  81.     }
  82.     return -1;
  83. }
  84. //
  85. // ReadImage()
  86. // read an entire GIF image into memory.  This will read only the first image
  87. // in an image set.
  88. //
  89. CImage* CImageIOGif::ReadImage(CNcbiIstream& istr)
  90. {
  91.     GifFileType* fp = NULL;
  92.     CRef<CImage> image;
  93.     try {
  94.         // open our file for reading
  95.         fp = DGifOpen(&istr, s_GifRead);
  96.         if ( !fp ) {
  97.             NCBI_THROW(CImageException, eReadError,
  98.                        "CImageIOGif::ReadImage(): "
  99.                        "cannot open file for reading");
  100.         }
  101.         // allocate an image
  102.         image.Reset(new CImage(fp->SWidth, fp->SHeight, 3));
  103.         memset(image->SetData(), fp->SBackGroundColor,
  104.                image->GetWidth() * image->GetHeight() * image->GetDepth());
  105.         // we also allocate a single row
  106.         // this row is a color indexed row, and will be decoded row-by-row into the
  107.         // image
  108.         vector<unsigned char> row_data(image->GetWidth());
  109.         unsigned char* row_ptr = &row_data[0];
  110.         bool done = false;
  111.         while ( !done ) {
  112.             // determine what sort of record type we have
  113.             // these can be image, extension, or termination
  114.             GifRecordType type;
  115.             if (DGifGetRecordType(fp, &type) == GIF_ERROR) {
  116.                 NCBI_THROW(CImageException, eReadError,
  117.                     "CImageIOGif::ReadImage(): error reading file");
  118.             }
  119.             switch (type) {
  120.             case IMAGE_DESC_RECORD_TYPE:
  121.                 //
  122.                 // we only support the first image in a gif
  123.                 //
  124.                 if (DGifGetImageDesc(fp) == GIF_ERROR) {
  125.                     NCBI_THROW(CImageException, eReadError,
  126.                         "CImageIOGif::ReadImage(): error reading file");
  127.                 }
  128.                 if (fp->Image.Interlace) {
  129.                     // interlaced images are a bit more complex
  130.                     size_t row = fp->Image.Top;
  131.                     size_t col = fp->Image.Left;
  132.                     size_t wid = fp->Image.Width;
  133.                     size_t ht  = fp->Image.Height;
  134.                     static int interlaced_offs[4] = { 0, 4, 2, 1 };
  135.                     static int interlaced_jump[4] = { 8, 8, 4, 2 };
  136.                     for (size_t i = 0;  i < 4;  ++i) {
  137.                         for (size_t j = row + interlaced_offs[i];
  138.                              j < row + ht;  j += interlaced_jump[i]) {
  139.                             x_ReadLine(fp, row_ptr);
  140.                             x_UnpackData(fp, row_ptr,
  141.                                          image->SetData() +
  142.                                          (j * wid + col) * image->GetDepth());
  143.                         }
  144.                     }
  145.                 } else {
  146.                     size_t col = fp->Image.Left;
  147.                     size_t wid = fp->Image.Width;
  148.                     size_t ht  = fp->Image.Height;
  149.                     for (size_t i = 0;  i < ht;  ++i) {
  150.                         x_ReadLine(fp, row_ptr);
  151.                         x_UnpackData(fp, row_ptr,
  152.                                      image->SetData() +
  153.                                      (i * wid + col) * image->GetDepth());
  154.                     }
  155.                 }
  156.                 break;
  157.             case EXTENSION_RECORD_TYPE:
  158.                 {{
  159.                      int ext_code;
  160.                      GifByteType* extension;
  161.                      // we ignore extension blocks
  162.                      if (DGifGetExtension(fp, &ext_code, &extension) == GIF_ERROR) {
  163.                          NCBI_THROW(CImageException, eReadError,
  164.                                     "CImageIOGif::ReadImage(): "
  165.                                     "error reading file");
  166.                      }
  167.                      while (extension != NULL) {
  168.                          if (DGifGetExtensionNext(fp, &extension) == GIF_OK) {
  169.                              continue;
  170.                          }
  171.                          NCBI_THROW(CImageException, eReadError,
  172.                                     "CImageIOGif::ReadImage(): "
  173.                                     "error reading file");
  174.                      }
  175.                  }}
  176.                 break;
  177.             default:
  178.                 // terminate record - break our of our while()
  179.                 done = true;
  180.                 break;
  181.             }
  182.         }
  183.         // close up and exit
  184.         DGifCloseFile(fp);
  185.     }
  186.     catch (...) {
  187.         DGifCloseFile(fp);
  188.         fp = NULL;
  189.         throw;
  190.     }
  191.     return image.Release();
  192. }
  193. //
  194. // ReadImage
  195. // this version returns a sub-image from the desired image.
  196. //
  197. CImage* CImageIOGif::ReadImage(CNcbiIstream& istr,
  198.                                size_t x, size_t y, size_t w, size_t h)
  199. {
  200.     // we use a brain-dead implementation here - this can be done in a more
  201.     // memory-efficient manner...
  202.     CRef<CImage> image(ReadImage(istr));
  203.     return image->GetSubImage(x, y, w, h);
  204. }
  205. //
  206. // WriteImage()
  207. // this writes out a GIF image.
  208. //
  209. void CImageIOGif::WriteImage(const CImage& image, CNcbiOstream& ostr,
  210.                              CImageIO::ECompress)
  211. {
  212.     if ( !image.GetData() ) {
  213.         NCBI_THROW(CImageException, eWriteError,
  214.                    "CImageIOGif::WriteImage(): "
  215.                    "cannot write empty image to file");
  216.     }
  217.     ColorMapObject* cmap = NULL;
  218.     GifFileType* fp = NULL;
  219.     try {
  220.         // first, we need to split our image into red/green/blue channels
  221.         // we do this to get proper GIF quantization
  222.         size_t size = image.GetWidth() * image.GetHeight();
  223.         vector<unsigned char> red  (size);
  224.         vector<unsigned char> green(size);
  225.         vector<unsigned char> blue (size);
  226.         unsigned char* red_ptr   = &red[0];
  227.         unsigned char* green_ptr = &green[0];
  228.         unsigned char* blue_ptr  = &blue[0];
  229.         const unsigned char* from_data = image.GetData();
  230.         const unsigned char* end_data  = image.GetData() + size * image.GetDepth();
  231.         switch (image.GetDepth()) {
  232.         case 3:
  233.             {{
  234.                  for ( ;  from_data != end_data;  ) {
  235.                      *red_ptr++   = *from_data++;
  236.                      *green_ptr++ = *from_data++;
  237.                      *blue_ptr++  = *from_data++;
  238.                  }
  239.              }}
  240.             break;
  241.         case 4:
  242.             {{
  243.                  LOG_POST(Warning <<
  244.                           "CImageIOGif::WriteImage(): "
  245.                           "ignoring alpha channel");
  246.                  for ( ;  from_data != end_data;  ) {
  247.                      *red_ptr++   = *from_data++;
  248.                      *green_ptr++ = *from_data++;
  249.                      *blue_ptr++  = *from_data++;
  250.                      // alpha channel ignored - should we use this to compute a
  251.                      // scaled rgb?
  252.                      ++from_data;
  253.                  }
  254.              }}
  255.             break;
  256.         default:
  257.             NCBI_THROW(CImageException, eWriteError,
  258.                        "CImageIOGif::WriteImage(): unsupported image depth");
  259.         }
  260.         // reset the color channel pointers!
  261.         red_ptr   = &red[0];
  262.         green_ptr = &green[0];
  263.         blue_ptr  = &blue[0];
  264.         // now, create a GIF color map object
  265.         int cmap_size = 256;
  266.         cmap = MakeMapObject(cmap_size, NULL);
  267.         if ( !cmap ) {
  268.             NCBI_THROW(CImageException, eWriteError,
  269.                        "CImageIOGif::WriteImage(): failed to allocate color map");
  270.         }
  271.         // we also allocate a strip of data to hold the indexed colors
  272.         vector<unsigned char> qdata(size);
  273.         unsigned char* qdata_ptr = &qdata[0];
  274.         // quantize our colors
  275.         if (QuantizeBuffer(image.GetWidth(), image.GetHeight(), &cmap_size,
  276.                            red_ptr, green_ptr, blue_ptr,
  277.                            qdata_ptr, cmap->Colors) == GIF_ERROR) {
  278.             free(cmap);
  279.             NCBI_THROW(CImageException, eWriteError,
  280.                        "CImageIOGif::WriteImage(): failed to quantize image");
  281.         }
  282.         //
  283.         // we are now ready to write our file
  284.         //
  285.         // open our file
  286.         fp = EGifOpen(&ostr, s_GifWrite);
  287.         if ( !fp ) {
  288.             NCBI_THROW(CImageException, eWriteError,
  289.                        "CImageIOGif::WriteImage(): failed to open file");
  290.         }
  291.         // write the GIF screen description
  292.         if (EGifPutScreenDesc(fp, image.GetWidth(), image.GetHeight(),
  293.                               8, 0, cmap) == GIF_ERROR) {
  294.             NCBI_THROW(CImageException, eWriteError,
  295.                 "CImageIOGif::WriteImage(): failed to write GIF screen "
  296.                 "description");
  297.         }
  298.         // write the GIF image description
  299.         if (EGifPutImageDesc(fp, 0, 0, image.GetWidth(), image.GetHeight(),
  300.                              false, NULL) == GIF_ERROR) {
  301.             NCBI_THROW(CImageException, eWriteError,
  302.                        "CImageIOGif::WriteImage(): failed to write GIF image "
  303.                        "description");
  304.         }
  305.         // put our data
  306.         for (size_t i = 0;  i < image.GetHeight();  ++i) {
  307.             if (EGifPutLine(fp, qdata_ptr, image.GetWidth()) == GIF_ERROR) {
  308.                 string msg("CImageIOGif::WriteImage(): error writing line ");
  309.                 msg += NStr::IntToString(i);
  310.                 NCBI_THROW(CImageException, eWriteError, msg);
  311.             }
  312.             qdata_ptr += image.GetWidth();
  313.         }
  314.         // clean-up and close
  315.         if (EGifCloseFile(fp) == GIF_ERROR) {
  316.             fp = NULL;
  317.             NCBI_THROW(CImageException, eWriteError,
  318.                        "CImageIOGif::WriteImage(): error closing file");
  319.         }
  320.         free(cmap);
  321.     }
  322.     catch (...) {
  323.         if (fp) {
  324.             if (EGifCloseFile(fp) == GIF_ERROR) {
  325.                 LOG_POST(Error
  326.                     << "CImageIOGif::WriteImage(): error closing file");
  327.             }
  328.             fp = NULL;
  329.         }
  330.         if (cmap) {
  331.             free(cmap);
  332.             cmap = NULL;
  333.         }
  334.         throw;
  335.     }
  336. }
  337. //
  338. // WriteImage()
  339. // this writes out a sub-image as a GIF file.  We use a brain-dead
  340. // implementation currently - subset the image and write it out, rather than
  341. // simply quantizing just the sub-image's data
  342. //
  343. void CImageIOGif::WriteImage(const CImage& image, CNcbiOstream& ostr,
  344.                              size_t x, size_t y, size_t w, size_t h,
  345.                              CImageIO::ECompress compress)
  346. {
  347.     CRef<CImage> subimage(image.GetSubImage(x, y, w, h));
  348.     WriteImage(*subimage, ostr, compress);
  349. }
  350. //
  351. // x_UnpackData()
  352. // this function de-indexes a GIF image's color table, expanding the values
  353. // into RGB tuples
  354. //
  355. void CImageIOGif::x_UnpackData(GifFileType* fp,
  356.                                const unsigned char* from_data,
  357.                                unsigned char* to_data)
  358. {
  359.     struct ColorMapObject* cmap =
  360.         (fp->Image.ColorMap ? fp->Image.ColorMap : fp->SColorMap);
  361.     for (int i = 0;  i < fp->Image.Width;  ++i) {
  362.         *to_data++ = cmap->Colors[ from_data[i] ].Red;
  363.         *to_data++ = cmap->Colors[ from_data[i] ].Green;
  364.         *to_data++ = cmap->Colors[ from_data[i] ].Blue;
  365.     }
  366. }
  367. //
  368. // x_ReadLine()
  369. // read a single line from a GIF file
  370. //
  371. void CImageIOGif::x_ReadLine(GifFileType* fp, unsigned char* data)
  372. {
  373.     if ( DGifGetLine(fp, data, fp->Image.Width) == GIF_ERROR) {
  374.         DGifCloseFile(fp);
  375.         string msg("CImageIOGif::ReadImage(): error reading file");
  376.         NCBI_THROW(CImageException, eReadError, msg);
  377.     }
  378. }
  379. END_NCBI_SCOPE
  380. #else   // HAVE_LIBGIF
  381. //
  382. // LIBGIF not supported
  383. //
  384. BEGIN_NCBI_SCOPE
  385. CImage* CImageIOGif::ReadImage(CNcbiIstream&)
  386. {
  387.     NCBI_THROW(CImageException, eUnsupported,
  388.                "CImageIOGif::ReadImage(): GIF format read unimplemented");
  389. }
  390. CImage* CImageIOGif::ReadImage(CNcbiIstream&,
  391.                                size_t, size_t, size_t, size_t)
  392. {
  393.     NCBI_THROW(CImageException, eUnsupported,
  394.                "CImageIOGif::ReadImage(): GIF format partial "
  395.                "read unimplemented");
  396. }
  397. void CImageIOGif::WriteImage(const CImage&, CNcbiOstream&,
  398.                              CImageIO::ECompress)
  399. {
  400.     NCBI_THROW(CImageException, eUnsupported,
  401.                "CImageIOGif::WriteImage(): GIF format write unimplemented");
  402. }
  403. void CImageIOGif::WriteImage(const CImage&, CNcbiOstream&,
  404.                              size_t, size_t, size_t, size_t,
  405.                              CImageIO::ECompress)
  406. {
  407.     NCBI_THROW(CImageException, eUnsupported,
  408.                "CImageIOGif::WriteImage(): GIF format partial "
  409.                "write unimplemented");
  410. }
  411. END_NCBI_SCOPE
  412. #endif  // !HAVE_LIBGIF
  413. /*
  414.  * ===========================================================================
  415.  * $Log: image_io_gif.cpp,v $
  416.  * Revision 1000.3  2004/06/01 19:41:27  gouriano
  417.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  418.  *
  419.  * Revision 1.6  2004/05/17 21:07:58  gorelenk
  420.  * Added include of PCH ncbi_pch.hpp
  421.  *
  422.  * Revision 1.5  2003/12/16 15:49:36  dicuccio
  423.  * Large re-write of image handling.  Added improved error-handling and support
  424.  * for streams-based i/o (via hooks into each client library).
  425.  *
  426.  * Revision 1.4  2003/11/03 15:19:57  dicuccio
  427.  * Added optional compression parameter
  428.  *
  429.  * Revision 1.3  2003/07/01 12:08:44  dicuccio
  430.  * Compilation fixes for MSVC
  431.  *
  432.  * Revision 1.2  2003/06/09 19:28:17  dicuccio
  433.  * Fixed compilation error - conversion from const char* to char* required for
  434.  * gif_lib
  435.  *
  436.  * Revision 1.1  2003/06/03 15:17:13  dicuccio
  437.  * Initial revision of image library
  438.  *
  439.  * ===========================================================================
  440.  */