summaryrefslogtreecommitdiffstats
path: root/src/display/cairo-utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/cairo-utils.cpp')
-rw-r--r--src/display/cairo-utils.cpp86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 24a75de4c..a7625f4a1 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -13,6 +13,7 @@
#endif
#include "display/cairo-utils.h"
+#include <arpa/inet.h>
#include <stdexcept>
#include <glib/gstdio.h>
@@ -1321,6 +1322,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++