home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / imagpng.cpp < prev    next >
C/C++ Source or Header  |  2002-06-04  |  13KB  |  430 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        imagepng.cpp
  3. // Purpose:     wxImage PNG handler
  4. // Author:      Robert Roebling
  5. // RCS-ID:      $Id: imagpng.cpp,v 1.27 2002/05/22 23:14:47 VZ Exp $
  6. // Copyright:   (c) Robert Roebling
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. #ifdef __GNUG__
  11. #pragma implementation "imagpng.h"
  12. #endif
  13.  
  14. // For compilers that support precompilation, includes "wx.h".
  15. #include "wx/wxprec.h"
  16.  
  17. #ifdef __BORLANDC__
  18.   #pragma hdrstop
  19. #endif
  20.  
  21. #ifndef WX_PRECOMP
  22.   #include "wx/defs.h"
  23. #endif
  24.  
  25. #if wxUSE_IMAGE && wxUSE_LIBPNG
  26.  
  27. #include "wx/imagpng.h"
  28. #include "wx/bitmap.h"
  29. #include "wx/debug.h"
  30. #include "wx/log.h"
  31. #include "wx/app.h"
  32. #include "png.h"
  33. #include "wx/filefn.h"
  34. #include "wx/wfstream.h"
  35. #include "wx/intl.h"
  36. #include "wx/module.h"
  37.  
  38. // For memcpy
  39. #include <string.h>
  40.  
  41. #ifdef __SALFORDC__
  42. #ifdef FAR
  43. #undef FAR
  44. #endif
  45. #endif
  46.  
  47. #ifdef __WXMSW__
  48. #include <windows.h>
  49. #endif
  50.  
  51. //-----------------------------------------------------------------------------
  52. // wxPNGHandler
  53. //-----------------------------------------------------------------------------
  54.  
  55. IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
  56.  
  57. #if wxUSE_LIBPNG
  58.  
  59. #ifndef PNGLINKAGEMODE
  60.   #define PNGLINKAGEMODE LINKAGEMODE
  61. #endif
  62.  
  63.  
  64. // VS: wxPNGInfoStruct declared below is a hack that needs some explanation.
  65. //     First, let me describe what's the problem: libpng uses jmp_buf in 
  66. //     its png_struct structure. Unfortunately, this structure is 
  67. //     compiler-specific and may vary in size, so if you use libpng compiled 
  68. //     as DLL with another compiler than the main executable, it may not work
  69. //     (this is for example the case with wxMGL port and SciTech MGL library 
  70. //     that provides custom runtime-loadable libpng implementation with jmpbuf
  71. //     disabled altogether). Luckily, it is still possible to use setjmp() & 
  72. //     longjmp() as long as the structure is not part of png_struct.
  73. //
  74. //     Sadly, there's no clean way to attach user-defined data to png_struct.
  75. //     There is only one customizable place, png_struct.io_ptr, which is meant
  76. //     only for I/O routines and is set with png_set_read_fn or 
  77. //     png_set_write_fn. The hacky part is that we use io_ptr to store
  78. //     a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf.
  79.  
  80. struct wxPNGInfoStruct
  81. {
  82.     jmp_buf jmpbuf;
  83.     bool verbose;
  84.     
  85.     union
  86.     {
  87.         wxInputStream  *in;
  88.         wxOutputStream *out;
  89.     } stream;
  90. };
  91.  
  92. #define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr))
  93.  
  94.  
  95. extern "C"
  96. {
  97.  
  98. void PNGLINKAGEMODE _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
  99. {
  100.     WX_PNG_INFO(png_ptr)->stream.in->Read(data, length);
  101. }
  102.  
  103. void PNGLINKAGEMODE _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
  104. {
  105.     WX_PNG_INFO(png_ptr)->stream.out->Write(data, length);
  106. }
  107.  
  108. // from pngerror.c
  109. // so that the libpng doesn't send anything on stderr
  110. void
  111. PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message)
  112. {
  113.     wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
  114.     if ( info->verbose )
  115.         wxLogError(wxString(message));
  116.  
  117. #ifdef USE_FAR_KEYWORD
  118.     {
  119.        jmp_buf jmpbuf;
  120.        png_memcpy(jmpbuf,info->jmpbuf,sizeof(jmp_buf));
  121.        longjmp(jmpbuf, 1);
  122.     }
  123. #else
  124.     longjmp(info->jmpbuf, 1);
  125. #endif
  126. }
  127.  
  128. void
  129. PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message)
  130. {
  131.     wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
  132.     if ( info->verbose )
  133.         wxLogWarning(wxString(message));
  134. }
  135.  
  136. } // extern "C"
  137.  
  138. // temporarily disable the warning C4611 (interaction between '_setjmp' and
  139. // C++ object destruction is non-portable) - I don't see any dtors here
  140. #ifdef __VISUALC__
  141.     #pragma warning(disable:4611)
  142. #endif /* VC++ */
  143.  
  144. bool wxPNGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
  145. {
  146.     // VZ: as this function uses setjmp() the only fool proof error handling
  147.     //     method is to use goto (setjmp is not really C++ dtors friendly...)
  148.  
  149.     unsigned char **lines;
  150.     unsigned int i;
  151.     png_infop info_ptr = (png_infop) NULL;   
  152.     wxPNGInfoStruct wxinfo;
  153.  
  154.     wxinfo.verbose = verbose;
  155.     wxinfo.stream.in = &stream;
  156.  
  157.     image->Destroy();
  158.  
  159.     png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
  160.         (voidp) NULL,
  161.         (png_error_ptr) NULL,
  162.         (png_error_ptr) NULL );
  163.     if (!png_ptr)
  164.         goto error_nolines;
  165.  
  166.     png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
  167.  
  168.     // NB: please see the comment near wxPNGInfoStruct declaration for
  169.     //     explanation why this line is mandatory
  170.     png_set_read_fn( png_ptr, &wxinfo, _PNG_stream_reader);
  171.  
  172.     info_ptr = png_create_info_struct( png_ptr );
  173.     if (!info_ptr)
  174.         goto error_nolines;
  175.  
  176.     if (setjmp(wxinfo.jmpbuf))
  177.         goto error_nolines;
  178.  
  179.     if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  180.         goto error_nolines;
  181.  
  182.     png_uint_32 width,height;
  183.     int bit_depth,color_type,interlace_type;
  184.  
  185.     png_read_info( png_ptr, info_ptr );
  186.     png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
  187.  
  188.     if (color_type == PNG_COLOR_TYPE_PALETTE)
  189.         png_set_expand( png_ptr );
  190.  
  191.     png_set_strip_16( png_ptr );
  192.     png_set_packing( png_ptr );
  193.     if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
  194.         png_set_expand( png_ptr );
  195.     png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
  196.  
  197.     image->Create( (int)width, (int)height );
  198.  
  199.     if (!image->Ok())
  200.         goto error_nolines;
  201.  
  202.     lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) );
  203.     if (lines == NULL)
  204.         goto error_nolines;
  205.  
  206.     for (i = 0; i < height; i++)
  207.     {
  208.         if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL)
  209.         {
  210.             for ( unsigned int n = 0; n < i; n++ )
  211.                 free( lines[n] );
  212.             goto error;
  213.         }
  214.     }
  215.  
  216.     // loaded successfully!
  217.     {
  218.         int transp = 0;
  219.         png_read_image( png_ptr, lines );
  220.         png_read_end( png_ptr, info_ptr );
  221.         png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
  222.         unsigned char *ptr = image->GetData();
  223.         if ((color_type == PNG_COLOR_TYPE_GRAY) ||
  224.             (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
  225.         {
  226.             for (unsigned int y = 0; y < height; y++)
  227.             {
  228.                 unsigned char *ptr2 = lines[y];
  229.                 for (unsigned int x = 0; x < width; x++)
  230.                 {
  231.                     unsigned char r = *ptr2++;
  232.                     unsigned char a = *ptr2++;
  233.                     if (a < 128)
  234.                     {
  235.                         *ptr++ = 255;
  236.                         *ptr++ = 0;
  237.                         *ptr++ = 255;
  238.                         transp = 1;
  239.                     }
  240.                     else
  241.                     {
  242.                         *ptr++ = r;
  243.                         *ptr++ = r;
  244.                         *ptr++ = r;
  245.                     }
  246.                 }
  247.             }
  248.         }
  249.         else
  250.         {
  251.             for (unsigned int y = 0; y < height; y++)
  252.             {
  253.                 unsigned char *ptr2 = lines[y];
  254.                 for (unsigned int x = 0; x < width; x++)
  255.                 {
  256.                     unsigned char r = *ptr2++;
  257.                     unsigned char g = *ptr2++;
  258.                     unsigned char b = *ptr2++;
  259.                     unsigned char a = *ptr2++;
  260.                     if (a < 128)
  261.                     {
  262.                         *ptr++ = 255;
  263.                         *ptr++ = 0;
  264.                         *ptr++ = 255;
  265.                         transp = 1;
  266.                     }
  267.                     else
  268.                     {
  269.                         if ((r == 255) && (g == 0) && (b == 255)) r = 254;
  270.                         *ptr++ = r;
  271.                         *ptr++ = g;
  272.                         *ptr++ = b;
  273.                     }
  274.                 }
  275.             }
  276.         }
  277.  
  278.         for ( unsigned int j = 0; j < height; j++ )
  279.             free( lines[j] );
  280.         free( lines );
  281.  
  282.         if (transp)
  283.         {
  284.             image->SetMaskColour( 255, 0, 255 );
  285.         }
  286.         else
  287.         {
  288.             image->SetMask( FALSE );
  289.         }
  290.     }
  291.  
  292.     return TRUE;
  293.  
  294.  error_nolines:
  295.     lines = NULL; // called from before it was set
  296.  error:
  297.     if (verbose)
  298.        wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory."));
  299.  
  300.     if ( image->Ok() )
  301.     {
  302.         image->Destroy();
  303.     }
  304.  
  305.     if ( lines )
  306.     {
  307.         free( lines );
  308.     }
  309.  
  310.     if ( png_ptr )
  311.     {
  312.         if ( info_ptr )
  313.         {
  314.             png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
  315.             free(info_ptr);
  316.         }
  317.         else
  318.             png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
  319.     }
  320.     return FALSE;
  321. }
  322.  
  323. bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
  324. {
  325.     wxPNGInfoStruct wxinfo;
  326.  
  327.     wxinfo.verbose = verbose;
  328.     wxinfo.stream.out = &stream;
  329.  
  330.     png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  331.     if (!png_ptr)
  332.     {
  333.         if (verbose)
  334.            wxLogError(_("Couldn't save PNG image."));
  335.         return FALSE;
  336.     }
  337.  
  338.     png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
  339.  
  340.     png_infop info_ptr = png_create_info_struct(png_ptr);
  341.     if (info_ptr == NULL)
  342.     {
  343.         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
  344.         if (verbose)
  345.            wxLogError(_("Couldn't save PNG image."));
  346.         return FALSE;
  347.     }
  348.  
  349.     if (setjmp(wxinfo.jmpbuf))
  350.     {
  351.         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
  352.         if (verbose)
  353.            wxLogError(_("Couldn't save PNG image."));
  354.         return FALSE;
  355.     }
  356.  
  357.     // NB: please see the comment near wxPNGInfoStruct declaration for
  358.     //     explanation why this line is mandatory
  359.     png_set_write_fn( png_ptr, &wxinfo, _PNG_stream_writer, NULL);
  360.  
  361.     png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
  362.         PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
  363.         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  364.  
  365.     png_color_8 sig_bit;
  366.     sig_bit.red = 8;
  367.     sig_bit.green = 8;
  368.     sig_bit.blue = 8;
  369.     sig_bit.alpha = 8;
  370.     png_set_sBIT( png_ptr, info_ptr, &sig_bit );
  371.     png_write_info( png_ptr, info_ptr );
  372.     png_set_shift( png_ptr, &sig_bit );
  373.     png_set_packing( png_ptr );
  374.  
  375.     unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
  376.     if (!data)
  377.     {
  378.         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
  379.         return FALSE;
  380.     }
  381.  
  382.     for (int y = 0; y < image->GetHeight(); y++)
  383.     {
  384.         unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
  385.         for (int x = 0; x < image->GetWidth(); x++)
  386.         {
  387.             data[(x << 2) + 0] = *ptr++;
  388.             data[(x << 2) + 1] = *ptr++;
  389.             data[(x << 2) + 2] = *ptr++;
  390.             if (( !image->HasMask() ) || \
  391.                 (data[(x << 2) + 0] != image->GetMaskRed()) || \
  392.                 (data[(x << 2) + 1] != image->GetMaskGreen()) || \
  393.                 (data[(x << 2) + 2] != image->GetMaskBlue()))
  394.             {
  395.                 data[(x << 2) + 3] = 255;
  396.             }
  397.             else
  398.             {
  399.                 data[(x << 2) + 3] = 0;
  400.             }
  401.         }
  402.         png_bytep row_ptr = data;
  403.         png_write_rows( png_ptr, &row_ptr, 1 );
  404.     }
  405.  
  406.     free(data);
  407.     png_write_end( png_ptr, info_ptr );
  408.     png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
  409.  
  410.     return TRUE;
  411. }
  412.  
  413. #ifdef __VISUALC__
  414.     #pragma warning(default:4611)
  415. #endif /* VC++ */
  416.  
  417. bool wxPNGHandler::DoCanRead( wxInputStream& stream )
  418. {
  419.     unsigned char hdr[4];
  420.  
  421.     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
  422.         return FALSE;
  423.  
  424.     return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;
  425. }
  426.  
  427. #endif  // wxUSE_STREAMS
  428.  
  429. #endif  // wxUSE_LIBPNG
  430.