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