#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "png.h" #include #include "BmpIoLib.h" /* Windows setjmp and longjmp don't work by Perl default */ #if defined(_WIN32) || defined(_WIN64) # undef setjmp # undef longjmp # if defined(__MINGW32__) // Copied from MinGW setjmp.h # ifdef _WIN64 # if (__MINGW_GCC_VERSION < 40702) # define setjmp(BUF) _setjmp((BUF), mingw_getsp()) # else # define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0)) # endif # else # define setjmp(BUF) _setjmp3((BUF), NULL) # endif __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); # else # include # endif #endif typedef struct { IBMP* pBmp; } ImagePNGSimple; MODULE = Image::PNG::Simple PACKAGE = Image::PNG::Simple SV new(...) PPCODE: { char* class_name = SvPV_nolen(ST(0)); ImagePNGSimple* ips = (ImagePNGSimple*)malloc(sizeof(ImagePNGSimple)); size_t ips_iv = PTR2IV(ips); SV* ips_sv = sv_2mortal(newSViv(ips_iv)); SV* ips_svrv = sv_2mortal(newRV_inc(ips_sv)); SV* ips_obj = sv_bless(ips_svrv, gv_stashpv(class_name, 1)); XPUSHs(ips_obj); XSRETURN(1); } SV DESTORY(...) PPCODE: { SV* ips_obj = ST(0); SV* ips_sv = SvROK(ips_obj) ? SvRV(ips_obj) : ips_obj; size_t ips_iv = SvIV(ips_sv); ImagePNGSimple* ips = INT2PTR(ImagePNGSimple*, ips_iv); if (ips->pBmp != NULL) { free(ips->pBmp); } free(ips); XSRETURN(0); } SV read_bmp_file(...) PPCODE : { SV* ips_obj = ST(0); SV* ips_sv = SvROK(ips_obj) ? SvRV(ips_obj) : ips_obj; size_t ips_iv = SvIV(ips_sv); ImagePNGSimple* ips = INT2PTR(ImagePNGSimple*, ips_iv); // Open bitmap file SV* sv_file = ST(1); char* file = SvPV_nolen(sv_file); FILE* in_fh = fopen(file, "rb"); if (in_fh == NULL) { croak("Can't open bitmap file %s", file); } // Create bitmap data IBMP *pBmp = BmpIO_Load(in_fh); fclose(in_fh); if (pBmp == NULL) { croak("Can't parse bitmap file %s", file); } ips->pBmp = pBmp; XSRETURN(0); } SV write_bmp_file(...) PPCODE: { SV* ips_obj = ST(0); SV* ips_sv = SvROK(ips_obj) ? SvRV(ips_obj) : ips_obj; size_t ips_iv = SvIV(ips_sv); ImagePNGSimple* ips = INT2PTR(ImagePNGSimple*, ips_iv); // Not exists bitmap data if (ips->pBmp == NULL) { croak("Can't write bitmap because bitmap data is not loaded"); } // Open file for write SV* sv_file = ST(1); char* file = SvPV_nolen(sv_file); FILE* out_fh = fopen(file, "wb" ); if (out_fh == NULL) { croak("Can't open file %s for writing", file); } BmpIO_Save(out_fh, ips->pBmp); fclose(out_fh); XSRETURN(0); } SV write_png_file(...) PPCODE: { SV* ips_obj = ST(0); SV* ips_sv = SvROK(ips_obj) ? SvRV(ips_obj) : ips_obj; size_t ips_iv = SvIV(ips_sv); ImagePNGSimple* ips = INT2PTR(ImagePNGSimple*, ips_iv); // Bitmap information IBMP* pBmp = ips->pBmp; // Not exists bitmap data if (ips->pBmp == NULL) { croak("Can't write bitmap because bitmap data is not loaded"); } // Open file for write SV* sv_file = ST(1); char* file = SvPV_nolen(sv_file); FILE* out_fh = fopen(file, "wb" ); if (out_fh == NULL) { croak("Can't open file %s for writing", file); } // PNG information IV x; IV y; // Create png write struct png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { fclose(out_fh); croak("Fail png_create_write_struct"); } // Create png information png_infop info = png_create_info_struct(png); if (info == NULL) { png_destroy_write_struct(&png, (png_infopp)NULL); fclose(out_fh); croak("Fail png_create_info_struct"); } // Set png error callback png_bytep* lines = NULL; if (setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &info); if (lines != NULL) { free(lines); } fclose(out_fh); croak("libpng internal error"); } // Initialize png IO png_init_io(png, out_fh); // Image width IV bmp_height = BmpIO_GetHeight(pBmp); // Image height IV bmp_width = BmpIO_GetWidth(pBmp); // Set png IHDR IV bit_per_pixcel = BmpIO_GetBitPerPixcel(pBmp); png_set_IHDR(png, info, bmp_width, bmp_height, 8, (bit_per_pixcel == 32 ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); // Set png sbit png_color_8 sBIT; sBIT.red = 8; sBIT.green = 8; sBIT.blue = 8; sBIT.alpha = (png_byte)(bit_per_pixcel == 32 ? 8 : 0); png_set_sBIT(png, info, &sBIT); // Write png information png_write_info(png, info); // Set png bgr png_set_bgr(png); // Set png lines unsigned char* rgb_data = malloc(bmp_height * bmp_width * 3); lines = (png_bytep *)malloc(sizeof(png_bytep *) * bmp_height); for (y = 0; y < bmp_height; y++) { for (x = 0; x < bmp_width; x++) { rgb_data[((bmp_height - y - 1) * bmp_width * 3) + (x * 3)] = BmpIO_GetB(x, y, pBmp); rgb_data[((bmp_height - y - 1) * bmp_width * 3) + (x * 3) + 1] = BmpIO_GetG(x, y, pBmp); rgb_data[((bmp_height - y - 1) * bmp_width * 3) + (x * 3) + 2] = BmpIO_GetR(x, y, pBmp); } lines[y] = (png_bytep)&(rgb_data[y * bmp_width * 3]); } // Write png image png_write_image(png, lines); png_write_end(png, info); png_destroy_write_struct(&png, &info); // Release resource free(lines); free(rgb_data); BmpIO_DeleteBitmap(pBmp); fclose(out_fh); XSRETURN(0); }