Loading...
Searching...
No Matches
MagickDrain.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31
32#ifndef MAGICKDRAIN_H_
33#define MAGICKDRAIN_H_
34
35
36
37
38
39#ifdef DRAIN_MAGICK_yes
40#include <Magick++.h>
41#endif
42
43// In compilation, use "Magick*-config" to get libs and includes right.
44
45
46#include "Image.h"
47
48
49namespace drain
50{
51
52namespace image
53{
54
56{
57public:
58 //MagickDrain();
59 //virtual ~MagickDrain();
60
61#ifdef DRAIN_MAGICK_yes
64 template<class T>
65 static void convert(const ImageT<T> &drainImage, Magick::ImageT &magickImage);
66
69 template<class T>
70 static void convert(Magick::ImageT &magickImage, ImageT<T> &drainImage);
71
72#endif
73
74};
75
76
77
78#ifdef DRAIN_MAGICK_yes
79
80// Looks like Magick inverts alpha channel
81template <class T>
82void MagickDrain::convert(const ImageT<T> &drainImage, Magick::ImageT &magickImage) {
83
84 Magick::ImageType type = Magick::TrueColorMatteType;
85
86 int imageChannels = drainImage.getImageChannelCount();
87 int alphaChannels = drainImage.getAlphaChannelCount();
88
89 if (alphaChannels > 1){
90 std::cerr << "Warning: multiple alpha channel image, using 1st only \n";
91 std::cerr << " Image geometry:" << drainImage.getGeometry() << '\n';
92 alphaChannels = 1;
93 }
94
95 const ImageT<T> *red = NULL, *green = NULL, *blue = NULL, *alpha = NULL;
96
97 //std::string toOStr;
98 //drainImage.getGeometry().toString(toOStr);
99 //std::cout << "MagickDrain: " << drainImage.getGeometry() << std::endl;
100 /*
101 std::cerr << "img.chs:" << imageChannels << std::endl;
102 std::cerr << "alpha.chs:" << alphaChannels << std::endl;
103 std::cerr << "Extra debug:" << std::endl;
104 drainImage.debug();
105 */
106
107 switch (imageChannels){
108 case 0:
109 if (alphaChannels == 0){
110 std::cerr << "Error: zero channel image!\n";
111 }
112 else {
113 type = Magick::GrayscaleType;
114 red =& drainImage.getChannel(0);
115 green =& drainImage.getChannel(0);
116 blue =& drainImage.getChannel(0);
117 }
118 break;
119 case 1:
120 type = Magick::GrayscaleType;
121 red =& drainImage.getChannel(0);
122 green =& drainImage.getChannel(0);
123 blue =& drainImage.getChannel(0);
124 if (alphaChannels > 0) {
125 type = Magick::GrayscaleMatteType;
126 alpha =& drainImage.getAlphaChannel();
127 }
128 break;
129 case 2:
130 if (!alphaChannels) {
131 type = Magick::GrayscaleMatteType;
132 std::cerr << "Notice: 2 channel image, storing 2nd as alpha channel \n";
133 red =& drainImage.getChannel(0);
134 green =& drainImage.getChannel(0);
135 blue =& drainImage.getChannel(0);
136 alpha =& drainImage.getChannel(1);
137 }
138 else {
139 std::cerr << "Notice: (2+alpha ) channel image, creating 'RGAA' image instead of 'RGBA'.\n";
140 type = Magick::TrueColorMatteType;
141 red =& drainImage.getChannel(0);
142 green =& drainImage.getChannel(1);
143 blue =& drainImage.getAlphaChannel();
144 alpha =& drainImage.getAlphaChannel();
145 }
146 break;
147 case 3:
148 type = Magick::TrueColorType;
149 red =& drainImage.getChannel(0);
150 green =& drainImage.getChannel(1);
151 blue =& drainImage.getChannel(2);
152 if (alphaChannels){
153 type = Magick::TrueColorMatteType;
154 alpha =& drainImage.getAlphaChannel();
155 }
156 break;
157 default:
158 type = Magick::TrueColorMatteType;
159 red =& drainImage.getChannel(0);
160 green =& drainImage.getChannel(1);
161 blue =& drainImage.getChannel(2);
162
163 if (alphaChannels){
164 std::cerr << "Warning: (" << imageChannels << "+alpha) channel image, using (3+alpha). \n";
165 alpha =& drainImage.getAlphaChannel();
166 }
167 else if (imageChannels == 4){
168 std::cerr << "Notice: 4 channel image, storing 4th as alpha channel \n";
169 alpha =& drainImage.getChannel(3);
170 };
171 imageChannels = 3; // WHY?
172 }
173
174
175 const int width = drainImage.getGeometry().getWidth();
176 const int height = drainImage.getGeometry().getHeight();
177
178
179 //Magick::Image magickImage(Magick::Geometry(width,height),Magick::Color("black"));
180
181
182 try {
183 magickImage.classType(Magick::DirectClass); // here?
184 magickImage.size(Magick::Geometry(width,height));
185 //magickImage.read("cow.png");
186
187 magickImage.modifyImage(); // actually: _prepare_to_ modify
188 magickImage.type(type); // The order copied from Magick examples
189
190
191 Magick::PixelPacket *pixel_cache = magickImage.getPixels(0,0,width,height);
192
193
194 Point2D<> p;
195 int &i = p.x;
196 int &j = p.y;
197
198 // TODO: const unsigned drainBits = std::numeric_limits<unsigned char>::is_integer ? std::numeric_limits<unsigned char>::max() : //
199 const unsigned int drainMax = std::numeric_limits<unsigned char>::max();
200 const int shiftBits = magickImage.depth() - 8; // ????
201
202
203 int rowAddress = 0;
204 int address = 0;
205
206 for (j=0; j<height; j++){
207 rowAddress = j*width;
208
209 for (i=0; i<width; i++){
210 address = i + rowAddress;
211 pixel_cache[address].red = (red->at(i,j) << shiftBits);
212 pixel_cache[address].green = (green->at(i,j) << shiftBits);
213 pixel_cache[address].blue = (blue->at(i,j) << shiftBits);
214 if (alpha != NULL)
215 //pixel_cache[address].opacity = ((alpha->at(i,j)) << shiftBits); //WARNING!!
216 // Looks like Magick does NOT invert alpha channel IN THIS DIRECTION
217 pixel_cache[address].opacity = ((drainMax-alpha->at(i,j)) << shiftBits); //WARNING!!
218 }
219 }
220 //std::cerr << "synching" << std::endl;
221 //pixel_cache[rowAddress + 10 + width] = Magick::Color("green");
222
223 magickImage.syncPixels();
224 }
225 catch (Magick::Error& e) {
226 // because 'Error' is derived from the standard C++ std::exception, it has a 'what()' method
227 std::cerr << "a Magick++ error occurred: " << e.what() << std::endl;
228 }
229 catch ( ... ) {
230 std::cerr << "MagickDrain: an unhandled error has occurred; exiting application." << std::endl;
231 exit(1);
232 }
233
234
235 // std::cerr << "magickImage.type = " << magickImage.type() << std::endl;
236
237 // Store comments as KEY=VALUE pairs
238 std::stringstream sstr;
239 std::map<std::string,Data>::const_iterator it;
240 for (it = drainImage.properties.begin(); it != drainImage.properties.end(); it++){
241 sstr << it->first << '=' << it->second << '\n';
242 }
243 magickImage.comment(sstr.toStr());
244
245
246}
247#endif
248
249
250
251#ifdef DRAIN_MAGICK_yes
252
253// Looks like Magick inverts alpha channel
254template <class T>
255void MagickDrain::convert(Magick::ImageT &magickImage, ImageT<T> &drainImage) {
256
257 const int w = magickImage.columns();
258 const int h = magickImage.rows();
259
260 //drainImage.setGeometry(w,h)
261
262 // TODO: redChannel = &drainImage.at(0,0,0);
263
264 switch (magickImage.type()){
265 case Magick::GrayscaleType:
266 drainImage.setGeometry(w,h,1);
267 magickImage.write(0,0,w,h,"I",Magick::CharPixel,&drainImage.at(0,0));
268 break;
269 case Magick::GrayscaleMatteType:
270 drainImage.setGeometry(w,h,1,1);
271 magickImage.write(0,0,w,h,"I",Magick::CharPixel,&drainImage.at(0,0,0));
272 magickImage.write(0,0,w,h,"A",Magick::CharPixel,&drainImage.at(0,0,1));
273 break;
274 // case Magick::RGBColorspace:
275 case Magick::PaletteType: // just test status
276 case Magick::TrueColorType:
277 drainImage.setGeometry(w,h,3);
278 magickImage.write(0,0,w,h,"R",Magick::CharPixel,&drainImage.at(0,0,0));
279 magickImage.write(0,0,w,h,"G",Magick::CharPixel,&drainImage.at(0,0,1));
280 magickImage.write(0,0,w,h,"B",Magick::CharPixel,&drainImage.at(0,0,2));
281 break;
282 case Magick::PaletteMatteType:
283 case Magick::TrueColorMatteType:
284 drainImage.setGeometry(w,h,3,1);
285 magickImage.write(0,0,w,h,"R",Magick::CharPixel,&drainImage.at(0,0,0));
286 magickImage.write(0,0,w,h,"G",Magick::CharPixel,&drainImage.at(0,0,1));
287 magickImage.write(0,0,w,h,"B",Magick::CharPixel,&drainImage.at(0,0,2));
288 magickImage.write(0,0,w,h,"A",Magick::CharPixel,&drainImage.at(0,0,3));
289 // magickImage.write(0,0,w,h,"A",Magick::CharPixel,&drainImage.alphaChannel(0)[0]);
290 break;
291 // default:
292 default:
293 std::stringstream sstr;
294 sstr << "operator<<(image,magickImage) : Magick type " << magickImage.type() << " not handled.";
295 throw std::runtime_error(sstr.toStr());
296 }
297
298 // TODO contradictory!
299 if (drainImage.getAlphaChannelCount()>0){
300 //Image<> & alpha = drainImage.getAlphaChannel();
301 //NegateOp<>().process(alpha,alpha); // Looks like Magick inverts alpha channel IN THIS DIRECTION.
302 //ScaleOp<>(-1.0,255).process(alpha,alpha); // Looks like Magick inverts alpha channel
303 }
304
305 std::stringstream sstr(magickImage.comment()); // dont touch sstr!!
306 drainImage.properties.reader.read(sstr);
307
308 if (drain::Debug > 5){ // TODO static (does not work)
309 std::cerr << "read magickImage.type = " << magickImage.type() << '\n';
310 std::cerr << "comment='" << magickImage.comment() << "'\n";
311 std::cerr << "::::::::::::::::::::\n";
312 std::cerr << drainImage.properties;
313 }
314
315
316}
317
318#endif
319
320
321
322
323} // image
324
325} // drain
326
327#endif /*MAGICKDRAIN_H_*/
328//#endif // ImageMagick
329
330// Drain
FlexVariableMap properties
Container for user-defined KEY=VALUE metadata.
Definition ImageFrame.h:369
A template class for images with static storage type.
Definition ImageT.h:67
Definition MagickDrain.h:56
Definition DataSelector.cpp:1277