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