Loading...
Searching...
No Matches
FilePng.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#ifndef FILEPNG_H_
32#define FILEPNG_H_
33
34
35#include <string>
36
37#include <png.h>
38
39#include "drain/util/FileInfo.h"
40// #include "drain/util/RegExp.h"
41#include "drain/util/JSON.h" // for reading attribute value
42
43#include "Image.h"
44//
45
46
47namespace drain
48{
49namespace image
50{
51
52// using namespace std;
53
55
60{
61public:
62
64 //static
65 //const drain::RegExp fileNameRegExp;
66
67
69
78 template <class T>
79 static
80 void readOld(T & image, const std::string &path, int png_transforms = 0); //(PNG_TRANSFORM_PACKING || PNG_TRANSFORM_EXPAND)); 16 >> 8?
81
82 // static
83 // void read(ImageFrame & image, const std::string &path, int png_transforms = 0); //(PNG_TRANSFORM_PACKING || PNG_TRANSFORM_EXPAND)); 16 >> 8?
84
85 static
86 void read(ImageFrame & image, const std::string &path, int png_transforms = 0); //(PNG_TRANSFORM_PACKING || PNG_TRANSFORM_EXPAND)); 16 >> 8?
87
88 // static
89 // void readImage(Image & image, const std::string &path, int png_transforms = 0); //(PNG_TRANSFORM_PACKING || PNG_TRANSFORM_EXPAND)); 16 >> 8?
90
91 // consider readFrame() like with PNM
92
94
102 static void write(const ImageFrame &image, const std::string &path);
103
105
107 static
109
110protected:
111
112 // static FileInfo & initFileInfo; //???
113
114
115 static
116 void readFile(const std::string & path, png_structp & png_ptr, png_infop & info_ptr, int png_transforms);
117
118 static
119 void readComments(png_structp & png_ptr, png_infop & info_ptr, FlexVariableMap & properties);
120
121 static
122 void readConfiguration(png_structp & png_ptr, png_infop & info_ptr, ImageConf & conf);
123
124 static
125 void copyData(png_structp & png_ptr, png_infop & info_ptr, const ImageConf & pngConf, ImageFrame & image);
126
127
128 static
129 void copyData8to8(png_structp & png_ptr, png_infop & info_ptr, ImageFrame & image);
130
131 static
132 void copyData8to16(png_structp & png_ptr, png_infop & info_ptr, ImageFrame & image);
133
134 static
135 void copyData16(png_structp & png_ptr, png_infop & info_ptr, ImageFrame & image);
136
137};
138
139
140template <class T> // , const CommentReader & commentReader = CommentReader()
141void FilePng::readOld(T & image, const std::string & path, int png_transforms ) {
142
143 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
144
145 mout.debug("path='" , path , "'" );
146
147
148 // Try to open the file
149 FILE *fp = fopen(path.c_str(), "rb");
150 if (fp == NULL){
151 throw std::runtime_error(std::string("FilePng: could not open file: ") + path);
152 }
153
154 // For checking magic code (signature)
155 //const unsigned int PNG_BYTES_TO_CHECK=4;
156 const size_t PNG_BYTES_TO_CHECK=4;
157 png_byte buf[PNG_BYTES_TO_CHECK];
158
159 /* Read in some of the signature bytes */
160 if (fread((void *)buf, size_t(1), PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK){
161 fclose(fp);
162 throw std::runtime_error(std::string("FilePng: suspicious size of file: ") + path);
163 }
164
165 /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
166 Return nonzero (true) if they match */
167 if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0){
168 fclose(fp);
169 throw std::runtime_error(std::string("FilePng: not a png file: ") + path);
170 }
171
172
173 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
174 if (!png_ptr){
175 fclose(fp);
176 throw std::runtime_error(std::string("FilePng: problem in allocating image memory for: ")+path);
177 }
178
179 png_infop info_ptr = png_create_info_struct(png_ptr);
180 if (!info_ptr){
181 fclose(fp);
182 png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
183 throw std::runtime_error(std::string("FilePng: problem in allocating info memory for: ")+path);
184 }
185
186 /*
187 png_infop end_info = png_create_info_struct(png_ptr);
188 if (!end_info){
189 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
190 throw std::runtime_error(std::string("FilePng: problem in allocating end_info memory for: ")+path);
191 }
192 */
193
194 // This may be unstable. According to the documentation, if one uses the high-level interface png_read_png()
195 // one can only configure it with png_transforms flags (PNG_TRANSFORM_*)
196 png_set_palette_to_rgb(png_ptr);
197
198 png_init_io(png_ptr, fp);
199 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
200
202 //if (drain::Debug > 2)
203 mout.debug3("reading data" );
204
205 png_read_png(png_ptr, info_ptr, png_transforms, NULL);
206
207
208
209
210
212 mout.debug3("reading image comments" );
213 int num_text = 0;
214 png_textp text_ptr = NULL;
215 png_get_text(png_ptr, info_ptr,&text_ptr, &num_text);
216 //mout.debug3() << '\n';
217 for (int i = 0; i < num_text; ++i) {
218 mout << text_ptr[i].key << '=' << text_ptr[i].text << '\n';
219 // ValueReader::scanValue(text_ptr[i].text, image.properties[text_ptr[i].key]);
220 JSON::readValue(text_ptr[i].text, image.properties[text_ptr[i].key]);
221 }
222 mout << mout.endl;
223
224
225 const unsigned int inputBitDepth = png_get_bit_depth(png_ptr, info_ptr);
226 drain::Type t;
227 switch (inputBitDepth) {
228 case 16:
229 //image.initialize<unsigned short>();
230 t.setType<unsigned short>();
231 break;
232 case 8:
233 t.setType<unsigned char>();
234 break;
235 default:
236 fclose(fp);
237 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
238 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
239 throw std::runtime_error(std::string("FilePng: unsupported bit depth in : ")+path);
240 return;
241 }
242
243 //image.setType(t);
244 mout.debug("initialize, type " , image.getType().name() );
245
247 const unsigned int width = png_get_image_width(png_ptr, info_ptr);
248 const unsigned int height = png_get_image_height(png_ptr, info_ptr);
249 const unsigned int channels = png_get_channels(png_ptr, info_ptr);
250
251
252 Geometry g(image.getGeometry());
253
254 // This test enables read into an alpha channel.
255 if ((channels!=g.channels.getChannelCount()) || (width!=g.area.getWidth()) || (height!=g.area.getHeight())){
256 switch (channels) {
257 case 4:
258 g.set(width,height,3,1);
259 break;
260 case 3:
261 g.setGeometry(width,height,3); // check alpha=0!
262 break;
263 case 2:
264 g.set(width,height,1,1);
265 break;
266 case 1:
267 g.setGeometry(width,height,1); // check alpha=0!
268 break;
269 default:
270 throw std::runtime_error(std::string("FilePng: invalid channel count in : ")+path);
271 }
272 }
273
274 // Form Image, set target type and geometry. For ImageFrame, compare target type and geometry. If differences, throw exception.
275 image.initialize(t, g);
276
277 mout.debug3() << "png geometry ok, ";
278 mout << "png channels =" << channels << "\n";
279 mout << "png bit_depth=" << inputBitDepth << "\n";
280 mout << mout.endl;
281
282 // TODO: use png_get_pCal(.........)
283#ifdef PNG_pCAL_SUPPORTED___DEFUNCT
285 if (info_ptr->pcal_X0 == info_ptr->pcal_X1){
286 mout.toOStr() << "physical scale supported, but no intensity range, pcalX0=" << info_ptr->pcal_X0 << ", pcalX1=" << info_ptr->pcal_X1 << mout.endl;
287 image.setDefaultLimits();
288 }
289 else {
290 image.setLimits(info_ptr->pcal_X0, info_ptr->pcal_X1);
291 mout.note("setting physical scale: " , image );
292 }
293
294#endif
295
296 /*
297 if ((bit_depth!=8) && (bit_depth != 16)){
298 fclose(fp);
299 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
300 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
301 throw std::runtime_error(std::string("FilePng: unsupported bit depth in : ")+path);
302 }
303 */
304 const unsigned int targetBitDepth = 8*image.getConf().getElementSize();
305
306 const bool from8to8 = (inputBitDepth == 8) && (targetBitDepth == 8);
307 const bool from8to16 = (inputBitDepth == 8) && (targetBitDepth == 16);
308
309 if (from8to8) {
310 mout.debug("8-bit input, 8-bit target, easy..." );
311 }
312 else if (from8to16) {
313 mout.note("-bit input, 16-bit target, rescaling..." );
314 }
315 else {
316 if ((inputBitDepth == 16) && (targetBitDepth == 16)){
317 mout.debug("16-bit input, 16-bit target, ok..." );
318 }
319 else {
320 mout.warn(inputBitDepth , "-bit input, ", targetBitDepth , "-bit target, problems ahead?" );
321 }
322 }
323
324 png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
325 png_bytep p;
326 int i0;
327 for (unsigned int j = 0; j < height; ++j) {
328 p = row_pointers[j];
329 for (unsigned int i = 0; i < width; ++i) {
330 for (unsigned int k = 0; k < channels; ++k) {
331 i0 = channels*i + k;
332 if (from8to8) {
333 image.put(i,j,k, p[i0]);
334 }
335 else if (from8to16) {
336 image.put(i,j,k, p[i0]<<8);
337 }
338 else {
339 image.put(i,j,k, (p[i0*2]<<8) + (p[i0*2+1]<<0));
340 }
341 }
342 }
343 }
344
345 fclose(fp);
346 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
347 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
348
349 //png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
350 //png_destroy_info_struct(png_ptr,&info_ptr);
351
352
353}
354
355
356
357}
358
359}
360
361#endif /*FILEPng_H_*/
362
363// Drain
Definition FileInfo.h:47
A map of FlexVariable:s.
Definition VariableMap.h:138
static void readValue(std::istream &istr, Castable &v, bool keepType=false)
Read a value (JSON syntax). Read stream until a value has been extracted, with type recognition.
Definition JSON.cpp:52
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:431
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:667
Logger & note(const TT &... args)
For top-level information.
Definition Log.h:490
Utilities related to std::type_info.
Definition Type.h:48
size_t getChannelCount() const
Return the number of channels (image and alpha)
Definition Geometry.h:106
For reading and writing images in PNG format.
Definition FilePng.h:60
static void readFile(const std::string &path, png_structp &png_ptr, png_infop &info_ptr, int png_transforms)
Definition FilePng.cpp:67
static void write(const ImageFrame &image, const std::string &path)
Writes image to a png file.
Definition FilePng.cpp:379
static FileInfo fileInfo
Syntax for recognising image files.
Definition FilePng.h:104
static void readComments(png_structp &png_ptr, png_infop &info_ptr, FlexVariableMap &properties)
Definition FilePng.cpp:130
static short int compressionLevel
Default compression level for png_set_compression_level(png_ptr, ...);.
Definition FilePng.h:108
static void readOld(T &image, const std::string &path, int png_transforms=0)
Syntax for recognising png files.
Definition FilePng.h:141
Definition Geometry.h:143
Struct for image (excluding data)
Definition ImageConf.h:333
Image with static geometry.
Definition ImageFrame.h:62
Definition DataSelector.cpp:1277