-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add libpng library support for PNG files
Currently works only on Unix (Linux and MacOS) systems with preinstalled libpng library #7
- Loading branch information
Showing
2 changed files
with
180 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
#include <stdlib.h> | ||
#include <png.h> | ||
#include <vector> | ||
#include "png_file.h" | ||
#include "../image_exception.h" | ||
|
||
namespace Png_Operation | ||
{ | ||
Bitmap_Image::Image Load( const std::string & path ) | ||
{ | ||
if( path.empty() ) | ||
throw imageException( "Incorrect file path for image file loading" ); | ||
|
||
FILE * file = fopen( path.data(), "rb" ); | ||
if( !file ) | ||
throw imageException( "Cannot create file for reading" ); | ||
|
||
png_structp png = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); | ||
if( !png ) | ||
return Bitmap_Image::Image(); | ||
|
||
png_infop info = png_create_info_struct( png ); | ||
if( !info ) | ||
return Bitmap_Image::Image(); | ||
|
||
png_init_io( png, file ); | ||
png_read_info( png, info ); | ||
|
||
const uint32_t width = png_get_image_width ( png, info ); | ||
const uint32_t height = png_get_image_height( png, info ); | ||
const uint8_t colorType = png_get_color_type ( png, info ); | ||
const uint8_t bitDepth = png_get_bit_depth ( png, info ); | ||
|
||
if( bitDepth == 16u ) | ||
png_set_strip_16( png ); | ||
|
||
if( colorType == PNG_COLOR_TYPE_PALETTE ) | ||
png_set_palette_to_rgb( png ); | ||
|
||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth | ||
if( colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8u ) | ||
png_set_expand_gray_1_2_4_to_8( png ); | ||
|
||
if( png_get_valid( png, info, PNG_INFO_tRNS ) ) | ||
png_set_tRNS_to_alpha( png ); | ||
|
||
// These color_type don't have an alpha channel then fill it with 0xff | ||
if( colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_PALETTE ) | ||
png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); | ||
|
||
if( colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA ) | ||
png_set_gray_to_rgb( png ); | ||
|
||
png_read_update_info( png, info ); | ||
|
||
uint8_t ** row_pointers = reinterpret_cast<uint8_t**>( malloc( sizeof( uint8_t* ) * height ) ); | ||
|
||
const size_t rowByteCount = png_get_rowbytes( png, info ); | ||
|
||
for( uint32_t y = 0; y < height; ++y ) | ||
row_pointers[y] = reinterpret_cast<uint8_t*>( malloc( rowByteCount ) ); | ||
|
||
png_read_image( png, row_pointers ); | ||
|
||
Bitmap_Image::Image image( width, height, Bitmap_Image::RGB ); | ||
|
||
uint8_t * outY = image.data(); | ||
for( uint32_t y = 0; y < height; ++y, outY += image.rowSize() ) { | ||
const uint8_t * column = row_pointers[y]; | ||
uint8_t * outX = outY; | ||
for( uint32_t x = 0; x < width; ++x, column += 4 ) { | ||
*(outX++) = column[2]; | ||
*(outX++) = column[1]; | ||
*(outX++) = column[0]; | ||
} | ||
} | ||
|
||
fclose( file ); | ||
|
||
for( uint32_t y = 0; y < height; ++y ) | ||
free( row_pointers[y] ); | ||
free( row_pointers ); | ||
|
||
png_destroy_read_struct( &png, &info, NULL ); | ||
|
||
return image; | ||
} | ||
|
||
void Load( const std::string & path, Bitmap_Image::Image & raw ) | ||
{ | ||
raw = Load( path ); | ||
} | ||
|
||
void Save( const std::string & path, const Bitmap_Image::Image & image ) | ||
{ | ||
Save( path, image, 0, 0, image.width(), image.height() ); | ||
} | ||
|
||
void Save( const std::string & path, const Bitmap_Image::Image & image, uint32_t startX, uint32_t startY, | ||
uint32_t width, uint32_t height ) | ||
{ | ||
Image_Function::ParameterValidation( image, startX, startY, width, height ); | ||
|
||
FILE * file = fopen( path.data(), "wb" ); | ||
if( !file ) | ||
throw imageException( "Cannot create file for saving" ); | ||
|
||
png_structp png = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); | ||
if( !png ) | ||
throw imageException( "Cannot create file for saving" ); | ||
|
||
png_infop info = png_create_info_struct( png ); | ||
if( !info ) | ||
throw imageException( "Cannot create file for saving" ); | ||
|
||
png_init_io( png, file ); | ||
|
||
// Output is 8bit depth, RGBA format | ||
png_set_IHDR( png, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, | ||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); | ||
|
||
png_write_info( png, info ); | ||
|
||
uint8_t ** row_pointers = reinterpret_cast<uint8_t**>( malloc( sizeof( uint8_t* ) * height ) ); | ||
|
||
const size_t rowByteCount = png_get_rowbytes( png, info ); | ||
|
||
for( uint32_t y = 0; y < height; ++y ) | ||
row_pointers[y] = reinterpret_cast<uint8_t*>( malloc( rowByteCount ) ); | ||
|
||
const bool grayScaleImage = image.colorCount() == Bitmap_Image::GRAY_SCALE; | ||
|
||
const uint8_t * outY = image.data() + startY * image.rowSize() + startX * image.colorCount(); | ||
for( uint32_t y = 0; y < height; ++y, outY += image.rowSize() ) { | ||
|
||
uint8_t * column = row_pointers[y]; | ||
const uint8_t * outX = outY; | ||
|
||
if( grayScaleImage ) | ||
{ | ||
for( uint32_t x = 0; x < width; ++x, column += 4 ) { | ||
column[0] = column[1] = column[2] = *(outX++); | ||
column[3] = 255; | ||
} | ||
} | ||
else | ||
{ | ||
for( uint32_t x = 0; x < width; ++x, column += 4 ) { | ||
column[2] = *(outX++); | ||
column[1] = *(outX++); | ||
column[0] = *(outX++); | ||
column[3] = 255; | ||
} | ||
} | ||
} | ||
|
||
png_write_image( png, row_pointers ); | ||
png_write_end( png, NULL ); | ||
|
||
fclose( file ); | ||
|
||
for( uint32_t y = 0; y < height; ++y ) | ||
free( row_pointers[y] ); | ||
free( row_pointers ); | ||
|
||
png_destroy_write_struct( &png, &info ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#include "../image_buffer.h" | ||
|
||
namespace Png_Operation | ||
{ | ||
// Below functions support only Bitmap_Image::Image and Bitmap_Image::ColorImage classes | ||
Bitmap_Image::Image Load( const std::string & path ); | ||
void Load( const std::string & path, Bitmap_Image::Image & image ); | ||
|
||
void Save( const std::string & path, const Bitmap_Image::Image & image ); | ||
void Save( const std::string & path, const Bitmap_Image::Image & image, uint32_t startX, uint32_t startY, | ||
uint32_t width, uint32_t height ); | ||
} |