png++  0.2.9
convert_color_space.hpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007,2008   Alex Shulgin
00003  *
00004  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free
00005  * software; the exact copying conditions are as follows:
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright notice,
00011  * this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  * notice, this list of conditions and the following disclaimer in the
00015  * documentation and/or other materials provided with the distribution.
00016  *
00017  * 3. The name of the author may not be used to endorse or promote products
00018  * derived from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00021  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00022  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00023  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00024  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00025  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00026  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00027  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00028  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  */
00031 #ifndef PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED
00032 #define PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED
00033 
00034 #include "error.hpp"
00035 #include "rgb_pixel.hpp"
00036 #include "rgba_pixel.hpp"
00037 #include "gray_pixel.hpp"
00038 #include "ga_pixel.hpp"
00039 #include "index_pixel.hpp"
00040 #include "reader.hpp"
00041 #include "writer.hpp"
00042 
00043 namespace png
00044 {
00045 
00046     namespace detail
00047     {
00048 
00053         template< typename pixel >
00054         struct convert_color_space_impl
00055         {
00056             typedef pixel_traits< pixel > traits;
00057             typedef typename traits::component_type component_type;
00058             typedef basic_alpha_pixel_traits< component_type > alpha_traits;
00059 
00060             template< class reader >
00061             void operator()(reader& io) const
00062             {
00063                 handle_16(io);
00064                 handle_alpha(io, alpha_traits::get_alpha_filler());
00065                 handle_palette(io);
00066                 handle_rgb(io);
00067                 handle_gray(io);
00068 
00069                 io.set_color_type(traits::get_color_type());
00070                 io.set_bit_depth(traits::get_bit_depth());
00071             }
00072 
00073         protected:
00074             static void expand_8_to_16(png_struct*, png_row_info* row_info,
00075                                        byte* row)
00076             {
00077 #ifdef DEBUG_EXPAND_8_16
00078                 printf("row: width=%d, bytes=%d, channels=%d\n",
00079                        row_info->width, row_info->rowbytes, row_info->channels);
00080                 printf("<= ");
00081                 dump_row(row, row_info->rowbytes);
00082 #endif
00083                 for (uint_32 i = row_info->rowbytes; i-- > 0; )
00084                 {
00085                     row[2*i + 1] = row[i];
00086                     row[2*i + 0] = 0;
00087                 }
00088 #ifdef DEBUG_EXPAND_8_16
00089                 printf("=> ");
00090                 dump_row(row, 2*row_info->rowbytes);
00091 #endif
00092             }
00093 
00094 #ifdef DEBUG_EXPAND_8_16
00095             static void dump_row(byte const* row, uint_32 width)
00096             {
00097                 printf("{");
00098                 for (uint_32 i = 0; i < width; ++i)
00099                 {
00100                     printf(" %02x,", row[i]);
00101                 }
00102                 printf(" }\n");
00103             }
00104 #endif
00105 
00106             template< class reader >
00107             static void handle_16(reader& io)
00108             {
00109                 if (io.get_bit_depth() == 16 && traits::get_bit_depth() == 8)
00110                 {
00111 #ifdef PNG_READ_16_TO_8_SUPPORTED
00112                     io.set_strip_16();
00113 #else
00114                     throw error("expected 8-bit data but found 16-bit; recompile with PNG_READ_16_TO_8_SUPPORTED");
00115 #endif
00116                 }
00117                 if (io.get_bit_depth() != 16 && traits::get_bit_depth() == 16)
00118                 {
00119 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
00120                     io.set_read_user_transform(expand_8_to_16);
00121                     io.set_user_transform_info(NULL, 16,
00122                                                traits::get_channels());
00123 #else
00124                     throw error("expected 16-bit data but found 8-bit; recompile with PNG_READ_USER_TRANSFORM_SUPPORTED");
00125 #endif
00126                 }
00127             }
00128 
00129             template< class reader >
00130             static void handle_alpha(reader& io, uint_32 filler)
00131             {
00132                 bool src_alpha = (io.get_color_type() & color_mask_alpha);
00133                 bool src_tRNS = io.has_chunk(chunk_tRNS);
00134                 bool dst_alpha = traits::get_color_type() & color_mask_alpha;
00135                 if ((src_alpha || src_tRNS) && !dst_alpha)
00136                 {
00137 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
00138                     io.set_strip_alpha();
00139 #else
00140                     throw error("alpha channel unexpected; recompile with PNG_READ_STRIP_ALPHA_SUPPORTED");
00141 #endif
00142                 }
00143                 if (!src_alpha && dst_alpha)
00144                 {
00145 #if defined(PNG_tRNS_SUPPORTED) && defined(PNG_READ_EXPAND_SUPPORTED)
00146                     if (src_tRNS)
00147                     {
00148                         io.set_tRNS_to_alpha();
00149                         return;
00150                     }
00151 #endif
00152 #if defined(PNG_READ_FILLER_SUPPORTED) && !defined(PNG_1_0_X)
00153                     io.set_add_alpha(filler, filler_after);
00154 #else
00155                     throw error("expected alpha channel but none found; recompile with PNG_READ_FILLER_SUPPORTED and be sure to use libpng > 1.0.x");
00156 #endif
00157                 }
00158             }
00159 
00160             template< class reader >
00161             static void handle_palette(reader& io)
00162             {
00163                 bool src_palette =
00164                     io.get_color_type() == color_type_palette;
00165                 bool dst_palette =
00166                     traits::get_color_type() == color_type_palette;
00167                 if (src_palette && !dst_palette)
00168                 {
00169 #ifdef PNG_READ_EXPAND_SUPPORTED
00170                     io.set_palette_to_rgb();
00171                     io.get_info().drop_palette();
00172 #else
00173                     throw error("indexed colors unexpected; recompile with PNG_READ_EXPAND_SUPPORTED");
00174 #endif
00175                 }
00176                 else if (!src_palette && dst_palette)
00177                 {
00178                     throw error("conversion to indexed colors is unsupported (yet)");
00179                 }
00180                 else if (src_palette && dst_palette
00181                          && io.get_bit_depth() != traits::get_bit_depth())
00182                 {
00183                     if (traits::get_bit_depth() == 8)
00184                     {
00185 #ifdef PNG_READ_PACK_SUPPORTED
00186                         io.set_packing();
00187 #endif
00188                     }
00189                     else
00190                     {
00191                         throw error("cannot convert to indexed colors with bit-depth < 8");
00192                     }
00193                 }
00194             }
00195 
00196             template< class reader >
00197             static void handle_rgb(reader& io)
00198             {
00199                 bool src_rgb =
00200                     io.get_color_type() & (color_mask_rgb | color_mask_palette);
00201                 bool dst_rgb = traits::get_color_type() & color_mask_rgb;
00202                 if (src_rgb && !dst_rgb)
00203                 {
00204 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
00205                     io.set_rgb_to_gray(/*rgb_to_gray_error*/);
00206 #else
00207                     throw error("grayscale data expected; recompile with PNG_READ_RGB_TO_GRAY_SUPPORTED");
00208 #endif
00209                 }
00210                 if (!src_rgb && dst_rgb)
00211                 {
00212 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
00213                     io.set_gray_to_rgb();
00214 #else
00215                     throw error("expected RGB data; recompile with PNG_READ_GRAY_TO_RGB_SUPPORTED");
00216 #endif
00217                 }
00218             }
00219 
00220             template< class reader >
00221             static void handle_gray(reader& io)
00222             {
00223                 if ((io.get_color_type() & ~color_mask_alpha)
00224                     == color_type_gray)
00225                 {
00226                     if (io.get_bit_depth() < 8 && traits::get_bit_depth() >= 8)
00227                     {
00228 #ifdef PNG_READ_EXPAND_SUPPORTED
00229                         io.set_gray_1_2_4_to_8();
00230 #else
00231                         throw error("convert_color_space: expected 8-bit data; recompile with PNG_READ_EXPAND_SUPPORTED");
00232 #endif
00233                     }
00234                 }
00235             }
00236         };
00237 
00238     } // namespace detal
00239 
00255     template< typename pixel >
00256     struct convert_color_space
00257     {
00258     };
00259 
00264     template<>
00265     struct convert_color_space< rgb_pixel >
00266         : detail::convert_color_space_impl< rgb_pixel >
00267     {
00268     };
00269 
00274     template<>
00275     struct convert_color_space< rgb_pixel_16 >
00276         : detail::convert_color_space_impl< rgb_pixel_16 >
00277     {
00278     };
00279 
00284     template<>
00285     struct convert_color_space< rgba_pixel >
00286         : detail::convert_color_space_impl< rgba_pixel >
00287     {
00288     };
00289 
00294     template<>
00295     struct convert_color_space< rgba_pixel_16 >
00296         : detail::convert_color_space_impl< rgba_pixel_16 >
00297     {
00298     };
00299 
00304     template<>
00305     struct convert_color_space< gray_pixel >
00306         : detail::convert_color_space_impl< gray_pixel >
00307     {
00308     };
00309 
00314     template<>
00315     struct convert_color_space< gray_pixel_16 >
00316         : detail::convert_color_space_impl< gray_pixel_16 >
00317     {
00318     };
00319 
00324     template<>
00325     struct convert_color_space< ga_pixel >
00326         : detail::convert_color_space_impl< ga_pixel >
00327     {
00328     };
00329 
00334     template<>
00335     struct convert_color_space< ga_pixel_16 >
00336         : detail::convert_color_space_impl< ga_pixel_16 >
00337     {
00338     };
00339 
00344     template<>
00345     struct convert_color_space< index_pixel >
00346         : detail::convert_color_space_impl< index_pixel >
00347     {
00348     };
00349 
00350 } // namespace png
00351 
00352 #endif // PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED