Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
magick/save.hh
1 // Copyright (C) 2009, 2010, 2011 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_IO_MAGICK_SAVE_HH
28 # define MLN_IO_MAGICK_SAVE_HH
29 
38 
39 # include <cstdlib>
40 
41 # include <Magick++.h>
42 
43 # include <mln/metal/equal.hh>
44 
45 # include <mln/core/image/image2d.hh>
46 
47 # include <mln/value/int_u8.hh>
48 # include <mln/value/rgb8.hh>
49 # include <mln/value/qt/rgb32.hh>
50 
51 
52 namespace mln
53 {
54 
55  namespace io
56  {
57 
58  namespace magick
59  {
60 
66  template <typename I>
67  void
68  save(const Image<I>& ima, const std::string& filename);
69 
80  template <typename I, typename J>
81  void
82  save(const Image<I>& ima, const Image<J>& opacity_mask,
83  const std::string& filename);
84 
85 
86  // FIXME: Unfinished?
87 #if 0
88 
92  template <typename T>
93  void
94  save(const Image< tiled2d<T> >& ima, const std::string& filename);
95 #endif
96 
97 
98 # ifndef MLN_INCLUDE_ONLY
99 
100  namespace impl
101  {
102 
103  inline
104  Magick::Color get_color(bool value)
105  {
106  return Magick::ColorMono(value);
107  }
108 
109  inline
110  Magick::Color get_color(const value::int_u8& value)
111  {
112  /* Each channel of a Magick++ image is coded on a
113  Magick::Quantum value, which can be an 8-, 16- or 32-bit
114  integer. Store the data from each mln::value::int_u8
115  values into the most significant bits of Magick::Color's
116  channels. */
117  return Magick::Color
118  (value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8)),
119  value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8)),
120  value << 8 * (sizeof(Magick::Quantum) - sizeof(value::int_u8)));
121  }
122 
123  inline
124  Magick::Color get_color(const value::rgb8& value)
125  {
126  /* Each channel of a Magick++ image is coded on a
127  Magick::Quantum value, which can be an 8-, 16- or 32-bit
128  integer. Store the data from each component of
129  mln::value::rgb8 values (of type mln::value::int_u8) into
130  the most significant bits of Magick::Color's
131  channels. */
132  return Magick::Color
133  (value.red() << 8 * (sizeof(Magick::Quantum)
134  - sizeof(value::rgb8::red_t)),
135  value.green() << 8 * (sizeof(Magick::Quantum)
136  - sizeof(value::rgb8::green_t)),
137  value.blue() << 8 * (sizeof(Magick::Quantum)
138  - sizeof(value::rgb8::blue_t)));
139  }
140 
141  } // end of namespace mln::io::magick::impl
142 
143 
144  namespace internal
145  {
146 
147  template <typename I>
148  void
149  paste_data(const Image<I>& ima_, Magick::Image& magick_ima)
150  {
151  const I& ima = exact(ima_);
152 
153  def::coord
154  minrow = geom::min_row(ima),
155  mincol = geom::min_col(ima),
156  maxrow = geom::max_row(ima),
157  maxcol = geom::max_col(ima),
158  ncols = geom::ncols(ima),
159  nrows = geom::nrows(ima);
160 
161  // Ensure that there is only one reference to underlying image
162  // If this is not done, then image pixels will not be modified.
163  magick_ima.modifyImage();
164 
165  Magick::Pixels view(magick_ima);
166  // As above, `ncols' is passed before `nrows'.
167  Magick::PixelPacket* pixels = view.get(0, 0, ncols, nrows);
168  const mln_value(I) *ptr_ima = &ima(ima.domain().pmin());
169 
170  unsigned row_offset = ima.delta_index(dpoint2d(+1, - ncols));
171 
172  for (def::coord row = minrow; row <= maxrow;
173  ++row, ptr_ima += row_offset)
174  for (def::coord col = mincol; col <= maxcol; ++col)
175  *pixels++ = impl::get_color(*ptr_ima++);
176 
177  view.sync();
178  }
179 
180  template <typename I, typename J>
181  void
182  paste_data_opacity(const Image<I>& ima_,
183  const Image<J>& opacity_mask_,
184  Magick::Image& magick_ima)
185  {
186  const I& ima = exact(ima_);
187  const J& opacity_mask = exact(opacity_mask_);
188 
189  def::coord
190  minrow = geom::min_row(ima),
191  mincol = geom::min_col(ima),
192  maxrow = geom::max_row(ima),
193  maxcol = geom::max_col(ima),
194  ncols = geom::ncols(ima),
195  nrows = geom::nrows(ima);
196 
197  // Ensure that there is only one reference to underlying image
198  // If this is not done, then image pixels will not be modified.
199  magick_ima.modifyImage();
200 
201  Magick::Pixels view(magick_ima);
202  // As above, `ncols' is passed before `nrows'.
203  Magick::PixelPacket* pixels = view.get(0, 0, ncols, nrows);
204  const mln_value(I) *ptr_ima = &ima(ima.domain().pmin());
205  const mln_value(J) *ptr_opacity_mask = &opacity_mask(opacity_mask.domain().pmin());
206 
207  unsigned row_offset = ima.delta_index(dpoint2d(+1, - ncols));
208  unsigned opacity_row_offset = opacity_mask.delta_index(dpoint2d(+1, - ncols));
209 
210  for (def::coord row = minrow; row <= maxrow;
211  ++row, ptr_ima += row_offset,
212  ptr_opacity_mask += opacity_row_offset)
213  for (def::coord col = mincol; col <= maxcol; ++col)
214  {
215  *pixels = impl::get_color(*ptr_ima++);
216  (*pixels).opacity = ((*ptr_opacity_mask++) ? 255 : 0);
217  ++pixels;
218  }
219 
220  view.sync();
221  }
222 
223  } // end of namespace mln::io::magick::internal
224 
225 
226  template <typename I, typename J>
227  void
228  save(const Image<I>& ima_, const Image<J>& opacity_mask_,
229  const std::string& filename)
230  {
231  trace::entering("mln::io::magick::save");
232 
233  mln_precondition(mln_site_(I)::dim == 2);
234  // Turn this into a static check?
235  if (!(mln::metal::equal<mln_value(I), bool>::value ||
236  mln::metal::equal<mln_value(I), value::int_u8>::value ||
237  mln::metal::equal<mln_value(I), value::rgb8>::value ||
238  mln::metal::equal<mln_value(I), value::qt::rgb32>::value))
239  {
240  std::cerr <<
241  "error: trying to save an unsupported format\n"
242  "supported formats are:\n"
243  " binary (bool)\n"
244  " 8-bit grayscale (mln::value::int_u8)\n"
245  " 3x8-bit truecolor (rgb8)" << std::endl;
246  abort();
247  }
248 
249  const I& ima = exact(ima_);
250  const J& opacity_mask = exact(opacity_mask_);
251 
252  def::coord
253  ncols = geom::ncols(ima),
254  nrows = geom::nrows(ima);
255 
256 
257  // In the construction of a Geometry object, the width (i.e.
258  // `ncols') comes first, then the height (i.e. `nrows')
259  // follows.
260  //
261  // FIXME: Default pixel value is set to "white". If the image is
262  // declared with the default constructor, without specifying a
263  // default value, no data seems to be allocated and the Pixel view
264  // declared further fails and segfault...
265  Magick::Image magick_ima(Magick::Geometry(ncols, nrows), "white");
266 
267  if (opacity_mask.is_valid())
268  {
269  magick_ima.type(Magick::TrueColorMatteType);
270  internal::paste_data_opacity(ima, opacity_mask, magick_ima);
271  }
272  else
273  {
274  magick_ima.type(Magick::TrueColorType);
275  internal::paste_data(ima, magick_ima);
276  }
277 
278  magick_ima.write(filename);
279 
280  trace::exiting("mln::io::magick::save");
281  }
282 
283 
284 
285  template <typename I>
286  inline
287  void
288  save(const Image<I>& ima, const std::string& filename)
289  {
290  mln_ch_value(I,bool) opacity_mask;
291  save(ima, opacity_mask, filename);
292  }
293 
294 
295  // FIXME: Unfinished?
296 #if 0
297  template <typename T>
298  void
299  save(const Image< tiled2d<T> >& ima_, const std::string& filename)
300  {
301  trace::entering("mln::io::magick::save");
302 
303  tiled2d<T>& ima = exact(ima_);
304 
305  ima.buffer().write(filename);
306 
307  trace::exiting("mln::io::magick::save");
308  }
309 #endif
310 
311 
312 # endif // ! MLN_INCLUDE_ONLY
313 
314  } // end of namespace mln::io::magick
315 
316  } // end of namespace mln::io
317 
318 } // end of namespace mln
319 
320 
321 #endif // ! MLN_IO_MAGICK_SAVE_HH