Created
October 17, 2015 14:02
-
-
Save MikuAuahDark/0a716b3e7bad6e2c9542 to your computer and use it in GitHub Desktop.
Crop PNG from 0x0 to specificed pixel
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
#include <iostream> | |
#include <string> | |
#include <cstdarg> | |
#include <png.h> | |
using namespace std; | |
// Prints message in stderr and exit program in release build. | |
// In debug build, it trigger debug breakpoint instead. | |
void failexit(const char* file,const char* msg) { | |
if(file) | |
cerr << "Cannot process " << file << ": "; | |
cerr << msg << endl; | |
#ifdef _DEBUG | |
__debugbreak(); | |
#endif | |
exit(-1); | |
} | |
// Same as failexit, except second argument is formatted string like printf instead. | |
void failexitf(const char* file,const char* msg,...) { | |
if(file) | |
cerr << "Cannot process " << file << ": "; | |
va_list a; | |
va_start(a,msg); | |
vfprintf(stderr,msg,a); | |
va_end(a); | |
cerr << endl; | |
#ifdef _DEBUG | |
__debugbreak(); | |
#endif | |
exit(-1); | |
} | |
int main(int argc,char** argv) { | |
png_byte** buffer1; // Reading | |
png_byte** buffer2; // Writing | |
png_byte* tmpbuf; | |
if(argc<4) { | |
cout << "Usage: " << argv[0] << " <in png> <crop x> <crop y> [out png=<in png>]" << endl; | |
cout << "Crops PNG from 0x0 to <crop x>x<crop y>" << endl; | |
cout << "Starting crop position can be changed with PNGCROP_SX and PNGCROP_SY environment variables" << endl; | |
return 1; | |
} | |
int crop_x,crop_y; | |
int sc_x,sc_y; | |
// get crop pixel | |
try { | |
crop_x=stoi(string(argv[2])); | |
try { | |
crop_y=stoi(string(argv[3])); | |
} catch(...) { | |
failexit(nullptr,"Argument 3 is not a number"); | |
} | |
} catch(...) { | |
failexit(nullptr,"Argument 2 is not a number"); | |
} | |
// get start crop pixel | |
{ | |
char* temp; | |
try { | |
temp=getenv("PNGCROP_SX"); | |
if(temp==nullptr) sc_x=0; | |
else sc_x=stoi(string(temp)); | |
try { | |
temp=getenv("PNGCROP_SY"); | |
if(temp==nullptr) sc_y=0; | |
else sc_y=stoi(string(temp)); | |
} catch(...) { | |
failexit(nullptr,"PNGCROP_SY environment variable is not a number"); | |
} | |
} catch(...) { | |
failexit(nullptr,"PNGCROP_SX environment variable is not a number"); | |
} | |
} | |
int rx=crop_x-sc_x; | |
int ry=crop_y-sc_y; | |
// check values | |
if(crop_x<0 || crop_y<0) | |
failexitf(nullptr,"Argument 2 or 3 is negative. argv[2]=%d, argv[3]=%d",crop_x,crop_y); | |
if(sc_x<0 || sc_y<0) | |
failexitf(nullptr,"PNGCROP_SX(%d) or PNGCROP_SY(%d) environment variable is negative.",sc_x,sc_y); | |
if(rx==0 || ry==0) | |
failexit(nullptr,"Nothing to crop or start crop position is higher than end crop position"); | |
char* file_out=argv[1]; | |
if(argc>=5) | |
file_out=argv[4]; | |
FILE* f=fopen(argv[1],"rb"); | |
if(f==nullptr) { | |
cerr << "Cannot open " << argv[1] << ": " << strerror(errno) << endl; | |
return -1; | |
} | |
tmpbuf=new png_byte[8]; | |
fread(tmpbuf,1,8,f); | |
if(png_sig_cmp(tmpbuf,0,8)) | |
failexit(argv[1],"Invalid PNG"); | |
delete[] tmpbuf; | |
png_struct* png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,nullptr,nullptr,nullptr); | |
if(png_ptr==nullptr) | |
failexit(nullptr,"Cannot create PNG reader structure"); | |
png_info* info_ptr=png_create_info_struct(png_ptr); | |
if(info_ptr==nullptr) | |
failexit(nullptr,"Cannot create PNG info structure"); | |
if(setjmp(png_jmpbuf(png_ptr))) | |
failexit(argv[1],"Error initializing input/output"); | |
png_init_io(png_ptr,f); | |
png_set_sig_bytes(png_ptr,8); | |
png_read_info(png_ptr,info_ptr); | |
unsigned int width=png_get_image_width(png_ptr,info_ptr); | |
unsigned int height=png_get_image_height(png_ptr,info_ptr); | |
unsigned char color_type=png_get_color_type(png_ptr,info_ptr); | |
unsigned char bit_depth=png_get_bit_depth(png_ptr,info_ptr); | |
int number_of_passes=png_set_interlace_handling(png_ptr); | |
// Make sure that our cropped pixel doesn't exceed width and height of the image | |
if(abs(crop_x-sc_x)>=width || abs(crop_y-sc_y)>=height) | |
failexitf(argv[1],"Crop rectangle exceeded width or height. width=%d, height=%d, crop_x=%d, crop_y=%d, sc_x=%d, sc_y=%d",width,height,crop_x,crop_y,sc_x,sc_y); | |
// read png | |
int y=(-1); | |
if(setjmp(png_jmpbuf(png_ptr))) | |
failexitf(argv[1],"Error reading at y=%d",y); | |
try { | |
buffer1=new png_byte*[height]; | |
for(y=0;y<height;y++) | |
buffer1[y]=new png_byte[png_get_rowbytes(png_ptr,info_ptr)]; | |
} catch(exception e) { | |
failexit(nullptr,e.what()); | |
} | |
png_read_image(png_ptr,buffer1); | |
// Let's start cropping. | |
int multipler=0; | |
if(color_type==PNG_COLOR_TYPE_RGB) multipler=3; | |
else if(color_type==PNG_COLOR_TYPE_RGBA) multipler=4; | |
else failexit(argv[1],"Unsupported color type"); | |
try { | |
buffer2=new png_byte*[abs(ry)]; | |
for(y=0;y<ry;y++) { | |
buffer2[y]=new png_byte[abs(rx)*multipler]; | |
memcpy(buffer2[y],buffer1[y+sc_y]+sc_x*multipler,rx*multipler); | |
} | |
} catch(exception e) { | |
failexit(nullptr,e.what()); | |
} | |
// Delete & reuse some things | |
png_destroy_read_struct(&png_ptr,&info_ptr,nullptr); | |
fclose(f); | |
f=fopen(file_out,"wb"); | |
if(f==nullptr) { | |
cerr << "Cannot open " << file_out << ": " <<strerror(errno) << endl; | |
cerr << "Writing to stdout instead." << endl; | |
f=stdout; | |
} | |
png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,nullptr,nullptr,nullptr); | |
if(png_ptr==nullptr) | |
failexit(nullptr,"Cannot create PNG writer structure"); | |
info_ptr=png_create_info_struct(png_ptr); | |
if(info_ptr==nullptr) | |
failexit(nullptr,"Cannot create PNG info structure"); | |
if(setjmp(png_jmpbuf(png_ptr))) | |
failexit(file_out,"Error initializing input/output"); | |
png_init_io(png_ptr,f); | |
png_set_IHDR(png_ptr,info_ptr,rx,ry,bit_depth,color_type,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); | |
png_write_info(png_ptr,info_ptr); | |
if(setjmp(png_jmpbuf(png_ptr))) | |
failexit(file_out,"Error writing"); | |
png_write_image(png_ptr,buffer2); | |
if(setjmp(png_jmpbuf(png_ptr))) | |
failexit(file_out,"Error writing at end"); | |
// End | |
png_write_end(png_ptr,info_ptr); | |
png_destroy_write_struct(&png_ptr,&info_ptr); | |
fclose(f); | |
// Free memory | |
for(y=0;y<height;y++) | |
delete[] buffer1[y]; | |
delete[] buffer1; | |
for(y=0;y<ry;y++) | |
delete[] buffer2[y]; | |
delete[] buffer2; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment