// // Expands RGB to ARGB allocating new buffer for it. // static gpointer expand_rgb_to_argb (MoonPixbuf *pixbuf) { guchar *pb_pixels = pixbuf->GetPixels (); guchar *p; int w = pixbuf->GetWidth (); int h = pixbuf->GetHeight (); int stride = w * 4; guchar *data = (guchar *) g_malloc (stride * h); guchar *out; for (int y = 0; y < h; y ++) { p = pb_pixels + y * pixbuf->GetRowStride (); out = data + y * (stride); for (int x = 0; x < w; x ++) { guchar r, g, b; get_pixel_bgr_p (p, b, g, r); set_pixel_bgra (out, 0, r, g, b, 255); p += 3; out += 4; } } return (gpointer) data; }
// // Converts RGBA unmultiplied alpha to ARGB pre-multiplied alpha. // static gpointer premultiply_rgba (MoonPixbuf *pixbuf) { guchar *pb_pixels = pixbuf->GetPixels (); guchar *p; int w = pixbuf->GetWidth (); int h = pixbuf->GetHeight (); int stride = w * 4; guchar *data = (guchar *) g_malloc (stride * h); guchar *out; for (int y = 0; y < h; y ++) { p = pb_pixels + y * pixbuf->GetRowStride (); out = data + y * (stride); for (int x = 0; x < w; x ++) { guchar r, g, b, a; get_pixel_bgra (p, b, g, r, a); /* pre-multipled alpha */ if (a == 0) { r = g = b = 0; } else if (a < 255) { r = pre_multiplied_table [r][a]; g = pre_multiplied_table [g][a]; b = pre_multiplied_table [b][a]; } /* store it back, swapping red and blue */ set_pixel_bgra (out, 0, r, g, b, a); p += 4; out += 4; } } return (gpointer) data; }
static GpStatus gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc, GpImage **image) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info_ptr = NULL; BYTE *rawdata = NULL; GpImage *result = NULL; GpStatus status = InvalidParameter; int bit_depth; int channels; BYTE color_type; png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { goto error; } if (setjmp(png_jmpbuf(png_ptr))) { /* png detected error occured */ goto error; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { goto error; } end_info_ptr = png_create_info_struct (png_ptr); if (end_info_ptr == NULL) { goto error; } if (fp != NULL) { png_init_io (png_ptr, fp); } else { png_set_read_fn (png_ptr, getBytesFunc, _gdip_png_stream_read_data); } png_read_png (png_ptr, info_ptr, 0, NULL); bit_depth = png_get_bit_depth (png_ptr, info_ptr); channels = png_get_channels (png_ptr, info_ptr); color_type = png_get_color_type (png_ptr, info_ptr); /* 2bpp is a special case (promoted to 32bpp ARGB by MS GDI+) */ if ((bit_depth <= 8) && (bit_depth != 2) && (channels == 1) && ((color_type == PNG_COLOR_TYPE_PALETTE) || (color_type == PNG_COLOR_TYPE_GRAY))) { int width; int height; int source_stride; int dest_stride; png_bytep *row_pointers; BYTE *rawptr; int num_colours; int palette_entries; ColorPalette *palette; ImageFlags colourspace_flag; int i; int j; width = png_get_image_width (png_ptr, info_ptr); height = png_get_image_height (png_ptr, info_ptr); source_stride = (width * bit_depth + 7) / 8; dest_stride = source_stride; gdip_align_stride (dest_stride); /* Copy image data. */ row_pointers = png_get_rows (png_ptr, info_ptr); rawdata = GdipAlloc(dest_stride * height); for (i=0; i < height; i++) { memcpy (rawdata + i * dest_stride, row_pointers[i], source_stride); } /* Copy palette. */ num_colours = 1 << bit_depth; if (png_get_color_type (png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) { /* A gray-scale image; generate a palette fading from black to white. */ colourspace_flag = ImageFlagsColorSpaceGRAY; palette = gdip_create_greyscale_palette (num_colours); palette->Flags = PaletteFlagsGrayScale; } else { /* Copy the palette data into the GDI+ structure. */ colourspace_flag = ImageFlagsColorSpaceRGB; palette_entries = num_colours; if (palette_entries > info_ptr->num_palette) { palette_entries = info_ptr->num_palette; } palette = GdipAlloc (sizeof(ColorPalette) + (num_colours - 1) * sizeof(ARGB)); palette->Flags = 0; palette->Count = num_colours; for (i=0; i < palette_entries; i++) { set_pixel_bgra (&palette->Entries[i], 0, info_ptr->palette[i].blue, info_ptr->palette[i].green, info_ptr->palette[i].red, 0xFF); /* alpha */ } } /* Make sure transparency is respected. */ if (info_ptr->num_trans > 0) { palette->Flags |= PaletteFlagsHasAlpha; colourspace_flag |= ImageFlagsHasAlpha; if (info_ptr->num_trans > info_ptr->num_palette) { info_ptr->num_trans = info_ptr->num_palette; } for (i=0; i < info_ptr->num_trans; i++) { set_pixel_bgra(&palette->Entries[i], 0, info_ptr->palette[i].blue, info_ptr->palette[i].green, info_ptr->palette[i].red, #if PNG_LIBPNG_VER > 10399 info_ptr->trans_alpha [i]); /* alpha */ #else info_ptr->trans[i]); /* alpha */ #endif } }