diff options
Diffstat (limited to 'src/display/cairo-utils.cpp')
| -rw-r--r-- | src/display/cairo-utils.cpp | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 24a75de4c..8045007e7 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -290,7 +290,7 @@ Pixbuf *Pixbuf::create_from_file(std::string const &fn) if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) { return NULL; } - struct stat stdir; + GStatBuf stdir; int val = g_stat(fn.c_str(), &stdir); if (val == 0 && stdir.st_mode & S_IFDIR){ return NULL; @@ -1321,6 +1321,91 @@ guint32 argb32_from_rgba(guint32 in) return px; } + +/** + * Converts a pixbuf to a PNG data structure. + * For 8-but RGBA png, this is like copying. + * + */ +const guchar* pixbuf_to_png(guchar const**rows, guchar* px, int num_rows, int num_cols, int stride, int color_type, int bit_depth) +{ + int n_fields = 1 + (color_type&2) + (color_type&4)/4; + const guchar* new_data = (const guchar*)malloc((n_fields * bit_depth * num_rows * num_cols)/8 + 64); + char* ptr = (char*) new_data; + int pad=0; //used when we write image data smaller than one byte (for instance in black and white images where 1px = 1bit) + for(int row = 0; row < num_rows; ++row){ + rows[row] = (const guchar*)ptr; + for(int col = 0; col < num_cols; ++col){ + guint32 *pixel = reinterpret_cast<guint32*>(px + row*stride)+col; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + //this part should probably be rewritten as (a tested, working) big endian, using htons() and ntohs() + guint64 a = (*pixel & 0xff000000) >> 24; + guint64 b = (*pixel & 0x00ff0000) >> 16; + guint64 g = (*pixel & 0x0000ff00) >> 8; + guint64 r = (*pixel & 0x000000ff); + + //one of possible rgb to greyscale formulas. This one is called "luminance, "luminosity" or "luma" + guint16 gray = (guint16)((guint32)((0.2126*(r<<24) + 0.7152*(g<<24) + 0.0722*(b<<24)))>>16); + + if (!pad) *((guint64*)ptr)=0; + if (color_type & 2) { //RGB + // for 8bit->16bit transition, I take the FF -> FFFF convention (multiplication by 0x101). + // If you prefer FF -> FF00 (multiplication by 0x100), remove the <<8, <<24, <<40 and <<56 + if (color_type & 4) { //RGBA + if (bit_depth==8) + *((guint32*)ptr) = *pixel; + else + *((guint64*)ptr) = (guint64)((a<<56)+(a<<48)+(b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+(r)); + } + else{ //no alpha + if(bit_depth==8) + *((guint32*)ptr) = ((*pixel)<<8)>>8; + else + *((guint64*)ptr) = (guint64)((b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+r); + } + } else { //Grayscale + if(bit_depth==16) + *(guint16*)ptr= ((gray & 0xff00)>>8) + ((gray &0x00ff)<<8); + else *((guint16*)ptr) += guint16(((gray >> (16-bit_depth))<<pad) ); //note the "+=" + + if(color_type & 4) { //Alpha channel + if (bit_depth == 16) + *((guint32*)(ptr+2)) = a + (a<<8); + else + *((guint32*)(ptr)) += guint32((a << 8) >> (16 - bit_depth))<<(bit_depth + pad); + } + } + +#else + // I don't have any access to a big-endian machine to test this. It should still work with default export settings. + guint64 r = (*pixel & 0xff000000) >> 24; + guint64 g = (*pixel & 0x00ff0000) >> 16; + guint64 b = (*pixel & 0x0000ff00) >> 8; + guint64 a = (*pixel & 0x000000ff); + guint32 gray = (guint32)(0.2126*(r<<24) + 0.7152*(g<<24) + 0.0722*(b<<24)); + if(color_type & 2){ + if(bit_depth==8)*ptr = *pixel; else *ptr = (guint64)((r<<56)+(g<<40)+(b<<24)+(a<<8)); + } else { + *((guint32*)ptr) += guint32(gray>>pad); + if(color_type & 4) *((guint32*)ptr) += guint32((a>>pad)>> bit_depth); + } +#endif + pad+=bit_depth*n_fields; + ptr+=(pad/8); + pad%=8; + } + if(pad){pad=0;ptr++;}//align bytes on rows + } + return new_data; +} + + + + + + + + /* Local Variables: mode:c++ |
