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 // consider readFrame() like with PNM
89
91
99 static void write(const ImageFrame &image, const std::string &path);
100
102
104 static
106
107protected:
108 static FileInfo & initFileInfo; //???
109
110};
111
112
113template <class T> // , const CommentReader & commentReader = CommentReader()
114void FilePng::readOld(T & image, const std::string & path, int png_transforms ) {
115
116 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
117
118 mout.debug("path='" , path , "'" );
119
120
121 // Try to open the file
122 FILE *fp = fopen(path.c_str(), "rb");
123 if (fp == NULL){
124 throw std::runtime_error(std::string("FilePng: could not open file: ") + path);
125 }
126
127 // For checking magic code (signature)
128 //const unsigned int PNG_BYTES_TO_CHECK=4;
129 const size_t PNG_BYTES_TO_CHECK=4;
130 png_byte buf[PNG_BYTES_TO_CHECK];
131
132 /* Read in some of the signature bytes */
133 if (fread((void *)buf, size_t(1), PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK){
134 fclose(fp);
135 throw std::runtime_error(std::string("FilePng: suspicious size of file: ") + path);
136 }
137
138 /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
139 Return nonzero (true) if they match */
140 if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0){
141 fclose(fp);
142 throw std::runtime_error(std::string("FilePng: not a png file: ") + path);
143 }
144
145
146 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
147 if (!png_ptr){
148 fclose(fp);
149 throw std::runtime_error(std::string("FilePng: problem in allocating image memory for: ")+path);
150 }
151
152 png_infop info_ptr = png_create_info_struct(png_ptr);
153 if (!info_ptr){
154 fclose(fp);
155 png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
156 throw std::runtime_error(std::string("FilePng: problem in allocating info memory for: ")+path);
157 }
158
159 /*
160 png_infop end_info = png_create_info_struct(png_ptr);
161 if (!end_info){
162 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
163 throw std::runtime_error(std::string("FilePng: problem in allocating end_info memory for: ")+path);
164 }
165 */
166
167 // This may be unstable. According to the documentation, if one uses the high-level interface png_read_png()
168 // one can only configure it with png_transforms flags (PNG_TRANSFORM_*)
169 png_set_palette_to_rgb(png_ptr);
170
171 png_init_io(png_ptr, fp);
172 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
173
175 //if (drain::Debug > 2)
176 mout.debug3("reading data" );
177
178 png_read_png(png_ptr, info_ptr, png_transforms, NULL);
179
180
181
182
183
185 mout.debug3("reading image comments" );
186 int num_text = 0;
187 png_textp text_ptr = NULL;
188 png_get_text(png_ptr, info_ptr,&text_ptr, &num_text);
189 //mout.debug3() << '\n';
190 for (int i = 0; i < num_text; ++i) {
191 mout << text_ptr[i].key << '=' << text_ptr[i].text << '\n';
192 // ValueReader::scanValue(text_ptr[i].text, image.properties[text_ptr[i].key]);
193 JSON::readValue(text_ptr[i].text, image.properties[text_ptr[i].key]);
194 }
195 mout << mout.endl;
196
197
198 const unsigned int inputBitDepth = png_get_bit_depth(png_ptr, info_ptr);
199 drain::Type t;
200 switch (inputBitDepth) {
201 case 16:
202 //image.initialize<unsigned short>();
203 t.setType<unsigned short>();
204 break;
205 case 8:
206 t.setType<unsigned char>();
207 break;
208 default:
209 fclose(fp);
210 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
211 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
212 throw std::runtime_error(std::string("FilePng: unsupported bit depth in : ")+path);
213 return;
214 }
215
216 //image.setType(t);
217 mout.debug("initialize, type " , image.getType().name() );
218
220 const unsigned int width = png_get_image_width(png_ptr, info_ptr);
221 const unsigned int height = png_get_image_height(png_ptr, info_ptr);
222 const unsigned int channels = png_get_channels(png_ptr, info_ptr);
223
224
225 Geometry g(image.getGeometry());
226
227 // This test enables read into an alpha channel.
228 if ((channels!=g.channels.getChannelCount()) || (width!=g.area.getWidth()) || (height!=g.area.getHeight())){
229 switch (channels) {
230 case 4:
231 g.set(width,height,3,1);
232 break;
233 case 3:
234 g.setGeometry(width,height,3); // check alpha=0!
235 break;
236 case 2:
237 g.set(width,height,1,1);
238 break;
239 case 1:
240 g.setGeometry(width,height,1); // check alpha=0!
241 break;
242 default:
243 throw std::runtime_error(std::string("FilePng: invalid channel count in : ")+path);
244 }
245 }
246
247 // Form Image, set target type and geometry. For ImageFrame, compare target type and geometry. If differences, throw exception.
248 image.initialize(t, g);
249
250 mout.debug3() << "png geometry ok, ";
251 mout << "png channels =" << channels << "\n";
252 mout << "png bit_depth=" << inputBitDepth << "\n";
253 mout << mout.endl;
254
255 // TODO: use png_get_pCal(.........)
256#ifdef PNG_pCAL_SUPPORTED___DEFUNCT
258 if (info_ptr->pcal_X0 == info_ptr->pcal_X1){
259 mout.toOStr() << "physical scale supported, but no intensity range, pcalX0=" << info_ptr->pcal_X0 << ", pcalX1=" << info_ptr->pcal_X1 << mout.endl;
260 image.setDefaultLimits();
261 }
262 else {
263 image.setLimits(info_ptr->pcal_X0, info_ptr->pcal_X1);
264 mout.note("setting physical scale: " , image );
265 }
266
267#endif
268
269 /*
270 if ((bit_depth!=8) && (bit_depth != 16)){
271 fclose(fp);
272 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
273 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
274 throw std::runtime_error(std::string("FilePng: unsupported bit depth in : ")+path);
275 }
276 */
277 const unsigned int targetBitDepth = 8*image.getConf().getElementSize();
278
279 const bool from8to8 = (inputBitDepth == 8) && (targetBitDepth == 8);
280 const bool from8to16 = (inputBitDepth == 8) && (targetBitDepth == 16);
281
282 if (from8to8) {
283 mout.debug("8-bit input, 8-bit target, easy..." );
284 }
285 else if (from8to16) {
286 mout.note("-bit input, 16-bit target, rescaling..." );
287 }
288 else {
289 if ((inputBitDepth == 16) && (targetBitDepth == 16)){
290 mout.debug("16-bit input, 16-bit target, ok..." );
291 }
292 else {
293 mout.warn(inputBitDepth , "-bit input, ", targetBitDepth , "-bit target, problems ahead?" );
294 }
295 }
296
297 png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
298 png_bytep p;
299 int i0;
300 for (unsigned int j = 0; j < height; ++j) {
301 p = row_pointers[j];
302 for (unsigned int i = 0; i < width; ++i) {
303 for (unsigned int k = 0; k < channels; ++k) {
304 i0 = channels*i + k;
305 if (from8to8) {
306 image.put(i,j,k, p[i0]);
307 }
308 else if (from8to16) {
309 image.put(i,j,k, p[i0]<<8);
310 }
311 else {
312 image.put(i,j,k, (p[i0*2]<<8) + (p[i0*2+1]<<0));
313 }
314 }
315 }
316 }
317
318 fclose(fp);
319 png_destroy_read_struct(&png_ptr,&info_ptr, (png_infopp)NULL);
320 //png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1); // ???
321
322 //png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
323 //png_destroy_info_struct(png_ptr,&info_ptr);
324
325
326}
327
328
329
330}
331
332}
333
334#endif /*FILEPng_H_*/
335
336// Drain
Definition FileInfo.h:48
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 write(const ImageFrame &image, const std::string &path)
Writes image to a png file.
Definition FilePng.cpp:288
static FileInfo fileInfo
Syntax for recognising image files.
Definition FilePng.h:101
static void read(ImageFrame &image, const std::string &path, int png_transforms=0)
Definition FilePng.cpp:76
static short int compressionLevel
Default compression level for png_set_compression_level(png_ptr, ...);.
Definition FilePng.h:105
static void readOld(T &image, const std::string &path, int png_transforms=0)
Syntax for recognising png files.
Definition FilePng.h:114
Definition Geometry.h:145
Image with static geometry.
Definition ImageFrame.h:67
Definition DataSelector.cpp:1277