1 /* imagewidget.c - for drawing black and white images
2    Copyright (C) 1996-2017 Paul Sheer
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307, USA.
18  */
19 
20 
21 /*general note: widget labels and identifiers are copied from
22    data passed and free'd on widget undraw. */
23 
24 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 
31 #include "stringtools.h"
32 #include "app_glob.c"
33 
34 #include "coolwidget.h"
35 
36 #include "mad.h"
37 
38 
39 #define TPRINTF tiffprintf
40 
41 
grey_scale_to_pixels(void * pixdata,unsigned char * data,int width,int height,int bytedepth)42 void grey_scale_to_pixels (void *pixdata, unsigned char *data, int width, int height, int bytedepth)
43 {
44     long p = width * height - 1;
45     int i;
46     static unsigned long c[256] =
47     {1};
48 
49     u_32bit_t *pixquad = pixdata;
50     word *pixword = pixdata;
51     byte *pixbyte = pixdata;
52 
53     if (*c == 1)
54 	for (i = 0; i < 256; i++)
55 	    c[i] = color_grey (i >> 2);
56 
57     switch (bytedepth) {
58     case 1:
59 	do {
60 	    *(pixbyte + p) = (byte) c[data[p]];
61 	} while (p--);
62 	break;
63     case 2:
64 	do {
65 	    *(pixword + p) = (word) c[data[p]];
66 	} while (p--);
67 	break;
68     case 3:{
69 	    long q = 0;
70 #if THIS_WAY_OR_THAT_WAY==THIS_WAY		/* this code is untested  ************ */
71 	    do {
72 		*(pixbyte++) = (u_32bit_t) c[data[q]];
73 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 8;
74 		*(pixbyte++) = (u_32bit_t) c[data[q++]] >> 16;
75 	    } while (q <= p);
76 #else
77 	    do {
78 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 16;
79 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 8;
80 		*(pixbyte++) = (u_32bit_t) c[data[q++]];
81 	    } while (q <= p);
82 #endif
83 	    break;
84 	}
85     case 4:
86 	do {
87 	    *(pixquad + p) = (u_32bit_t) c[data[p]];
88 	} while (p--);
89 	break;
90     }
91 }
92 
93 
94 
color_8bit_to_pixels(void * pixdata,unsigned char * data,int width,int height,int bytedepth)95 void color_8bit_to_pixels (void *pixdata, unsigned char *data, int width, int height, int bytedepth)
96 {
97     long p = width * height - 1;
98     static unsigned long c[256] =
99     {1};
100     u_32bit_t *pixquad = pixdata;
101     word *pixword = pixdata;
102     byte *pixbyte = pixdata;
103 
104     if (c[0] == 1)
105 	memcpy (c, color_pixels, 256 * sizeof (long));
106 
107     switch (bytedepth) {
108     case 1:
109 	do {
110 	    *(pixbyte + p) = (byte) c[data[p]];
111 	} while (p--);
112 	break;
113     case 2:
114 	do {
115 	    *(pixword + p) = (word) c[data[p]];
116 	} while (p--);
117 	break;
118     case 3:{
119 	    long q = 0;
120 #if THIS_WAY_OR_THAT_WAY==THIS_WAY		/* this code is untested  ************ */
121 	    do {
122 		*(pixbyte++) = (u_32bit_t) c[data[q]];
123 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 8;
124 		*(pixbyte++) = (u_32bit_t) c[data[q++]] >> 16;
125 	    } while (q <= p);
126 #else
127 	    do {
128 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 16;
129 		*(pixbyte++) = (u_32bit_t) c[data[q]] >> 8;
130 		*(pixbyte++) = (u_32bit_t) c[data[q++]];
131 	    } while (q <= p);
132 #endif
133 	    break;
134 	}
135     case 4:
136 	do {
137 	    *(pixquad + p) = (u_32bit_t) c[data[p]];
138 	} while (p--);
139 	break;
140     }
141 }
142 
143 
144 
145 /* width and height refer to the image. 4 pixels will be added on to
146    this for the border */
CDrawBWImage(const char * identifier,Window parent,int x,int y,int width,int height,unsigned char * data)147 CWidget * CDrawBWImage (const char *identifier, Window parent, int x, int y,
148 		       int width, int height, unsigned char *data)
149 {
150     int bytespp = 16;
151     CWidget *w;
152 
153     if (width & 1)
154 	bytespp = 8;
155     if (!(width & 3))
156 	bytespp = 32;
157 
158     w = CSetupWidget (identifier, parent, x, y,
159 			  width + 4, height + 4, C_BWIMAGE_WIDGET, INPUT_MOTION, COLOR_WHITE, 0);
160 
161     w->ximage = XCreateImage (CDisplay, CVisual, CDepth, ZPixmap,
162 				   0, NULL, width, height, bytespp, 0);
163 
164     if (w->ximage == NULL) {
165 	CDestroyWidget(identifier);
166 	CErrorDialog (w->mainid, 20, 20, " CDrawBWImage ", _(" Cannot create Ximage "));
167 	return NULL;
168     }
169 
170     w->ximage->data = CMalloc (width * height * w->ximage->bits_per_pixel / 8 + 4);
171 
172 /*now format the one-byte-per-pixel-is-an-eight-bit-grey-level
173    to a bytedepth-per-pixel-is-an-actual-pixel-value format */
174 /*We shift right by two to bring 0-255 grey-scale down to 0-63 for
175    the coolwidget palette */
176 
177     if (w->ximage->bits_per_pixel % 8)
178 /* Not essential to translate */
179 	CError (_("Non-multiple of 8 bits_per_pixel in XImage not supported.\n"));
180 
181     grey_scale_to_pixels (w->ximage->data, data, width, height, w->ximage->bits_per_pixel / 8);
182 
183     return w;
184 }
185 
186 
187 /*data[] must be 1 byte per pixel. Each pixel is a value between 0
188    and 16+27+64 = 107: 0-16 is widget-cool-colors, 16-42 is 3^3 colors,
189    43-63 is greyscale-colors. */
190 
191 /*width and height refer to the image. 4 pixels will be added on to
192    this for the border */
Cdraw8bitimage(const char * identifier,Window parent,int x,int y,int width,int height,unsigned char * data)193 CWidget * Cdraw8bitimage (const char *identifier, Window parent, int x, int y,
194 			 int width, int height, unsigned char *data)
195 {
196     int bytespp = 16;
197     CWidget *w;
198 
199     if (width & 1)
200 	bytespp = 8;
201     if (!(width & 3))
202 	bytespp = 32;
203 
204     w = CSetupWidget (identifier, parent, x, y,
205 			  width + 4, height + 4, C_8BITIMAGE_WIDGET, INPUT_MOTION, COLOR_WHITE, 0);
206 
207     w->ximage = XCreateImage (CDisplay, CVisual, CDepth, ZPixmap,
208 				   0, NULL, width, height, bytespp, 0);
209 
210     if (w->ximage == NULL) {
211 	CDestroyWidget(identifier);
212 	CErrorDialog (w->mainid, 20, 20, " CDrawBWImage ", _(" Cannot create Ximage "));
213 	return NULL;
214     }
215 
216     w->ximage->data = CMalloc (width * height * w->ximage->bits_per_pixel / 8);
217 
218     if (w->ximage->bits_per_pixel % 8)
219 	CError (_("Non-multiple of 8 bits_per_pixel in XImage not supported.\n"));
220 
221     color_8bit_to_pixels (w->ximage->data, data, width, height, w->ximage->bits_per_pixel / 8);
222 
223     return w;
224 }
225 
226 
render_bw_image(CWidget * wdt,int x,int y,int rendw,int rendh)227 void render_bw_image (CWidget *wdt, int x, int y, int rendw, int rendh)
228 {
229     int w = wdt->width;
230     int h = wdt->height;
231     Window win = wdt->winid;
232     int xim, yim, xwin, ywin;
233 
234     xim = x - 2;
235     yim = y - 2;
236     xwin = x;
237     ywin = y;
238     if (xim < 0) {
239 	rendw += xim;
240 	xim = 0;
241 	xwin = 2;
242     }
243     if (yim < 0) {
244 	rendh += yim;
245 	yim = 0;
246 	ywin = 2;
247     }
248     XPutImage (CDisplay, win, CGC, wdt->ximage,
249 	       xim, yim, xwin, ywin, rendw, rendh);
250 
251     render_bevel (win, 0, 0, w - 1, h - 1, 2, 1);
252 }
253 
254 
255 /*xvtarga.c : */
256 
257 
258 /*This file originally comes from XVIEW version 3.1 image viewing utility.
259    I modified it to my needs. I suppose it isn't really a copyright violation
260    because the targa image file format is really simple --- I just got
261    lazy --- and I've changed the code considerably. Here are the original
262    comments for the file just to acknowledge the help:  */
263 
264 /*
265  * xvtarga.c - load routine for 'targa' format pictures
266  *
267  * written and submitted by:
268  *     Derek Dongray    (dongray@genrad.com)
269  *
270  * The format read/written is actually Targa type 2 uncompressed as
271  * produced by POVray 1.0
272  *
273  * LoadTarga(fname, pinfo)
274  * WriteTarga(fp, pic, ptype, w,h, rmap,gmap,bmap,numcols, cstyle)
275  */
276 
277 
278 /*
279  * Targa Format (near as I can tell)
280  *   0:
281  *   1: colormap type
282  *   2: image type  (1=colmap RGB, 2=uncomp RGB, 3=uncomp gray)
283  *   3:
284  *   4:
285  *   5: colormap_length, low byte
286  *   6: colormap_length, high byte
287  *   7: bits per cmap entry     (8, 24, 32)
288  *
289  *  12: width, low byte
290  *  13: width, high byte
291  *  14: height, low byte
292  *  15: height, high byte
293  *  16: bits per pixel (8, 24)
294  *  17: flags
295  */
296 
297 
tgaerror(const char * errmessage)298 void tgaerror (const char *errmessage)
299 {
300     fprintf (stderr, errmessage);	/*OR for the application: */
301 /*    CError (errmessage); *//********/
302 }
303 
304 
305 /*This loads a targa file and converts it to grey scale if it is color */
306 
307 /*it returns a pointer to the data, which consists of contigous
308    scanlines from the top left. It also returns the width and height.
309    The returned data are 8bpp greyscale.
310    Since load_targa_to_grey mallocs, the returned pointer must be free'd */
311 
312 
load_targa_to_grey(const char * fname,long * width,long * height,long rowstart,long rowend)313 unsigned char *load_targa_to_grey (const char *fname, long *width, long *height, long rowstart, long rowend)
314 {
315     FILE *fp;
316     int i, j, k, row, c, c1, w, h, flags, intlace, topleft, trunc, bytesperpixel;
317     unsigned char *pic8 = NULL, *pp;
318     long filesize;
319 
320     if ((fp = fopen (fname, "r")) == NULL) {
321 /* NLS ? */
322 	tgaerror ("Cannot open targa image file.\n");
323 	return NULL;
324     }
325     /* compute file length */
326     fseek (fp, 0L, 2);
327     filesize = ftell (fp);
328     fseek (fp, 0L, 0);
329 
330     if (filesize < 18) {
331 	fclose (fp);
332 /* NLS ? */
333 	tgaerror ("Targa file is too short.\n");
334 	return NULL;
335     }
336     /* Discard the first few bytes of the file. */
337 
338     for (i = 0; i < 12; i++) {
339 	c = getc (fp);
340     }
341 
342 
343     /* read in header information */
344     c = getc (fp);
345     c1 = getc (fp);
346     w = c1 * 256 + c;
347     *width = w;
348 
349     c = getc (fp);
350     c1 = getc (fp);
351     h = c1 * 256 + c;
352     *height = h;
353 
354     if (rowstart > rowend) {
355 /* NLS ? */
356 	tgaerror ("loadtga2grey called with rowstart > rowend.\n");
357 	return NULL;
358     }
359     if (rowstart > h)
360 	rowstart = h;
361 
362     if (rowstart < 0)
363 	rowstart = 0;
364 
365     if (rowend > h)
366 	rowend = h;
367 
368     if (w < 2 || h < 2) {
369 	fclose (fp);
370 /* NLS ? */
371 	tgaerror ("Error in Targa header (bad image size).\n");
372 	return NULL;
373     }
374     c = getc (fp);
375     if (c != 24 && c != 8) {
376 	fclose (fp);
377 /* NLS ? */
378 	tgaerror ("Unsupported type (not 24-bit or 8-bit)\n");
379 	return NULL;
380     }
381     bytesperpixel = c / 8;
382 
383     flags = getc (fp);
384     topleft = (flags & 0x20) >> 5;
385     intlace = (flags & 0xc0) >> 6;
386 
387     if (intlace && (rowstart || rowend < h || !topleft)) {
388 /* NLS ? */
389 	tgaerror ("Cannot load only a part of an interlaced or inverted tga.\n");
390 	return NULL;
391     }
392     if ((pic8 = malloc ((rowend - rowstart) * w + 1)) == NULL || (pp = malloc (w * 3)) == NULL) {
393 /* NLS ? */
394 	tgaerror ("Cannot allocate memory for tga file.\n");
395 	return NULL;
396     }
397     if (rowstart)
398 	fseek (fp, rowstart * w * bytesperpixel, SEEK_CUR);
399 
400     trunc = 0;
401 
402     /* read the data */
403     for (i = 0; i < rowend - rowstart; i++) {
404 	if (intlace == 2) {	/* four pass interlace */
405 	    if (i < (1 * h) / 4)
406 		row = 4 * i;
407 	    else if (i < (2 * h) / 4)
408 		row = 4 * (i - ((1 * h) / 4)) + 1;
409 	    else if (i < (3 * h) / 4)
410 		row = 4 * (i - ((2 * h) / 4)) + 2;
411 	    else
412 		row = 4 * (i - ((3 * h) / 4)) + 3;
413 	} else if (intlace == 1) {	/* two pass interlace */
414 	    if (i < h / 2)
415 		row = 2 * i;
416 	    else
417 		row = 2 * (i - h / 2) + 1;
418 	} else
419 	    row = i;		/* no interlace */
420 
421 	if (!topleft)
422 	    row = (h - row - 1);	/* bottom-left origin: invert y */
423 
424 	if (bytesperpixel == 3) {
425 	    c = fread (pp, (size_t) 1, (size_t) w * 3, fp);
426 	    if (c != w * 3)
427 		trunc = 1;
428 	    for (j = 0, k = 0; j < w; j++, k += 3)
429 /*luminance transformation: */
430 		pic8[j + row * w] = (int) (11 * pp[k + 2] + 16 * pp[k + 1] + 5 * pp[k]) >> 5;
431 	} else {
432 	    c = fread (pp, (size_t) 1, (size_t) w, fp);
433 	    if (c != w)
434 		trunc = 1;
435 	    for (j = 0; j < w; j++)
436 		pic8[j + row * w] = pp[j];
437 	}
438     }
439 
440     free (pp);
441 
442     if (trunc) {
443 /* NLS ? */
444 	tgaerror ("File appears to be truncated.\n");
445     }
446     fclose (fp);
447 
448     return pic8;
449 }
450 
451 
452 
453 /*returns 1 on error */
write_targa(unsigned char * pic8,const char * fname,long w,long h,int grey)454 int write_targa (unsigned char *pic8, const char *fname, long w, long h, int grey)
455 {
456     FILE *fp;
457     int i, j;
458     long index = 0;
459 
460     if ((fp = fopen (fname, "w+")) == NULL) {
461 /* NLS ? */
462 	tgaerror ("Cannot open create/overwrite targa image file.\n");
463 	return 1;
464     }
465     /* write header information */
466 
467     putc (0, fp);
468     putc (0, fp);
469 
470     if (grey)
471 	putc (3, fp);
472     else
473 	putc (2, fp);
474 
475     for (i = 0; i < 9; i++) {
476 	putc (0, fp);
477     }
478 
479     putc (w & 0xFF, fp);
480     putc (w >> 8, fp);
481 
482     putc (h & 0xFF, fp);
483     putc (h >> 8, fp);
484 
485     if (grey)
486 	putc (8, fp);
487     else
488 	putc (24, fp);
489 
490     putc (32, fp);		/*top left displayed */
491 
492     /* write the data */
493 
494     for (i = 0; i < h; i++) {
495 	if (grey)
496 	    fwrite (pic8 + i * w, w, 1, fp);
497 	else
498 	    for (j = 0; j < w; j++) {
499 		fputc (pic8[index], fp);
500 		fputc (pic8[index], fp);
501 		fputc (pic8[index++], fp);
502 	    }
503     }
504 
505     fclose (fp);
506     return 0;
507 }
508 
509