OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimPngCodec.cpp
Go to the documentation of this file.
1 #include "ossimPngCodec.h"
3 #include <png.h>
4 #include <cstdlib>
5 
6 static const char ADD_ALPHA_CHANNEL_KW[] = "add_alpha_channel";
7 
8 static void user_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
9 {
10  ossim_uint8** input_pointer = reinterpret_cast<ossim_uint8**>(png_get_io_ptr (png_ptr));
11 
12  memcpy (data, *input_pointer, sizeof (ossim_uint8) * length);
13  (*input_pointer) += length;
14 }
15 
16 static void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
17 {
18  std::vector<ossim_uint8> *p = (std::vector<ossim_uint8>*)png_get_io_ptr(png_ptr);
19  p->insert(p->end(), data, data + length);
20 }
21 
23  png_struct *p;
24  TPngDestructor(png_struct *p) : p(p) {}
25  ~TPngDestructor() { if (p) { png_destroy_write_struct(&p, NULL); } }
26 };
27 
29  :m_addAlphaChannel(addAlpha),
30  m_ext("png")
31 {
32 
33 }
34 
36 {
37  return "png";
38 }
39 
40 const std::string& ossimPngCodec::getExtension() const
41 {
42  return m_ext; // "png"
43 }
44 
45 
47  std::vector<ossim_uint8>& out ) const
48 {
49  out.clear();
50  ossim_int32 colorType = -1;
51  ossim_int32 bitDepth = 0;
52  if(!in->getBuf()) return false;
53  if(in->getNumberOfBands() == 1)
54  {
56  {
57  colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
58  }
59  else
60  {
61  colorType = PNG_COLOR_TYPE_GRAY;
62  }
63  }
64  else if(in->getNumberOfBands() == 3)
65  {
67  {
68  colorType = PNG_COLOR_TYPE_RGB_ALPHA;
69  }
70  else
71  {
72  colorType = PNG_COLOR_TYPE_RGB;
73  }
74  }
75  if(colorType < 0) return false;
76 
77  switch(in->getScalarType())
78  {
79  case OSSIM_UINT8:
80  {
81  bitDepth = 8;
82  break;
83  }
84  case OSSIM_USHORT11:
85  case OSSIM_UINT16:
86  {
87  bitDepth = 16;
88  break;
89  }
90  default:
91  {
92  bitDepth = 0;
93  }
94  }
95  if(bitDepth == 0) return false;
96  // std::cout << "bitDepth = " << bitDepth << ", BANDS = " << in->getNumberOfBands() << std::endl;
97  ossim_int32 w = in->getWidth();
98  ossim_int32 h = in->getHeight();
99  png_structp p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
100  TPngDestructor destroyPng(p);
101  png_infop info_ptr = png_create_info_struct(p);
102  setjmp(png_jmpbuf(p));
103 
104  png_set_IHDR(p, info_ptr, w, h, bitDepth,
105  colorType,
106  PNG_INTERLACE_NONE,
107  PNG_COMPRESSION_TYPE_DEFAULT,
108  PNG_FILTER_TYPE_DEFAULT);
109  png_set_compression_level(p, 1);
110 
111  switch(colorType)
112  {
113  case PNG_COLOR_TYPE_GRAY:
114  {
115  if(bitDepth == 8)
116  {
117  ossim_uint8* buf = (ossim_uint8*)in->getBuf();
118  std::vector<ossim_uint8*> rows(h);
119  for(ossim_int32 y=0; y<h;++y)
120  {
121  rows[y] = (ossim_uint8*)(buf + y * w) ;
122  }
123  png_set_rows(p, info_ptr, &rows[0]);
124  png_set_write_fn(p, &out, PngWriteCallback, NULL);
125  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
126  }
127  else if(bitDepth == 16)
128  {
129  ossim_uint16* buf = (ossim_uint16*)in->getBuf();
130  std::vector<ossim_uint8*> rows(h);
131  for(int y=0; y<h;++y)
132  {
133  rows[y] = (ossim_uint8*)(buf + y * w) ;
134  }
135  png_set_rows(p, info_ptr, &rows[0]);
136  png_set_write_fn(p, &out, PngWriteCallback, NULL);
137  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
138  }
139  break;
140  }
141  case PNG_COLOR_TYPE_GRAY_ALPHA:
142  {
143  if(bitDepth == 8)
144  {
145  std::vector<ossim_uint8> buf(w*h*2);
146  std::vector<ossim_uint8*> rows(h);
147  ossim_uint8* bufPtr = &buf.front();
148  in->unloadTileToBipAlpha(&buf.front(), in->getImageRectangle(), in->getImageRectangle());
149  for(int y=0; y<h;++y)
150  {
151  rows[y] = (ossim_uint8*)(bufPtr + y * (w*2)) ;
152  }
153  png_set_rows(p, info_ptr, &rows[0]);
154  png_set_write_fn(p, &out, PngWriteCallback, NULL);
155  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
156 
157  }
158  else
159  {
160  std::vector<ossim_uint16> buf(w*h*2);
161  std::vector<ossim_uint8*> rows(h);
162  ossim_uint16* bufPtr = &buf.front();
163  in->unloadTileToBipAlpha(&buf.front(), in->getImageRectangle(), in->getImageRectangle());
164  for(ossim_int32 y=0; y<h;++y)
165  {
166  rows[y] = (ossim_uint8*)(bufPtr + y * (w*2)) ;
167  }
168  png_set_rows(p, info_ptr, &rows[0]);
169  png_set_write_fn(p, &out, PngWriteCallback, NULL);
170  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
171  }
172 
173  break;
174  }
175  case PNG_COLOR_TYPE_RGB:
176  {
177  if(bitDepth == 8)
178  {
179  std::vector<ossim_uint8> buf(w*h*3);
180  std::vector<ossim_uint8*> rows(h);
181  in->unloadTile(&buf.front(), in->getImageRectangle(), in->getImageRectangle(), OSSIM_BIP);
182  ossim_uint8* bufPtr = &buf.front();
183  for(ossim_int32 y=0; y<h;++y)
184  {
185  rows[y] = (ossim_uint8*)(bufPtr + y * (w*3)) ;
186  }
187  png_set_rows(p, info_ptr, &rows[0]);
188  png_set_write_fn(p, &out, PngWriteCallback, NULL);
189  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
190  }
191  else
192  {
193  std::vector<ossim_uint16> buf(w*h*3);
194  std::vector<ossim_uint8*> rows(h);
195  ossim_uint16* bufPtr = &buf.front();
196  in->unloadTile(&buf.front(), in->getImageRectangle(), in->getImageRectangle(),OSSIM_BIP);
197  for(ossim_int32 y=0; y<h;++y)
198  {
199  rows[y] = (ossim_uint8*)(bufPtr + y * (w*3)) ;
200  }
201  png_set_rows(p, info_ptr, &rows[0]);
202  png_set_write_fn(p, &out, PngWriteCallback, NULL);
203  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
204  }
205  break;
206  }
207  case PNG_COLOR_TYPE_RGB_ALPHA:
208  {
209  if(bitDepth == 8)
210  {
211  std::vector<ossim_uint8> buf(w*h*4);
212  std::vector<ossim_uint8*> rows(h);
213  in->unloadTileToBipAlpha(&buf.front(), in->getImageRectangle(), in->getImageRectangle());
214  ossim_uint8* bufPtr = &buf.front();
215  for(int y=0; y<h;++y)
216  {
217  rows[y] = (ossim_uint8*)(bufPtr + y * (w*4)) ;
218  }
219  png_set_rows(p, info_ptr, &rows[0]);
220  png_set_write_fn(p, &out, PngWriteCallback, NULL);
221  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
222  }
223  else
224  {
225  std::vector<ossim_uint16> buf(w*h*4);
226  std::vector<ossim_uint8*> rows(h);
227  in->unloadTileToBipAlpha(&buf.front(), in->getImageRectangle(), in->getImageRectangle());
228  ossim_uint16* bufPtr = &buf.front();
229  for(ossim_int32 y=0; y<h;++y)
230  {
231  rows[y] = (ossim_uint8*)(bufPtr + y * (w*4)) ;
232  }
233  png_set_rows(p, info_ptr, &rows[0]);
234  png_set_write_fn(p, &out, PngWriteCallback, NULL);
235  png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
236  }
237  break;
238  }
239  }
240 
241  return true;
242 }
243 
244 bool ossimPngCodec::decode(const std::vector<ossim_uint8>& in,
245  ossimRefPtr<ossimImageData>& out ) const
246 {
247  bool result = true;
248  ossim_uint32 y = 0;
249  png_structp pngPtr = 0;
250  png_infop infoPtr = 0;
251  png_uint_32 pngWidth = 0;
252  png_uint_32 pngHeight = 0;
253  ossim_int32 pngBitDepth=0, pngByteDepth = 0, pngColorType=0, pngInterlaceType=0;
254 
255  // png_bytep* row_pointers=0;
256 
257  if (in.empty())
258  {
259  return false;
260  }
261 
262  pngPtr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
263  //assert (png_ptr && "creating png_create_write_structpng_create_write_struct failed");
264 
265  // Initialize info structure
266  infoPtr = png_create_info_struct (pngPtr);
267 
268  // Setup Exception handling
269  setjmp (png_jmpbuf(pngPtr));
270 
271  const ossim_uint8* inputPointer = &in.front();//&pngData_arg[0];
272  png_set_read_fn (pngPtr, reinterpret_cast<void*> (&inputPointer), user_read_data);
273 
274  png_read_info (pngPtr, infoPtr);
275 
276  png_get_IHDR (pngPtr, infoPtr, &pngWidth, &pngHeight, &pngBitDepth,
277  &pngColorType, &pngInterlaceType, NULL, NULL);
278 
279 
280 
281  // ensure a color bit depth of 8
282  //assert(png_bit_depth==sizeof(T)*8);
283 
284  ossim_uint32 pngChannels = 0;
285  switch (pngColorType)
286  {
287  case PNG_COLOR_TYPE_GRAY:
288  {
289  pngChannels = 1;
290  break;
291  }
292  case PNG_COLOR_TYPE_GRAY_ALPHA:
293  {
294  pngChannels = 2;
295  break;
296  }
297  case PNG_COLOR_TYPE_RGB:
298  {
299  pngChannels = 3;
300  break;
301  }
302  case PNG_COLOR_TYPE_RGB_ALPHA:
303  {
304  pngChannels = 4;
305  break;
306  }
307  default:
308  {
309  pngChannels = 0;
310  break;
311  }
312  }
313  pngByteDepth = pngBitDepth>>3;
314  //imageData_arg.clear ();
315  //imageData_arg.resize (png_height * png_width * png_channels);
316 
317  ossim_uint32 bytes = pngHeight*pngWidth*pngChannels*pngByteDepth;
318  //row_pointers = reinterpret_cast<png_bytep*> (malloc (sizeof(png_bytep) * png_height));
319  std::vector<ossim_uint8> data(bytes);
320  std::vector<ossim_uint8*> rowPointers(pngHeight);
321  ossim_uint8* dataPtr = &data.front();
322  for (y = 0; y < pngHeight; y++)
323  {
324  rowPointers[y] = reinterpret_cast<ossim_uint8*> (dataPtr + ( y*(pngWidth*pngByteDepth*pngChannels)));
325  }
326 
327  png_read_image (pngPtr, &rowPointers.front());
328 
329  ossimScalarType scalarType = ((pngByteDepth==1)?OSSIM_UINT8:OSSIM_UINT16);
330  ossim_uint32 bands = pngChannels;
331 
332  if((bands == 2) ||(bands==4))
333  {
334  bands = bands - 1;
335  }
336  // now allocate the ossimImageData object if not already allocated
337  if(!out.valid())
338  {
339  out = new ossimImageData(0, scalarType, bands, pngWidth, pngHeight);
340  out->initialize();
341  }
342  else
343  {
344  out->setNumberOfDataComponents(bands);
345  out->setImageRectangleAndBands(ossimIrect(0,0,pngWidth-1,pngHeight-1), bands);
346  out->initialize();
347  }
348 
349  if(pngChannels == 1)
350  {
351  // ossim_uint32 idx = 0;
352  memcpy(out->getBuf(0), dataPtr, bytes);
353  out->validate();
354  // once we support alpha channel properly we will need to add alpha settings here
355 
356  }
357  else if(pngChannels == 2)
358  {
359  //std::cout << "DECODING 2 channels\n";
360  ossim_uint32 size = pngWidth*pngHeight;
361  ossim_uint32 idx = 0;
362  if(scalarType == OSSIM_UINT16)
363  {
364  ossim_uint16* tempDataPtr = reinterpret_cast<ossim_uint16*> (dataPtr);
365  ossim_uint16* buf = static_cast<ossim_uint16*>(out->getBuf(0));
366 
367  for(idx = 0; idx < size;++idx)
368  {
369  *buf = tempDataPtr[0];
370 
371  tempDataPtr+=2;++buf;
372  }
373  out->validate();
374  }
375  else if(scalarType == OSSIM_UINT8)
376  {
377  ossim_uint8* tempDataPtr = dataPtr;
378  ossim_uint8* buf = static_cast<ossim_uint8*>(out->getBuf(0));
379 
380  for(idx = 0; idx < size;++idx)
381  {
382  *buf = *tempDataPtr;
383 
384  tempDataPtr+=2;++buf;
385  }
386  out->validate();
387  }
388  else
389  {
390  result = false;
391  }
392  }
393  else if(pngChannels == 4)
394  {
395  //std::cout << "DECODING 4 channels\n";
396  ossim_uint32 size = pngWidth*pngHeight;
397  ossim_uint32 idx = 0;
398  if(scalarType == OSSIM_UINT16)
399  {
400  ossim_uint16* tempDataPtr = reinterpret_cast<ossim_uint16*> (dataPtr);
401  ossim_uint16* buf1 = static_cast<ossim_uint16*>(out->getBuf(0));
402  ossim_uint16* buf2 = static_cast<ossim_uint16*>(out->getBuf(1));
403  ossim_uint16* buf3 = static_cast<ossim_uint16*>(out->getBuf(2));
404 
405  for(idx = 0; idx < size;++idx)
406  {
407  *buf1 = tempDataPtr[0];
408  *buf2 = tempDataPtr[1];
409  *buf3 = tempDataPtr[2];
410 
411  tempDataPtr+=4;++buf1;++buf2;++buf3;
412  }
413  out->validate();
414  }
415  else if(scalarType == OSSIM_UINT8)
416  {
417  ossim_uint8* tempDataPtr = dataPtr;
418  ossim_uint8* buf1 = static_cast<ossim_uint8*>(out->getBuf(0));
419  ossim_uint8* buf2 = static_cast<ossim_uint8*>(out->getBuf(1));
420  ossim_uint8* buf3 = static_cast<ossim_uint8*>(out->getBuf(2));
421 
422  for(idx = 0; idx < size;++idx)
423  {
424  *buf1 = tempDataPtr[0];
425  *buf2 = tempDataPtr[1];
426  *buf3 = tempDataPtr[2];
427 
428  tempDataPtr+=4;++buf1;++buf2;++buf3;
429  }
430  out->validate();
431  }
432  else
433  {
434  result = false;
435  }
436  }
437  else
438  {
439  out->loadTile(dataPtr, out->getImageRectangle(), OSSIM_BIP);
440  }
441 
442  if (infoPtr)
443  {
444  png_free_data (pngPtr, infoPtr, PNG_FREE_ALL, -1);
445  }
446  if (pngPtr)
447  {
448  png_destroy_read_struct (&pngPtr, 0, 0);
449  }
450 
451  return result;
452 }
453 
455 {
456  if(property->getName() == ADD_ALPHA_CHANNEL_KW)
457  {
458  m_addAlphaChannel = property->valueToString().toBool();
459  }
460  else
461  {
462  ossimCodecBase::setProperty(property);
463  }
464 }
465 
467 {
469 
470  if(name == ADD_ALPHA_CHANNEL_KW)
471  {
472 
473  }
474  else
475  {
476  result = ossimCodecBase::getProperty(name);
477  }
478 
479  return result;
480 }
481 
482 void ossimPngCodec::getPropertyNames(std::vector<ossimString>& propertyNames)const
483 {
484  propertyNames.push_back(ADD_ALPHA_CHANNEL_KW);
485 }
486 
487 bool ossimPngCodec::loadState(const ossimKeywordlist& kwl, const char* prefix)
488 {
489  ossimString addAlphaChannel = kwl.find(prefix, ADD_ALPHA_CHANNEL_KW);
490 
491  if(!addAlphaChannel.empty())
492  {
493  m_addAlphaChannel = addAlphaChannel.toBool();
494  }
495 
496  return ossimCodecBase::loadState(kwl, prefix);
497 }
498 
499 bool ossimPngCodec::saveState(ossimKeywordlist& kwl, const char* prefix)const
500 {
501  kwl.add(prefix, ADD_ALPHA_CHANNEL_KW, m_addAlphaChannel);
502 
503  return ossimCodecBase::saveState(kwl, prefix);
504 }
virtual const std::string & getExtension() const
virtual ossim_uint32 getWidth() const
std::string m_ext
Definition: ossimPngCodec.h:91
virtual ossim_uint32 getNumberOfBands() const
16 bit unsigned integer
virtual void setProperty(ossimRefPtr< ossimProperty > property)
Ineterface to allow for specific properties to be set.
Represents serializable keyword/value map.
ossim_uint32 y
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
bool m_addAlphaChannel
Definition: ossimPngCodec.h:90
ossimPngCodec(bool addAlpha=false)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Definition: ossimObject.cpp:95
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
virtual ossim_uint32 getHeight() const
virtual ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
Interface to get the value of a specific property.
virtual bool decode(const std::vector< ossim_uint8 > &in, ossimRefPtr< ossimImageData > &out) const
Decode png method.
virtual ossimString getCodecType() const
Will return the identifier used to identify the codec type.
unsigned short ossim_uint16
virtual void initialize()
Initialize the data buffer.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Save the state of the codec to the keywordlist.
png_struct * p
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual void loadTile(const void *src, const ossimIrect &src_rect, ossimInterleaveType il_type)
virtual void setNumberOfDataComponents(ossim_uint32 n)
How many components make up this data object.
TPngDestructor(png_struct *p)
yy_size_t size
virtual ossimDataObjectStatus validate() const
virtual void setImageRectangleAndBands(const ossimIrect &rect, ossim_uint32 numberOfBands)
bool toBool() const
String to numeric methods.
unsigned int ossim_uint32
virtual ossimIrect getImageRectangle() const
virtual void unloadTileToBipAlpha(void *dest, const ossimIrect &dest_rect, const ossimIrect &clip_rect) const
virtual void unloadTile(void *dest, const ossimIrect &dest_rect, ossimInterleaveType il_type) const
ossimScalarType
virtual void getPropertyNames(std::vector< ossimString > &propertyNames) const
Get a list of all supported property names.
virtual ossimScalarType getScalarType() const
16 bit unsigned integer (11 bits used)
virtual ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Allocate the state of the object thorugh a factory load/keywordlist.
virtual const void * getBuf() const
virtual void setProperty(const ossimString &name, const ossimString &value)
bool empty() const
Definition: ossimString.h:411
8 bit unsigned integer
unsigned char ossim_uint8
virtual bool encode(const ossimRefPtr< ossimImageData > &in, std::vector< ossim_uint8 > &out) const
Encode png method.
const ossimString & getName() const
int ossim_int32