png++
0.2.9
|
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