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