Real-time dock left-right swapping
[wmaker-crm.git] / wrlib / png.c
blobe28d7304d238e80ccfdeed0ceabc9664b10dd33c
1 /* png.c - load PNG image from file
3 * Raster graphics library
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
23 #include <config.h>
25 #ifdef USE_PNG
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
31 #include <png.h>
33 #include "wraster.h"
35 RImage *RLoadPNG(RContext * context, char *file)
37 char *tmp;
38 RImage *image = NULL;
39 FILE *f;
40 png_structp png;
41 png_infop pinfo, einfo;
42 png_color_16p bkcolor;
43 int alpha;
44 int x, y, i;
45 double gamma, sgamma;
46 png_uint_32 width, height;
47 int depth, junk, color_type;
48 png_bytep *png_rows;
49 unsigned char *ptr;
51 f = fopen(file, "rb");
52 if (!f) {
53 RErrorCode = RERR_OPEN;
54 return NULL;
56 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) NULL, (png_error_ptr) NULL);
57 if (!png) {
58 RErrorCode = RERR_NOMEMORY;
59 fclose(f);
60 return NULL;
63 pinfo = png_create_info_struct(png);
64 if (!pinfo) {
65 RErrorCode = RERR_NOMEMORY;
66 fclose(f);
67 png_destroy_read_struct(&png, NULL, NULL);
68 return NULL;
71 einfo = png_create_info_struct(png);
72 if (!einfo) {
73 RErrorCode = RERR_NOMEMORY;
74 fclose(f);
75 png_destroy_read_struct(&png, &pinfo, NULL);
76 return NULL;
79 RErrorCode = RERR_INTERNAL;
80 #if PNG_LIBPNG_VER - 0 < 10400
81 if (setjmp(png->jmpbuf)) {
82 #else
83 if (setjmp(png_jmpbuf(png))) {
84 #endif
85 fclose(f);
86 png_destroy_read_struct(&png, &pinfo, &einfo);
87 if (image)
88 RReleaseImage(image);
89 return NULL;
92 png_init_io(png, f);
94 png_read_info(png, pinfo);
96 png_get_IHDR(png, pinfo, &width, &height, &depth, &color_type, &junk, &junk, &junk);
98 /* sanity check */
99 if (width < 1 || height < 1) {
100 fclose(f);
101 png_destroy_read_struct(&png, &pinfo, &einfo);
102 RErrorCode = RERR_BADIMAGEFILE;
103 return NULL;
106 /* check for an alpha channel */
107 if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
108 alpha = True;
109 else
110 alpha = (color_type & PNG_COLOR_MASK_ALPHA);
112 /* allocate RImage */
113 image = RCreateImage(width, height, alpha);
114 if (!image) {
115 fclose(f);
116 png_destroy_read_struct(&png, &pinfo, &einfo);
117 return NULL;
120 /* normalize to 8bpp with alpha channel */
121 if (color_type == PNG_COLOR_TYPE_PALETTE && depth <= 8)
122 png_set_expand(png);
124 if (color_type == PNG_COLOR_TYPE_GRAY && depth <= 8)
125 png_set_expand(png);
127 if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
128 png_set_expand(png);
130 if (depth == 16)
131 png_set_strip_16(png);
133 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
134 png_set_gray_to_rgb(png);
136 /* set gamma correction */
137 if ((context->attribs->flags & RC_GammaCorrection)
138 && context->depth != 8) {
139 sgamma = (context->attribs->rgamma + context->attribs->ggamma + context->attribs->bgamma) / 3;
140 } else if ((tmp = getenv("DISPLAY_GAMMA")) != NULL) {
141 sgamma = atof(tmp);
142 if (sgamma == 0)
143 sgamma = 1;
144 } else {
145 /* blah */
146 sgamma = 2.2;
149 if (png_get_gAMA(png, pinfo, &gamma))
150 png_set_gamma(png, sgamma, gamma);
151 else
152 png_set_gamma(png, sgamma, 0.45);
154 /* do the transforms */
155 png_read_update_info(png, pinfo);
157 /* set background color */
158 if (png_get_bKGD(png, pinfo, &bkcolor)) {
159 image->background.red = bkcolor->red >> 8;
160 image->background.green = bkcolor->green >> 8;
161 image->background.blue = bkcolor->blue >> 8;
164 png_rows = calloc(height, sizeof(char *));
165 if (!png_rows) {
166 RErrorCode = RERR_NOMEMORY;
167 fclose(f);
168 RReleaseImage(image);
169 png_destroy_read_struct(&png, &pinfo, &einfo);
170 return NULL;
172 for (y = 0; y < height; y++) {
173 png_rows[y] = malloc(png_get_rowbytes(png, pinfo));
174 if (!png_rows[y]) {
175 RErrorCode = RERR_NOMEMORY;
176 fclose(f);
177 RReleaseImage(image);
178 png_destroy_read_struct(&png, &pinfo, &einfo);
179 while (y-- > 0)
180 if (png_rows[y])
181 free(png_rows[y]);
182 free(png_rows);
183 return NULL;
186 /* read data */
187 png_read_image(png, png_rows);
189 png_read_end(png, einfo);
191 png_destroy_read_struct(&png, &pinfo, &einfo);
193 fclose(f);
195 ptr = image->data;
197 /* convert to RImage */
198 if (alpha) {
199 for (y = 0; y < height; y++) {
200 for (x = 0, i = width * 4; x < i; x++, ptr++) {
201 *ptr = *(png_rows[y] + x);
204 } else {
205 for (y = 0; y < height; y++) {
206 for (x = 0, i = width * 3; x < i; x++, ptr++) {
207 *ptr = *(png_rows[y] + x);
211 for (y = 0; y < height; y++)
212 if (png_rows[y])
213 free(png_rows[y]);
214 free(png_rows);
215 return image;
218 #endif /* USE_PNG */