1 /* 2 * Copyright (C) 2007,2008 Alex Shulgin 3 * 4 * This file is part of png++ the C++ wrapper for libpng. PNG++ is free 5 * software; the exact copying conditions are as follows: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 23 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #ifndef PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED 32 #define PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED 33 34 #include "error.hpp" 35 #include "rgb_pixel.hpp" 36 #include "rgba_pixel.hpp" 37 #include "gray_pixel.hpp" 38 #include "ga_pixel.hpp" 39 #include "index_pixel.hpp" 40 #include "reader.hpp" 41 #include "writer.hpp" 42 43 namespace png 44 { 45 46 namespace detail 47 { 48 49 /** 50 * \brief IO transformation class template. Converts %image %color 51 * space. 52 */ 53 template< typename pixel > 54 struct convert_color_space_impl 55 { 56 typedef pixel_traits< pixel > traits; 57 typedef typename traits::component_type component_type; 58 typedef basic_alpha_pixel_traits< component_type > alpha_traits; 59 60 template< class reader > operator ()png::detail::convert_color_space_impl61 void operator()(reader& io) const 62 { 63 handle_16(io); 64 handle_alpha(io, alpha_traits::get_alpha_filler()); 65 handle_palette(io); 66 handle_rgb(io); 67 handle_gray(io); 68 69 io.set_color_type(traits::get_color_type()); 70 io.set_bit_depth(traits::get_bit_depth()); 71 } 72 73 protected: expand_8_to_16png::detail::convert_color_space_impl74 static void expand_8_to_16(png_struct*, png_row_info* row_info, 75 byte* row) 76 { 77 #ifdef DEBUG_EXPAND_8_16 78 printf("row: width=%d, bytes=%d, channels=%d\n", 79 row_info->width, row_info->rowbytes, row_info->channels); 80 printf("<= "); 81 dump_row(row, row_info->rowbytes); 82 #endif 83 for (uint_32 i = row_info->rowbytes; i-- > 0; ) 84 { 85 row[2*i + 1] = row[i]; 86 row[2*i + 0] = 0; 87 } 88 #ifdef DEBUG_EXPAND_8_16 89 printf("=> "); 90 dump_row(row, 2*row_info->rowbytes); 91 #endif 92 } 93 94 #ifdef DEBUG_EXPAND_8_16 dump_rowpng::detail::convert_color_space_impl95 static void dump_row(byte const* row, uint_32 width) 96 { 97 printf("{"); 98 for (uint_32 i = 0; i < width; ++i) 99 { 100 printf(" %02x,", row[i]); 101 } 102 printf(" }\n"); 103 } 104 #endif 105 106 template< class reader > handle_16png::detail::convert_color_space_impl107 static void handle_16(reader& io) 108 { 109 if (io.get_bit_depth() == 16 && traits::get_bit_depth() == 8) 110 { 111 #ifdef PNG_READ_16_TO_8_SUPPORTED 112 io.set_strip_16(); 113 #else 114 throw error("expected 8-bit data but found 16-bit; recompile with PNG_READ_16_TO_8_SUPPORTED"); 115 #endif 116 } 117 if (io.get_bit_depth() != 16 && traits::get_bit_depth() == 16) 118 { 119 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 120 io.set_read_user_transform(expand_8_to_16); 121 io.set_user_transform_info(NULL, 16, 122 traits::get_channels()); 123 #else 124 throw error("expected 16-bit data but found 8-bit; recompile with PNG_READ_USER_TRANSFORM_SUPPORTED"); 125 #endif 126 } 127 } 128 129 template< class reader > handle_alphapng::detail::convert_color_space_impl130 static void handle_alpha(reader& io, uint_32 filler) 131 { 132 bool src_alpha = (io.get_color_type() & color_mask_alpha); 133 bool src_tRNS = io.has_chunk(chunk_tRNS); 134 bool dst_alpha = traits::get_color_type() & color_mask_alpha; 135 if ((src_alpha || src_tRNS) && !dst_alpha) 136 { 137 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED 138 io.set_strip_alpha(); 139 #else 140 throw error("alpha channel unexpected; recompile with PNG_READ_STRIP_ALPHA_SUPPORTED"); 141 #endif 142 } 143 if (!src_alpha && dst_alpha) 144 { 145 #if defined(PNG_tRNS_SUPPORTED) && defined(PNG_READ_EXPAND_SUPPORTED) 146 if (src_tRNS) 147 { 148 io.set_tRNS_to_alpha(); 149 return; 150 } 151 #endif 152 #if defined(PNG_READ_FILLER_SUPPORTED) && !defined(PNG_1_0_X) 153 io.set_add_alpha(filler, filler_after); 154 #else 155 throw error("expected alpha channel but none found; recompile with PNG_READ_FILLER_SUPPORTED and be sure to use libpng > 1.0.x"); 156 #endif 157 } 158 } 159 160 template< class reader > handle_palettepng::detail::convert_color_space_impl161 static void handle_palette(reader& io) 162 { 163 bool src_palette = 164 io.get_color_type() == color_type_palette; 165 bool dst_palette = 166 traits::get_color_type() == color_type_palette; 167 if (src_palette && !dst_palette) 168 { 169 #ifdef PNG_READ_EXPAND_SUPPORTED 170 io.set_palette_to_rgb(); 171 io.get_info().drop_palette(); 172 #else 173 throw error("indexed colors unexpected; recompile with PNG_READ_EXPAND_SUPPORTED"); 174 #endif 175 } 176 else if (!src_palette && dst_palette) 177 { 178 throw error("conversion to indexed colors is unsupported (yet)"); 179 } 180 else if (src_palette && dst_palette 181 && io.get_bit_depth() != traits::get_bit_depth()) 182 { 183 if (traits::get_bit_depth() == 8) 184 { 185 #ifdef PNG_READ_PACK_SUPPORTED 186 io.set_packing(); 187 #endif 188 } 189 else 190 { 191 throw error("cannot convert to indexed colors with bit-depth < 8"); 192 } 193 } 194 } 195 196 template< class reader > handle_rgbpng::detail::convert_color_space_impl197 static void handle_rgb(reader& io) 198 { 199 bool src_rgb = 200 io.get_color_type() & (color_mask_rgb | color_mask_palette); 201 bool dst_rgb = traits::get_color_type() & color_mask_rgb; 202 if (src_rgb && !dst_rgb) 203 { 204 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 205 io.set_rgb_to_gray(/*rgb_to_gray_error*/); 206 #else 207 throw error("grayscale data expected; recompile with PNG_READ_RGB_TO_GRAY_SUPPORTED"); 208 #endif 209 } 210 if (!src_rgb && dst_rgb) 211 { 212 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED 213 io.set_gray_to_rgb(); 214 #else 215 throw error("expected RGB data; recompile with PNG_READ_GRAY_TO_RGB_SUPPORTED"); 216 #endif 217 } 218 } 219 220 template< class reader > handle_graypng::detail::convert_color_space_impl221 static void handle_gray(reader& io) 222 { 223 if ((io.get_color_type() & ~color_mask_alpha) 224 == color_type_gray) 225 { 226 if (io.get_bit_depth() < 8 && traits::get_bit_depth() >= 8) 227 { 228 #ifdef PNG_READ_EXPAND_SUPPORTED 229 io.set_gray_1_2_4_to_8(); 230 #else 231 throw error("convert_color_space: expected 8-bit data; recompile with PNG_READ_EXPAND_SUPPORTED"); 232 #endif 233 } 234 } 235 } 236 }; 237 238 } // namespace detal 239 240 /** 241 * \brief IO transformation class template. Converts %image %color 242 * space. 243 * 244 * This IO transformation class template is used to convert %color 245 * space of the source %image to the %color space of the target 246 * %image. An error with human-readable description is thrown 247 * when the %color space could not be converted. Often, this 248 * means that you have to recompile libpng with some more 249 * conversion options turned on. 250 * 251 * Not implemented--see specializations. 252 * 253 * \see image, image::read 254 */ 255 template< typename pixel > 256 struct convert_color_space 257 { 258 }; 259 260 /** 261 * \brief Converts %image %color space. A specialization for 262 * rgb_pixel type. 263 */ 264 template<> 265 struct convert_color_space< rgb_pixel > 266 : detail::convert_color_space_impl< rgb_pixel > 267 { 268 }; 269 270 /** 271 * \brief Converts %image %color space. A specialization for 272 * rgb_pixel_16 type. 273 */ 274 template<> 275 struct convert_color_space< rgb_pixel_16 > 276 : detail::convert_color_space_impl< rgb_pixel_16 > 277 { 278 }; 279 280 /** 281 * \brief Converts %image %color space. A specialization for 282 * rgba_pixel type. 283 */ 284 template<> 285 struct convert_color_space< rgba_pixel > 286 : detail::convert_color_space_impl< rgba_pixel > 287 { 288 }; 289 290 /** 291 * \brief Converts %image %color space. A specialization for 292 * rgba_pixel_16 type. 293 */ 294 template<> 295 struct convert_color_space< rgba_pixel_16 > 296 : detail::convert_color_space_impl< rgba_pixel_16 > 297 { 298 }; 299 300 /** 301 * \brief Converts %image %color space. A specialization for 302 * gray_pixel type. 303 */ 304 template<> 305 struct convert_color_space< gray_pixel > 306 : detail::convert_color_space_impl< gray_pixel > 307 { 308 }; 309 310 /** 311 * \brief Converts %image %color space. A specialization for 312 * gray_pixel_16 type. 313 */ 314 template<> 315 struct convert_color_space< gray_pixel_16 > 316 : detail::convert_color_space_impl< gray_pixel_16 > 317 { 318 }; 319 320 /** 321 * \brief Converts %image %color space. A specialization for 322 * ga_pixel type. 323 */ 324 template<> 325 struct convert_color_space< ga_pixel > 326 : detail::convert_color_space_impl< ga_pixel > 327 { 328 }; 329 330 /** 331 * \brief Converts %image %color space. A specialization for 332 * ga_pixel_16 type. 333 */ 334 template<> 335 struct convert_color_space< ga_pixel_16 > 336 : detail::convert_color_space_impl< ga_pixel_16 > 337 { 338 }; 339 340 /** 341 * \brief Converts %image %color space. A specialization for 342 * index_pixel type. 343 */ 344 template<> 345 struct convert_color_space< index_pixel > 346 : detail::convert_color_space_impl< index_pixel > 347 { 348 }; 349 350 } // namespace png 351 352 #endif // PNGPP_CONVERT_COLOR_SPACE_HPP_INCLUDED 353