1 //
2 // Copyright (C) 1999-2002 Toshikaz Hirabayashi
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 // SOFTWARE.
21 //
22 // Except as contained in this notice, the name of Toshikaz Hirabayashi shall
23 // not be used in advertising or otherwise to promote the sale, use or other
24 // dealings in this Software without prior written authorization from
25 // Toshikaz Hirabayashi.
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <unistd.h>
32
33 #include <png.h>
34 extern long PngReadFileToPixmap(Display* display,Window window,GC gc,
35 char* filename,Pixmap* pixmap,long* w,long* h);
36
png_cexcept_error(png_structp png_ptr,png_const_charp msg)37 void png_cexcept_error(png_structp png_ptr, png_const_charp msg){
38 if(png_ptr){
39 fprintf(stderr, "png file read error: %s\n", msg);
40 }
41 }
42
PngReadFileToPixmap(Display * display,Window window,GC gc,char * filename,Pixmap * pixmap,long * w,long * h)43 long PngReadFileToPixmap(Display* display,Window window,GC gc,char* filename,Pixmap* pixmap,long* w,long* h){
44
45 int red_mask, green_mask, blue_mask;
46 int red_shift, green_shift, blue_shift;
47 int start_shift, msb_flag;
48 unsigned int start_mask, udat;
49 XWindowAttributes win_attr;
50 FILE* ifile;
51 long display_depth;
52 png_byte sig[8];
53 png_infop info_ptr;
54 png_structp png_ptr;
55 png_uint_32 png_width;
56 png_uint_32 png_height;
57 int png_depth;
58 int png_color_type;
59 png_uint_32 png_row_bytes;
60 png_uint_32 png_channels;
61 long rwidth;
62 long rheight;
63 long components;
64 unsigned char* buf;
65 png_byte** png_row_ptrs;
66 long vwidth;
67 long vheight;
68 long stretched;
69 XImage* image;
70 Visual* visual;
71 Pixmap pix;
72 int i;
73 char* data1;
74 unsigned char r,g,b;
75 long ptr = 0;
76 long ptr2 = 0;
77 long j;
78
79 red_mask = green_mask = blue_mask = 0;
80 red_shift = green_shift = blue_shift = 0;
81
82 ifile = fopen(filename,"r");
83 if (ifile == NULL){
84 return -1;
85 }
86 display_depth = XDefaultDepth(display,XDefaultScreen(display));
87
88 fread(sig, 1, 8, ifile);
89 if (!png_check_sig(sig, 8)){
90 fclose(ifile);
91 return -1;
92 }
93 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
94 (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
95 if (png_ptr == NULL){
96 fclose(ifile);
97 return -1;
98 }
99 info_ptr = png_create_info_struct(png_ptr);
100 if (info_ptr == NULL){
101 png_destroy_read_struct(&png_ptr, NULL, NULL);
102 fclose(ifile);
103 return -1;
104 }
105
106 png_init_io(png_ptr, ifile);
107 png_set_sig_bytes(png_ptr, 8);
108 png_read_info(png_ptr, info_ptr);
109 png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &png_depth,
110 &png_color_type, NULL, NULL, NULL);
111 if (png_depth == 16){
112 png_set_strip_16(png_ptr);
113 }
114 png_row_bytes = png_get_rowbytes(png_ptr, info_ptr);
115 png_channels = png_get_channels(png_ptr, info_ptr);
116
117 if (png_depth < 8){
118 if (png_color_type == PNG_COLOR_TYPE_GRAY ){
119 png_set_gray_1_2_4_to_8(png_ptr);
120 png_row_bytes = png_width;
121 }else{
122 png_set_expand(png_ptr);
123 png_row_bytes = png_width;
124 png_row_bytes = png_width * 3;
125 png_channels = 3;
126 }
127 }
128 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
129 png_set_expand(png_ptr);
130 png_row_bytes = png_width;
131 }
132 if (png_color_type == PNG_COLOR_TYPE_GRAY ||
133 png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
134 png_set_gray_to_rgb(png_ptr);
135 png_row_bytes = png_width;
136 }
137
138 if (png_color_type == PNG_COLOR_TYPE_PALETTE){
139 png_set_palette_to_rgb(png_ptr);
140 png_row_bytes = png_width * 3;
141 png_channels = 3;
142 }
143
144 rwidth = png_width;
145 rheight = png_height;
146 components = png_channels;
147
148 buf = malloc(png_row_bytes * png_height * sizeof(png_byte));
149 if (buf == NULL){
150 fprintf(stderr,"png read error: out of memory..\n");
151 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
152 fclose(ifile);
153 return -1;
154 }
155 png_row_ptrs = malloc (sizeof(png_bytep)*png_height);
156 if (png_row_ptrs == NULL){
157 fprintf(stderr,"png read error: out of memory..\n");
158 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
159 fclose(ifile);
160 return -1;
161 }
162
163 for(i = 0; i < (int)png_height; i++){
164 png_row_ptrs[i] = (png_byte*)(buf + i * png_row_bytes);
165 }
166 png_read_image(png_ptr, png_row_ptrs);
167 png_read_end(png_ptr,NULL);
168 free(png_row_ptrs);
169
170 vwidth = *w;
171 vheight = *h;
172 stretched =0;
173 if (*w == 0 || *h == 0){
174 *w = rwidth;
175 *h = rheight;
176 }else{
177 if ((long)((double)rwidth * vheight/vwidth) < rheight){
178 *w = (long)((double)vheight * rwidth/rheight);
179 }else{
180 *h = (long)((double)vwidth * rheight/rwidth);
181 }
182 stretched = 1;
183 }
184 vwidth = *w;
185 vheight = *h;
186
187
188
189 image = 0;
190 visual = XDefaultVisual(display,XDefaultScreen(display));
191 if (display_depth >16){
192 image = XCreateImage(display,visual, display_depth,
193 ZPixmap,0,0,vwidth,vheight,32,0);
194 }else
195 if (display_depth >8){
196 image = XCreateImage(display,visual, display_depth,
197 ZPixmap,0,0,vwidth,vheight,16,0);
198 }else{
199 image = XCreateImage(display,visual, display_depth,
200 ZPixmap,0,0,vwidth,vheight,8,0);
201 }
202
203 msb_flag = (ImageByteOrder(display) == MSBFirst)?1:0;
204
205 if (XGetWindowAttributes(display,
206 RootWindow(display, DefaultScreen(display)),
207 &win_attr) == 0) {
208 fclose(ifile);
209 return -1;
210 }
211 //
212 if ((win_attr.depth == 24) || (win_attr.depth == 16)) {
213 unsigned int n;
214 if (win_attr.depth == 24) {
215 start_shift = 24;
216 start_mask = 0x80000000;
217 }else{
218 start_shift = 8;
219 start_mask = 0x8000;
220 }
221 red_mask = win_attr.visual->red_mask;
222 red_shift = start_shift;
223 n = start_mask;
224 while (!(n & red_mask)) {
225 n >>= 1;
226 red_shift--;
227 }
228 green_mask = win_attr.visual->green_mask;
229 green_shift = start_shift;
230 n = start_mask;
231 while (!(n & green_mask)) {
232 n >>= 1;
233 green_shift--;
234 }
235 blue_mask = win_attr.visual->blue_mask;
236 blue_shift = start_shift;
237 n = start_mask;
238 while (!(n & blue_mask)) {
239 n >>= 1;
240 blue_shift--;
241 }
242 }
243
244 data1 = malloc(image->bytes_per_line * vheight);
245 if (image->bits_per_pixel ==32){
246 if (components == 3 || components == 4){
247 for(i=0; i<vheight; i++){
248 for(j=0; j<vwidth; j++){
249 if (stretched != 0){
250 ptr = (long)((double)i*rheight/vheight)*rwidth
251 + (long)((double)j*rwidth/vwidth);
252 ptr *= 3;
253 }
254 r = buf[ptr++];
255 g = buf[ptr++];
256 b = buf[ptr++];
257 if (components == 4){
258 ptr++;
259 }
260 udat = 0;
261 if (red_shift >= 0){
262 udat |= (((int)r << red_shift) & red_mask);
263 }else{
264 udat |= (((int)r >> (-red_shift)) & red_mask);
265 }
266 if (green_shift >= 0){
267 udat |= (((int)g << green_shift) & green_mask);
268 }else{
269 udat |= (((int)g >> (-green_shift)) & green_mask);
270 }
271 if (blue_shift >= 0){
272 udat |= (((int)b << blue_shift) & blue_mask);
273 }else{
274 udat |= (((int)b >> (-blue_shift)) & blue_mask);
275 }
276 if (msb_flag){
277 ((unsigned char*)data1)[ptr2++] = (udat & 0xff000000)>>24;
278 ((unsigned char*)data1)[ptr2++] = (udat & 0xff0000)>>16;
279 ((unsigned char*)data1)[ptr2++] = (udat & 0xff00)>>8;
280 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
281 }else{
282 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
283 ((unsigned char*)data1)[ptr2++] = (udat & 0xff00)>>8;
284 ((unsigned char*)data1)[ptr2++] = (udat & 0xff0000)>>16;
285 ((unsigned char*)data1)[ptr2++] = (udat & 0xff000000)>>24;
286 }
287 }
288 }
289 }else{
290 for(i=0; i<vheight; i++){
291 for(j=0; j<vwidth; j++){
292 if (stretched != 0){
293 ptr = (long)((double)i*rheight/vheight)*rwidth
294 + (long)((double)j*rwidth/vwidth);
295 }
296 r = buf[ptr];
297 g = buf[ptr];
298 b = buf[ptr++];
299 if (msb_flag){
300 ((unsigned char*)data1)[ptr2++] = 0;
301 ((unsigned char*)data1)[ptr2++] = b;
302 ((unsigned char*)data1)[ptr2++] = g;
303 ((unsigned char*)data1)[ptr2++] = r;
304 }else{
305 ((unsigned char*)data1)[ptr2++] = r;
306 ((unsigned char*)data1)[ptr2++] = g;
307 ((unsigned char*)data1)[ptr2++] = b;
308 ((unsigned char*)data1)[ptr2++] = 0;
309 }
310 }
311 }
312 }
313 }else if (image->bits_per_pixel == 24){
314 if (components == 3 || components == 4){
315 for(i=0; i<vheight; i++){
316 ptr2 = i * image->bytes_per_line;
317 for(j=0; j<vwidth; j++){
318 if (stretched != 0){
319 ptr = (long)((double)i*rheight/vheight)*rwidth
320 + (long)((double)j*rwidth/vwidth);
321 ptr *= 3;
322 }
323 r = buf[ptr++];
324 g = buf[ptr++];
325 b = buf[ptr++];
326 if (components == 4){
327 ptr++;
328 }
329
330 udat = 0;
331 if (red_shift >= 0){
332 udat |= (((int)r << red_shift) & red_mask);
333 }else{
334 udat |= (((int)r >> (-red_shift)) & red_mask);
335 }
336 if (green_shift >= 0){
337 udat |= (((int)g << green_shift) & green_mask);
338 }else{
339 udat |= (((int)g >> (-green_shift)) & green_mask);
340 }
341 if (blue_shift >= 0){
342 udat |= (((int)b << blue_shift) & blue_mask);
343 }else{
344 udat |= (((int)b >> (-blue_shift)) & blue_mask);
345 }
346
347 if (msb_flag){
348 ((unsigned char*)data1)[ptr2++] = (udat & 0xff0000)>>16;
349 ((unsigned char*)data1)[ptr2++] = (udat & 0xff00)>>8;
350 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
351 }else{
352 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
353 ((unsigned char*)data1)[ptr2++] = (udat & 0xff00)>>8;
354 ((unsigned char*)data1)[ptr2++] = (udat & 0xff0000)>>16;
355 }
356 }
357 }
358 }else{
359 for(i=0; i<vheight; i++){
360 for(j=0; j<vwidth; j++){
361 if (stretched != 0){
362 ptr = (long)((double)i*rheight/vheight)*rwidth
363 + (long)((double)j*rwidth/vwidth);
364 }
365 r = buf[ptr];
366 g = buf[ptr];
367 b = buf[ptr++];
368 if (msb_flag){
369 ((unsigned char*)data1)[ptr2++] = b;
370 ((unsigned char*)data1)[ptr2++] = g;
371 ((unsigned char*)data1)[ptr2++] = r;
372 }else{
373 ((unsigned char*)data1)[ptr2++] = r;
374 ((unsigned char*)data1)[ptr2++] = g;
375 ((unsigned char*)data1)[ptr2++] = b;
376 }
377 }
378 }
379 }
380 }else if (image->bits_per_pixel ==16){
381 if (components == 3 || components == 4){
382 for(i=0; i<vheight; i++){
383 for(j=0; j<vwidth; j++){
384 unsigned int rr,gg,bb;
385 if (stretched != 0){
386 ptr = (long)((double)i*rheight/vheight+0.5)*rwidth
387 + (long)((double)j*rwidth/vwidth + 0.5);
388 ptr *= 3;
389 }
390 rr = buf[ptr++];
391 gg = buf[ptr++];
392 bb = buf[ptr++];
393 if (components == 4){
394 ptr++;
395 }
396
397 udat = 0;
398 if (red_shift >= 0){
399 udat |= (((int)rr << red_shift) & red_mask);
400 }else{
401 udat |= (((int)rr >> (-red_shift)) & red_mask);
402 }
403 if (green_shift >= 0){
404 udat |= (((int)gg << green_shift) & green_mask);
405 }else{
406 udat |= (((int)gg >> (-green_shift)) & green_mask);
407 }
408 if (blue_shift >= 0){
409 udat |= (((int)bb << blue_shift) & blue_mask);
410 }else{
411 udat |= (((int)bb >> (-blue_shift)) & blue_mask);
412 }
413 if (msb_flag){
414 ((unsigned char*)data1)[ptr2++] = (udat >> 8) & 0xff;
415 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
416 }else{
417 ((unsigned char*)data1)[ptr2++] = (udat & 0xff);
418 ((unsigned char*)data1)[ptr2++] = (udat & 0xff00)>>8;
419 }
420 }
421 }
422 }else{
423 for(i=0; i<vheight; i++){
424 for(j=0; j<vwidth; j++){
425 if (stretched != 0){
426 ptr = (long)((double)i*rheight/vheight)*rwidth
427 + (long)((double)j*rwidth/vwidth);
428 }
429 r = buf[ptr]>>3;
430 g = buf[ptr]>>2;
431 b = buf[ptr++]>>3;
432 ((short*)data1)[ptr2++] = r <<11 | g<<5 | b;
433 }
434 }
435 }
436 }else if (image->bits_per_pixel == 8){
437 //printf("components=%d\n",components);
438 XColor col[5*5*5];
439 Colormap cm = DefaultColormap(display,DefaultScreen(display));
440 long k;
441 long cnt=0;
442 long colptr = 0;
443 long rr = 0,gg = 0,bb = 0;
444 long tr1,tg1,tb1;
445 signed char dr1,dg1,db1;
446 for(i=0; i<5; i++){
447 for(j=0; j<5; j++){
448 for(k=0; k<5; k++){
449 if (i != 4){
450 col[cnt].red = i*64*256;
451 }else{
452 col[cnt].red = 0xffff;
453 }
454 if (j != 4){
455 col[cnt].green = j*64*256;
456 }else{
457 col[cnt].green = 0xffff;
458 }
459 if (k != 4){
460 col[cnt].blue = k*64*256;
461 }else{
462 col[cnt].blue = 0xffff;
463 }
464 XAllocColor(display,cm,&(col[cnt]));
465 cnt++;
466 }
467 }
468 }
469
470 for(i=0; i<vheight; i++){
471 dr1 = 0;
472 dg1 = 0;
473 db1 = 0;
474 for(j=0; j<vwidth; j++){
475
476 if (components == 3 || components== 4){
477 if (stretched != 0){
478 ptr = (long)((double)i*rheight/vheight)*rwidth
479 + (long)((double)j*rwidth/vwidth);
480 ptr *= 3;
481 }
482 tr1 = buf[ptr++];
483 tg1 = buf[ptr++];
484 tb1 = buf[ptr++];
485 if (components == 4){
486 ptr++;
487 }
488 }else{
489 ptr = (long)((double)i*rheight/vheight)*rwidth
490 + (long)((double)j*rwidth/vwidth);
491 tr1 = buf[ptr];
492 tg1 = buf[ptr];
493 tb1 = buf[ptr++];
494 }
495 if ((0 < tr1 + dr1) && (tr1 + dr1) < 256){
496 if ((-32 < dr1) && (dr1 < 32)){
497 rr = (tr1 + dr1 + 31) & 0x1c0;
498 }else if (dr1 > 31){
499 rr = (tr1 + 63) & 0x1c0;
500 }else{
501 rr = tr1 & 0x1c0;
502 }
503 }else if (tr1 + dr1 > 255){
504 rr = 0x100;
505 }else{
506 rr = 0;
507 }
508 dr1 += (tr1 - rr);
509 if (0 < tg1 + dg1 &&tg1 + dg1 < 256){
510 if (-32 < dg1 && dg1 < 32 ){
511 gg = (tg1 + dg1 + 31) & 0x1c0;
512 }else if (dg1 > 31){
513 gg = (tg1 + 63) & 0x1c0;
514 }else{
515 gg = tg1 & 0x1c0;
516 }
517 }else if (tg1 + dg1 > 255){
518 gg = 0x100;
519 }else{
520 gg = 0;
521 }
522 dg1 += (tg1 - gg);
523
524 if (0 < tb1 + db1 && tb1 + db1 < 256){
525 if (-32 < db1 && db1 < 32){
526 bb = (tb1 + db1 + 31) & 0x1c0;
527 }else if (db1 > 31){
528 bb = (tb1 + 63) & 0x1c0;
529 }else{
530 bb = tb1 & 0x1c0;
531 }
532 }else if (tb1 + db1 > 255){
533 bb = 0x100;
534 }else{
535 bb = 0;
536 }
537 db1 += (tb1 - bb);
538 db1 += (tb1 - bb);
539 colptr = (rr>>6)*5*5 + (gg>>6)*5 + (bb>>6);
540 data1[ptr2++] = col[colptr].pixel;
541 }
542 }
543 }
544 image->data = data1;
545 free(buf);
546
547 pix = XCreatePixmap(display,window, vwidth,vheight,display_depth);
548 *pixmap = pix;
549 XPutImage(display,pix,gc,image,0,0,0,0,vwidth,vheight);
550
551 if (image->data != NULL){
552 free(image->data);
553 image->data = NULL;
554 }
555 XDestroyImage(image);
556 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
557
558 fclose(ifile);
559 return 0;
560 }
561