Milena (Olena)
User documentation 2.0a Id
|
00001 // Copyright (C) 2009, 2010, 2011 EPITA Research and Development 00002 // Laboratory (LRDE) 00003 // 00004 // This file is part of Olena. 00005 // 00006 // Olena is free software: you can redistribute it and/or modify it under 00007 // the terms of the GNU General Public License as published by the Free 00008 // Software Foundation, version 2 of the License. 00009 // 00010 // Olena is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Olena. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 // As a special exception, you may use this file as part of a free 00019 // software project without restriction. Specifically, if other files 00020 // instantiate templates or use macros or inline functions from this 00021 // file, or you compile this file and link it with other files to produce 00022 // an executable, this file does not by itself cause the resulting 00023 // executable to be covered by the GNU General Public License. This 00024 // exception does not however invalidate any other reasons why the 00025 // executable file might be covered by the GNU General Public License. 00026 00027 #ifndef MLN_IO_MAGICK_SAVE_HH 00028 # define MLN_IO_MAGICK_SAVE_HH 00029 00038 00039 # include <cstdlib> 00040 00041 # include <Magick++.h> 00042 00043 # include <mln/metal/equal.hh> 00044 00045 # include <mln/core/image/image2d.hh> 00046 00047 # include <mln/value/int_u8.hh> 00048 # include <mln/value/rgb8.hh> 00049 # include <mln/value/qt/rgb32.hh> 00050 00051 00052 namespace mln 00053 { 00054 00055 namespace io 00056 { 00057 00058 namespace magick 00059 { 00060 00066 template <typename I> 00067 void 00068 save(const Image<I>& ima, const std::string& filename); 00069 00080 template <typename I, typename J> 00081 void 00082 save(const Image<I>& ima, const Image<J>& opacity_mask, 00083 const std::string& filename); 00084 00085 00086 // FIXME: Unfinished? 00087 #if 0 00088 00092 template <typename T> 00093 void 00094 save(const Image< tiled2d<T> >& ima, const std::string& filename); 00095 #endif 00096 00097 00098 # ifndef MLN_INCLUDE_ONLY 00099 00100 namespace impl 00101 { 00102 00103 inline 00104 Magick::Color get_color(bool value) 00105 { 00106 return Magick::ColorMono(value); 00107 } 00108 00109 inline 00110 Magick::Color get_color(const value::int_u8& value) 00111 { 00112 /* Each channel of a Magick++ image is coded on a 00113 Magick::Quantum value, which can be an 8-, 16- or 32-bit 00114 integer. Store the data from each mln::value::int_u8 00115 values into the most significant bits of Magick::Color's 00116 channels. */ 00117 return Magick::Color 00118 (value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8)), 00119 value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8)), 00120 value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8))); 00121 } 00122 00123 inline 00124 Magick::Color get_color(const value::rgb8& value) 00125 { 00126 /* Each channel of a Magick++ image is coded on a 00127 Magick::Quantum value, which can be an 8-, 16- or 32-bit 00128 integer. Store the data from each component of 00129 mln::value::rgb8 values (of type mln::value::int_u8) into 00130 the most significant bits of Magick::Color's 00131 channels. */ 00132 return Magick::Color 00133 (value.red() << 8 * (sizeof(Magick::Quantum) 00134 - sizeof(value::rgb8::red_t)), 00135 value.green() << 8 * (sizeof(Magick::Quantum) 00136 - sizeof(value::rgb8::green_t)), 00137 value.blue() << 8 * (sizeof(Magick::Quantum) 00138 - sizeof(value::rgb8::blue_t))); 00139 } 00140 00141 } // end of namespace mln::io::magick::impl 00142 00143 00144 namespace internal 00145 { 00146 00147 template <typename I> 00148 void 00149 paste_data(const Image<I>& ima_, Magick::Image& magick_ima) 00150 { 00151 const I& ima = exact(ima_); 00152 00153 def::coord 00154 minrow = geom::min_row(ima), 00155 mincol = geom::min_col(ima), 00156 maxrow = geom::max_row(ima), 00157 maxcol = geom::max_col(ima), 00158 ncols = geom::ncols(ima), 00159 nrows = geom::nrows(ima); 00160 00161 // Ensure that there is only one reference to underlying image 00162 // If this is not done, then image pixels will not be modified. 00163 magick_ima.modifyImage(); 00164 00165 Magick::Pixels view(magick_ima); 00166 // As above, `ncols' is passed before `nrows'. 00167 Magick::PixelPacket* pixels = view.get(0, 0, ncols, nrows); 00168 const mln_value(I) *ptr_ima = &ima(ima.domain().pmin()); 00169 00170 unsigned row_offset = ima.delta_index(dpoint2d(+1, - ncols)); 00171 00172 for (def::coord row = minrow; row <= maxrow; 00173 ++row, ptr_ima += row_offset) 00174 for (def::coord col = mincol; col <= maxcol; ++col) 00175 *pixels++ = impl::get_color(*ptr_ima++); 00176 00177 view.sync(); 00178 } 00179 00180 template <typename I, typename J> 00181 void 00182 paste_data_opacity(const Image<I>& ima_, 00183 const Image<J>& opacity_mask_, 00184 Magick::Image& magick_ima) 00185 { 00186 const I& ima = exact(ima_); 00187 const J& opacity_mask = exact(opacity_mask_); 00188 00189 def::coord 00190 minrow = geom::min_row(ima), 00191 mincol = geom::min_col(ima), 00192 maxrow = geom::max_row(ima), 00193 maxcol = geom::max_col(ima), 00194 ncols = geom::ncols(ima), 00195 nrows = geom::nrows(ima); 00196 00197 // Ensure that there is only one reference to underlying image 00198 // If this is not done, then image pixels will not be modified. 00199 magick_ima.modifyImage(); 00200 00201 Magick::Pixels view(magick_ima); 00202 // As above, `ncols' is passed before `nrows'. 00203 Magick::PixelPacket* pixels = view.get(0, 0, ncols, nrows); 00204 const mln_value(I) *ptr_ima = &ima(ima.domain().pmin()); 00205 const mln_value(J) *ptr_opacity_mask = &opacity_mask(opacity_mask.domain().pmin()); 00206 00207 unsigned row_offset = ima.delta_index(dpoint2d(+1, - ncols)); 00208 unsigned opacity_row_offset = opacity_mask.delta_index(dpoint2d(+1, - ncols)); 00209 00210 for (def::coord row = minrow; row <= maxrow; 00211 ++row, ptr_ima += row_offset, 00212 ptr_opacity_mask += opacity_row_offset) 00213 for (def::coord col = mincol; col <= maxcol; ++col) 00214 { 00215 *pixels = impl::get_color(*ptr_ima++); 00216 (*pixels).opacity = ((*ptr_opacity_mask++) ? 255 : 0); 00217 ++pixels; 00218 } 00219 00220 view.sync(); 00221 } 00222 00223 } // end of namespace mln::io::magick::internal 00224 00225 00226 template <typename I, typename J> 00227 void 00228 save(const Image<I>& ima_, const Image<J>& opacity_mask_, 00229 const std::string& filename) 00230 { 00231 trace::entering("mln::io::magick::save"); 00232 00233 mln_precondition(mln_site_(I)::dim == 2); 00234 // Turn this into a static check? 00235 if (!(mln::metal::equal<mln_value(I), bool>::value || 00236 mln::metal::equal<mln_value(I), value::int_u8>::value || 00237 mln::metal::equal<mln_value(I), value::rgb8>::value || 00238 mln::metal::equal<mln_value(I), value::qt::rgb32>::value)) 00239 { 00240 std::cerr << 00241 "error: trying to save an unsupported format\n" 00242 "supported formats are:\n" 00243 " binary (bool)\n" 00244 " 8-bit grayscale (mln::value::int_u8)\n" 00245 " 3x8-bit truecolor (rgb8)" << std::endl; 00246 abort(); 00247 } 00248 00249 const I& ima = exact(ima_); 00250 const J& opacity_mask = exact(opacity_mask_); 00251 00252 def::coord 00253 ncols = geom::ncols(ima), 00254 nrows = geom::nrows(ima); 00255 00256 00257 // In the construction of a Geometry object, the width (i.e. 00258 // `ncols') comes first, then the height (i.e. `nrows') 00259 // follows. 00260 // 00261 // FIXME: Default pixel value is set to "white". If the image is 00262 // declared with the default constructor, without specifying a 00263 // default value, no data seems to be allocated and the Pixel view 00264 // declared further fails and segfault... 00265 Magick::Image magick_ima(Magick::Geometry(ncols, nrows), "white"); 00266 00267 if (opacity_mask.is_valid()) 00268 { 00269 magick_ima.type(Magick::TrueColorMatteType); 00270 internal::paste_data_opacity(ima, opacity_mask, magick_ima); 00271 } 00272 else 00273 { 00274 magick_ima.type(Magick::TrueColorType); 00275 internal::paste_data(ima, magick_ima); 00276 } 00277 00278 magick_ima.write(filename); 00279 00280 trace::exiting("mln::io::magick::save"); 00281 } 00282 00283 00284 00285 template <typename I> 00286 inline 00287 void 00288 save(const Image<I>& ima, const std::string& filename) 00289 { 00290 mln_ch_value(I,bool) opacity_mask; 00291 save(ima, opacity_mask, filename); 00292 } 00293 00294 00295 // FIXME: Unfinished? 00296 #if 0 00297 template <typename T> 00298 void 00299 save(const Image< tiled2d<T> >& ima_, const std::string& filename) 00300 { 00301 trace::entering("mln::io::magick::save"); 00302 00303 tiled2d<T>& ima = exact(ima_); 00304 00305 ima.buffer().write(filename); 00306 00307 trace::exiting("mln::io::magick::save"); 00308 } 00309 #endif 00310 00311 00312 # endif // ! MLN_INCLUDE_ONLY 00313 00314 } // end of namespace mln::io::magick 00315 00316 } // end of namespace mln::io 00317 00318 } // end of namespace mln 00319 00320 00321 #endif // ! MLN_IO_MAGICK_SAVE_HH