1 /* png.c
2 Copyright (C) 2004-2021 Mark Tyler and Dmitry Groshev
3
4 This file is part of mtPaint.
5
6 mtPaint is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 mtPaint is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with mtPaint in the file COPYING.
18 */
19
20 /* Rewritten for version 3.10 by Dmitry Groshev */
21
22 #include <stdio.h>
23 #include <errno.h>
24
25 #define PNG_READ_PACK_SUPPORTED
26
27 #include <png.h>
28 #include <zlib.h>
29 #ifdef U_JPEG
30 #define NEED_CMYK
31 /* !!! libjpeg 9 headers conflict with these */
32 #undef TRUE
33 #undef FALSE
34 #include <jpeglib.h>
35 /* !!! Since libjpeg 7, this conflicts with <windows.h>; with libjpeg 8a,
36 * conflict can be avoided if windows.h is included BEFORE this - WJ */
37 #endif
38 #ifdef U_JP2
39 #if U_JP2 < 2
40 #define NEED_FILE2MEM
41 #endif
42 #define HANDLE_JP2
43 #include <openjpeg.h>
44 #endif
45 #ifdef U_JASPER
46 #define HANDLE_JP2
47 #include <jasper/jasper.h>
48 #endif
49 #ifdef U_TIFF
50 #define NEED_CMYK
51 #include <tiffio.h>
52 #endif
53 #ifdef U_WEBP
54 #include <webp/encode.h>
55 #include <webp/decode.h>
56 #endif
57 #if U_LCMS == 2
58 #include <lcms2.h>
59 /* For version 1.x compatibility */
60 #define icSigCmykData cmsSigCmykData
61 #define icSigRgbData cmsSigRgbData
62 #define icHeader cmsICCHeader
63 #elif defined U_LCMS
64 #include <lcms.h>
65 #endif
66
67 #include "global.h"
68 #undef _
69 #define _(X) X
70
71 #include "mygtk.h"
72 #include "memory.h"
73 #include "ani.h"
74 #include "png.h"
75 #include "canvas.h"
76 #include "toolbar.h"
77 #include "layer.h"
78 #include "spawn.h"
79 #include "thread.h"
80
81 /* Make fseek() and ftell() on Win64 have the same limits as on 64-bit Unix */
82 #ifdef _WIN64 /* LLP64 */
83 #define F_LONG_MAX LLONG_MAX /* What can be handled - including allocated */
84 typedef long long f_long;
85 #define ftell(A) _ftelli64(A)
86 #define fseek(A,B,C) _fseeki64(A, B, C)
87
88 #else /* LP64 or ILP32 */
89 #define F_LONG_MAX LONG_MAX /* What can be handled - including allocated */
90 typedef long f_long;
91
92 #endif
93
94 #if F_LONG_MAX > SIZE_MAX
95 #error "File offset limit exceeds allocation limit"
96 #endif
97
98
99 /* Macro for big-endian tags (IFF and BMP) */
100 #define TAG4B(A,B,C,D) (((A) << 24) + ((B) << 16) + ((C) << 8) + (D))
101
102 /* All-in-one transport container for animation save/load */
103 typedef struct {
104 frameset fset;
105 ls_settings settings;
106 int mode;
107 /* Explode frames mode */
108 int desttype;
109 int error, miss, cnt;
110 int lastzero;
111 char *destdir;
112 } ani_settings;
113
114 int silence_limit, jpeg_quality, png_compression;
115 int tga_RLE, tga_565, tga_defdir, jp2_rate;
116 int lzma_preset, zstd_level, tiff_predictor, tiff_rtype, tiff_itype, tiff_btype;
117 int webp_preset, webp_quality, webp_compression;
118 int lbm_mask, lbm_untrans, lbm_pack, lbm_pbm;
119 int apply_icc;
120
121 fformat file_formats[NUM_FTYPES] = {
122 { "", "", "", 0},
123 { "PNG", "png", "apng", FF_256 | FF_RGB | FF_ANIM | FF_ALPHA | FF_MULTI
124 | FF_MEM, XF_TRANS | XF_COMPZ },
125 #ifdef U_JPEG
126 { "JPEG", "jpg", "jpeg", FF_RGB, XF_COMPJ },
127 #else
128 { "", "", "", 0},
129 #endif
130 #ifdef HANDLE_JP2
131 { "JPEG2000", "jp2", "", FF_RGB | FF_ALPHA, XF_COMPJ2 },
132 { "J2K", "j2k", "jpc", FF_RGB | FF_ALPHA, XF_COMPJ2 },
133 #else
134 { "", "", "", 0},
135 { "", "", "", 0},
136 #endif
137 #ifdef U_TIFF
138 #define TIFF0FLAGS FF_LAYER | FF_MEM
139 #define TIFFLAGS (FF_BW | FF_256 | FF_RGB | FF_ALPHA | TIFF0FLAGS)
140 { "TIFF", "tif", "tiff", TIFFLAGS, XF_COMPT },
141 #else
142 { "", "", "", 0},
143 #endif
144 { "GIF", "gif", "", FF_256 | FF_ANIM, XF_TRANS },
145 { "BMP", "bmp", "", FF_256 | FF_RGB | FF_ALPHAR | FF_MEM },
146 { "XPM", "xpm", "", FF_256 | FF_RGB, XF_TRANS | XF_SPOT },
147 { "XBM", "xbm", "", FF_BW, XF_SPOT },
148 { "LSS16", "lss", "", FF_16 },
149 { "TGA", "tga", "", FF_256 | FF_RGB | FF_ALPHAR, XF_TRANS | XF_COMPR },
150 { "PCX", "pcx", "", FF_256 | FF_RGB },
151 { "PBM", "pbm", "", FF_BW | FF_LAYER },
152 { "PGM", "pgm", "", FF_256 | FF_LAYER | FF_NOSAVE },
153 { "PPM", "ppm", "pnm", FF_RGB | FF_LAYER },
154 { "PAM", "pam", "", FF_BW | FF_RGB | FF_ALPHA | FF_LAYER },
155 { "GPL", "gpl", "", FF_PALETTE },
156 { "TXT", "txt", "", FF_PALETTE },
157 { "PAL", "pal", "", FF_PALETTE },
158 { "ACT", "act", "", FF_PALETTE },
159 { "LAYERS", "txt", "", FF_LAYER },
160 /* !!! No 2nd layers format yet */
161 { "", "", "", 0},
162 /* An X pixmap - not a file at all */
163 { "PIXMAP", "", "", FF_RGB | FF_NOSAVE },
164 /* SVG image - import only */
165 { "SVG", "svg", "", FF_RGB | FF_ALPHA | FF_SCALE | FF_NOSAVE },
166 /* mtPaint's own format - extended PAM */
167 { "* PMM *", "pmm", "", FF_256 | FF_RGB | FF_ANIM | FF_ALPHA | FF_MULTI
168 | FF_LAYER | FF_PALETTE | FF_MEM, XF_TRANS },
169 #ifdef U_WEBP
170 { "WEBP", "webp", "", FF_RGB | FF_ANIM | FF_ALPHA, XF_COMPW },
171 #else
172 { "", "", "", 0},
173 #endif
174 { "LBM", "lbm", "ilbm", FF_256 | FF_RGB | FF_ALPHA, XF_TRANS | XF_COMPRL },
175 };
176
177 #ifndef U_TIFF
178 tiff_format tiff_formats[] = { { NULL } };
179 #endif
180 #ifndef U_WEBP
181 char *webp_presets[] = { NULL };
182 #endif
183
file_type_by_ext(char * name,guint32 mask)184 int file_type_by_ext(char *name, guint32 mask)
185 {
186 char *ext;
187 int i, l = LONGEST_EXT;
188
189
190 ext = strrchr(name, '.');
191 if (!ext || !ext[0]) return (FT_NONE);
192
193 /* Special case for exploded frames (*.gif.000 etc.) */
194 if (!ext[strspn(ext, ".0123456789")] && memchr(name, '.', ext - name))
195 {
196 char *tmp = ext;
197
198 while (*(--ext) != '.');
199 if (tmp - ext - 1 < LONGEST_EXT) l = tmp - ext - 1;
200 }
201
202 ext++;
203 for (i = 0; i < NUM_FTYPES; i++)
204 {
205 unsigned int flags = file_formats[i].flags;
206
207 if ((flags & FF_NOSAVE) || !(flags & mask)) continue;
208 if (!strncasecmp(ext, file_formats[i].ext, l))
209 return (i);
210 if (!file_formats[i].ext2[0]) continue;
211 if (!strncasecmp(ext, file_formats[i].ext2, l))
212 return (i);
213 }
214
215 return (FT_NONE);
216 }
217
218 /* Which of 2 palette colors is more like black */
get_bw(ls_settings * settings)219 static int get_bw(ls_settings *settings)
220 {
221 return (pal2B(settings->pal + 0) > pal2B(settings->pal + 1));
222 }
223
224 /* Set palette to white and black */
set_bw(ls_settings * settings)225 static void set_bw(ls_settings *settings)
226 {
227 static const png_color wb[2] = { { 255, 255, 255 }, { 0, 0, 0 } };
228 settings->colors = 2;
229 memcpy(settings->pal, wb, sizeof(wb));
230 }
231
232 /* Set palette to grayscale */
set_gray(ls_settings * settings)233 static void set_gray(ls_settings *settings)
234 {
235 settings->colors = 256;
236 mem_bw_pal(settings->pal, 0, 255);
237 }
238
239 /* Map RGB transparency to indexed */
map_rgb_trans(ls_settings * settings)240 static void map_rgb_trans(ls_settings *settings)
241 {
242 int i;
243
244 if ((settings->rgb_trans < 0) || (settings->bpp < 3)) return;
245 // Look for transparent colour in palette
246 for (i = 0; i < settings->colors; i++)
247 {
248 if (PNG_2_INT(settings->pal[i]) != settings->rgb_trans) continue;
249 settings->xpm_trans = i;
250 return;
251 }
252 // Colour not in palette so force it into last entry
253 settings->pal[255].red = INT_2_R(settings->rgb_trans);
254 settings->pal[255].green = INT_2_G(settings->rgb_trans);
255 settings->pal[255].blue = INT_2_B(settings->rgb_trans);
256 settings->xpm_trans = 255;
257 settings->colors = 256;
258 }
259
check_next_frame(frameset * fset,int mode,int anim)260 static int check_next_frame(frameset *fset, int mode, int anim)
261 {
262 int lim = mode != FS_LAYER_LOAD ? FRAMES_MAX : anim ? MAX_LAYERS - 1 :
263 MAX_LAYERS;
264 return (fset->cnt < lim);
265 }
266
267 static int write_out_frame(char *file_name, ani_settings *ani, ls_settings *f_set);
268
process_page_frame(char * file_name,ani_settings * ani,ls_settings * w_set)269 static int process_page_frame(char *file_name, ani_settings *ani, ls_settings *w_set)
270 {
271 image_frame *frame;
272
273 if (ani->settings.mode == FS_EXPLODE_FRAMES)
274 return (write_out_frame(file_name, ani, w_set));
275
276 /* Store a new frame */
277 // !!! Currently, frames are allocated without checking any limits
278 if (!mem_add_frame(&ani->fset, w_set->width, w_set->height,
279 w_set->bpp, CMASK_NONE, w_set->pal)) return (FILE_MEM_ERROR);
280 frame = ani->fset.frames + (ani->fset.cnt - 1);
281 frame->cols = w_set->colors;
282 frame->trans = w_set->xpm_trans;
283 frame->delay = w_set->gif_delay > 0 ? w_set->gif_delay : 0;
284 frame->x = w_set->x;
285 frame->y = w_set->y;
286 memcpy(frame->img, w_set->img, sizeof(chanlist));
287 return (0);
288 }
289
290 /* Receives struct with image parameters, and channel flags;
291 * returns 0 for success, or an error code;
292 * success doesn't mean that anything was allocated, loader must check that;
293 * loader may call this multiple times - say, for each channel */
allocate_image(ls_settings * settings,int cmask)294 static int allocate_image(ls_settings *settings, int cmask)
295 {
296 size_t sz, l;
297 int i, j, oldmask, wbpp, mode = settings->mode;
298
299 if ((settings->width < 1) || (settings->height < 1)) return (-1);
300
301 if ((settings->width > MAX_WIDTH) || (settings->height > MAX_HEIGHT))
302 return (TOO_BIG);
303
304 /* Don't show progress bar where there's no need */
305 if (settings->width * settings->height <= (1 << silence_limit))
306 settings->silent = TRUE;
307 if (mode == FS_PATTERN_LOAD) settings->silent = TRUE;
308
309 /* Reduce cmask according to mode */
310 if (mode == FS_CLIP_FILE) cmask &= CMASK_CLIP;
311 else if (mode == FS_CLIPBOARD) cmask &= CMASK_RGBA;
312 else if ((mode == FS_CHANNEL_LOAD) || (mode == FS_PATTERN_LOAD))
313 cmask &= CMASK_IMAGE;
314
315 /* Overwriting is allowed */
316 oldmask = cmask_from(settings->img);
317 cmask &= ~oldmask;
318 if (!cmask) return (0); // Already allocated
319
320 /* No utility channels without image */
321 oldmask |= cmask;
322 if (!(oldmask & CMASK_IMAGE)) return (-1);
323
324 /* Can ask for RGBA-capable image channel */
325 wbpp = settings->bpp;
326 if (wbpp > 3) settings->bpp = 3;
327
328 j = TRUE; // For FS_LAYER_LOAD
329 sz = (size_t)settings->width * settings->height;
330 switch (mode)
331 {
332 case FS_PNG_LOAD: /* Regular image */
333 /* Reserve memory */
334 j = undo_next_core(UC_CREATE | UC_GETMEM, settings->width,
335 settings->height, settings->bpp, oldmask);
336 /* Drop current image if not enough memory for undo */
337 if (j) mem_free_image(&mem_image, FREE_IMAGE);
338 case FS_EXPLODE_FRAMES: /* Frames' temporaries */
339 case FS_LAYER_LOAD: /* Layers */
340 /* Allocate, or at least try to */
341 for (i = 0; i < NUM_CHANNELS; i++)
342 {
343 if (!(cmask & CMASK_FOR(i))) continue;
344 l = i == CHN_IMAGE ? sz * wbpp : sz;
345 settings->img[i] = j ? malloc(l) : mem_try_malloc(l);
346 if (!settings->img[i]) return (FILE_MEM_ERROR);
347 }
348 break;
349 case FS_CLIP_FILE: /* Clipboard */
350 case FS_CLIPBOARD:
351 /* Allocate the entire batch at once */
352 if (cmask & CMASK_IMAGE)
353 {
354 j = mem_clip_new(settings->width, settings->height,
355 settings->bpp, cmask, NULL);
356 if (j) return (FILE_MEM_ERROR);
357 memcpy(settings->img, mem_clip.img, sizeof(chanlist));
358 break;
359 }
360 /* Try to extend image channel to RGBA if asked */
361 if (wbpp > 3)
362 {
363 unsigned char *w = realloc(mem_clipboard, sz * wbpp);
364 if (!w) return (FILE_MEM_ERROR);
365 settings->img[CHN_IMAGE] = mem_clipboard = w;
366 }
367 /* Try to add clipboard alpha and/or mask */
368 for (i = 0; i < NUM_CHANNELS; i++)
369 {
370 if (!(cmask & CMASK_FOR(i))) continue;
371 if (!(settings->img[i] = mem_clip.img[i] = malloc(sz)))
372 return (FILE_MEM_ERROR);
373 }
374 break;
375 case FS_CHANNEL_LOAD: /* Current channel */
376 /* Dimensions & depth have to be the same */
377 if ((settings->width != mem_width) ||
378 (settings->height != mem_height) ||
379 (settings->bpp != MEM_BPP)) return (-1);
380 /* Reserve memory */
381 j = undo_next_core(UC_CREATE | UC_GETMEM, settings->width,
382 settings->height, settings->bpp, CMASK_CURR);
383 if (j) return (FILE_MEM_ERROR);
384 /* Allocate */
385 settings->img[CHN_IMAGE] = mem_try_malloc(sz * wbpp);
386 if (!settings->img[CHN_IMAGE]) return (FILE_MEM_ERROR);
387 break;
388 case FS_PATTERN_LOAD: /* Patterns */
389 /* Check dimensions & depth */
390 if (!set_patterns(settings)) return (-1);
391 /* Allocate temp memory */
392 settings->img[CHN_IMAGE] = calloc(1, sz * wbpp);
393 if (!settings->img[CHN_IMAGE]) return (FILE_MEM_ERROR);
394 break;
395 case FS_PALETTE_LOAD: /* Palette */
396 case FS_PALETTE_DEF:
397 return (-1); // Should not arrive here if palette is present
398 }
399 return (0);
400 }
401
402 /* Receives struct with image parameters, and which channels to deallocate */
deallocate_image(ls_settings * settings,int cmask)403 static void deallocate_image(ls_settings *settings, int cmask)
404 {
405 int i;
406
407 /* No deallocating image channel */
408 if (!(cmask &= ~CMASK_IMAGE)) return;
409
410 for (i = 0; i < NUM_CHANNELS; i++)
411 {
412 if (!(cmask & CMASK_FOR(i))) continue;
413 if (!settings->img[i]) continue;
414
415 free(settings->img[i]);
416 settings->img[i] = NULL;
417
418 /* Clipboard */
419 if ((settings->mode == FS_CLIP_FILE) ||
420 (settings->mode == FS_CLIPBOARD))
421 mem_clip.img[i] = NULL;
422 }
423 }
424
425 /* Deallocate alpha channel if useless; namely, all filled with given value */
delete_alpha(ls_settings * settings,int v)426 static void delete_alpha(ls_settings *settings, int v)
427 {
428 if (settings->img[CHN_ALPHA] && is_filled(settings->img[CHN_ALPHA], v,
429 settings->width * settings->height))
430 deallocate_image(settings, CMASK_ALPHA);
431 }
432
433 typedef struct {
434 FILE *file; // for traditional use
435 memx2 m; // data
436 int top; // end of data
437 } memFILE;
438 #define MEMFILE_MAX INT_MAX /* How much it can hold */
439
440 #if MEMFILE_MAX != MEMX2_MAX
441 #error "Mismatched max sizes"
442 #endif
443
mfread(void * ptr,size_t size,size_t nmemb,memFILE * mf)444 static size_t mfread(void *ptr, size_t size, size_t nmemb, memFILE *mf)
445 {
446 size_t l, m;
447
448 if (mf->file) return (fread(ptr, size, nmemb, mf->file));
449
450 if ((mf->m.here < 0) || (mf->m.here > mf->top)) return (0);
451 l = size * nmemb; m = mf->top - mf->m.here;
452 if (l > m) l = m , nmemb = m / size;
453 memcpy(ptr, mf->m.buf + mf->m.here, l);
454 mf->m.here += l;
455 return (nmemb);
456 }
457
mfwrite(void * ptr,size_t size,size_t nmemb,memFILE * mf)458 static size_t mfwrite(void *ptr, size_t size, size_t nmemb, memFILE *mf)
459 {
460 size_t l;
461
462 if (mf->file) return (fwrite(ptr, size, nmemb, mf->file));
463
464 if (mf->m.here < 0) return (0);
465 l = getmemx2(&mf->m, size * nmemb);
466 nmemb = l / size;
467 memcpy(mf->m.buf + mf->m.here, ptr, l);
468 mf->m.here += l;
469 if (mf->top < mf->m.here) mf->top = mf->m.here;
470 return (nmemb);
471 }
472
mfseek(memFILE * mf,f_long offset,int mode)473 static int mfseek(memFILE *mf, f_long offset, int mode)
474 {
475 // !!! For operating on tarballs, adjust fseek() params here
476 if (mf->file) return (fseek(mf->file, offset, mode));
477
478 if (mode == SEEK_SET);
479 else if (mode == SEEK_CUR) offset += mf->m.here;
480 else if (mode == SEEK_END) offset += mf->top;
481 else return (-1);
482 if ((offset < 0) || (offset > MEMFILE_MAX)) return (-1);
483 mf->m.here = offset;
484 return (0);
485 }
486
mfgets(char * s,int size,memFILE * mf)487 static char *mfgets(char *s, int size, memFILE *mf)
488 {
489 size_t m;
490 char *t, *v;
491
492 if (mf->file) return (fgets(s, size, mf->file));
493
494 if (size < 1) return (NULL);
495 if ((mf->m.here < 0) || (mf->m.here > mf->top)) return (NULL);
496 m = mf->top - mf->m.here;
497 if (m >= (unsigned)size) m = size - 1;
498 t = memchr(v = mf->m.buf + mf->m.here, '\n', m);
499 if (t) m = t - v + 1;
500 memcpy(s, v, m);
501 s[m] = '\0';
502 mf->m.here += m;
503 return (s);
504 }
505
mfputs(const char * s,memFILE * mf)506 static int mfputs(const char *s, memFILE *mf)
507 {
508 size_t l;
509
510 if (mf->file) return (fputs(s, mf->file));
511
512 l = strlen(s);
513 return (!l || mfwrite((void *)s, l, 1, mf) ? 0 : EOF);
514 }
515
mfputss(memFILE * mf,const char * s,...)516 static int mfputss(memFILE *mf, const char *s, ...)
517 {
518 va_list args;
519 size_t l;
520 int m = 0;
521
522 va_start(args, s);
523 while (s)
524 {
525 if (mf->file) m = fputs(s, mf->file);
526 else
527 {
528 l = strlen(s);
529 m = !l || mfwrite((void *)s, l, 1, mf) ? 0 : EOF;
530 }
531 if (m < 0) break;
532 s = va_arg(args, const char *);
533 }
534 va_end(args);
535 return (m);
536 }
537
copy_run(unsigned char * dest,unsigned char * src,int len,int dstep,int sstep,int bgr)538 static void copy_run(unsigned char *dest, unsigned char *src, int len,
539 int dstep, int sstep, int bgr)
540 {
541 if (bgr) bgr = 2;
542 while (len-- > 0)
543 {
544 dest[0] = src[bgr];
545 dest[1] = src[1];
546 dest[2] = src[bgr ^ 2];
547 dest += dstep;
548 src += sstep;
549 }
550 }
551
552 /* Fills temp buffer row, or returns image row if no buffer */
prepare_row(unsigned char * buf,ls_settings * settings,int bpp,int y)553 static unsigned char *prepare_row(unsigned char *buf, ls_settings *settings,
554 int bpp, int y)
555 {
556 unsigned char *tmp, *tmi, *tma, *tms;
557 int i, j, w = settings->width, h = y * w;
558 int bgr = (settings->ftype == FT_BMP) || (settings->ftype == FT_TGA) ? 2 : 0;
559
560 tmi = settings->img[CHN_IMAGE] + h * settings->bpp;
561 if (bpp < (bgr ? 3 : 4)) /* Return/copy image row */
562 {
563 if (!buf) return (tmi);
564 memcpy(buf, tmi, w * bpp);
565 return (buf);
566 }
567
568 /* Produce BGR / BGRx / RGBx */
569 tmp = buf;
570 if (settings->bpp == 1) // Indexed
571 {
572 png_color *pal = settings->pal;
573
574 for (i = 0; i < w; tmp += bpp , i++)
575 {
576 png_color *col = pal + *tmi++;
577 tmp[bgr] = col->red;
578 tmp[1] = col->green;
579 tmp[bgr ^ 2] = col->blue;
580 }
581 }
582 else copy_run(tmp, tmi, w, bpp, 3, bgr); // RGB
583
584 /* Add alpha to the mix */
585 tmp = buf + 3;
586 tma = settings->img[CHN_ALPHA] + h;
587 if (bpp == 3); // No alpha - all done
588 else if ((settings->mode != FS_CLIPBOARD) || !settings->img[CHN_SEL])
589 {
590 // Only alpha here
591 for (i = 0; i < w; tmp += bpp , i++)
592 *tmp = *tma++;
593 }
594 else
595 {
596 // Merge alpha and selection
597 tms = settings->img[CHN_SEL] + h;
598 for (i = 0; i < w; tmp += bpp , i++)
599 {
600 j = *tma++ * *tms++;
601 *tmp = (j + (j >> 8) + 1) >> 8;
602 }
603 }
604
605 return (buf);
606 }
607
608 /* Converts palette-based transparency to color transparency or alpha channel */
palette_trans(ls_settings * settings,unsigned char ttb[256])609 static int palette_trans(ls_settings *settings, unsigned char ttb[256])
610 {
611 int i, n, res;
612
613 /* Count transparent colors */
614 for (i = n = 0; i < 256; i++) n += ttb[i] < 255;
615 /* None means no transparency */
616 settings->xpm_trans = -1;
617 if (!n) return (0);
618 /* One fully transparent color means color transparency */
619 if (n == 1)
620 {
621 for (i = 0; i < 256; i++)
622 {
623 if (ttb[i]) continue;
624 settings->xpm_trans = i;
625 return (0);
626 }
627 }
628 /* Anything else means alpha transparency */
629 res = allocate_image(settings, CMASK_ALPHA);
630 if (!res && settings->img[CHN_ALPHA])
631 {
632 unsigned char *src, *dest;
633 size_t i = (size_t)settings->width * settings->height;
634
635 src = settings->img[CHN_IMAGE];
636 dest = settings->img[CHN_ALPHA];
637 while (i-- > 0) *dest++ = ttb[*src++];
638 }
639 return (res);
640 }
641
ls_init(char * what,int save)642 static void ls_init(char *what, int save)
643 {
644 what = g_strdup_printf(save ? __("Saving %s image") : __("Loading %s image"), what);
645 progress_init(what, 0);
646 g_free(what);
647 }
648
ls_progress(ls_settings * settings,int n,int steps)649 static void ls_progress(ls_settings *settings, int n, int steps)
650 {
651 int h = settings->height;
652
653 if (!settings->silent && ((n * steps) % h >= h - steps))
654 progress_update((float)n / h);
655 }
656
657 #if PNG_LIBPNG_VER >= 10400 /* 1.4+ */
658 #define png_set_gray_1_2_4_to_8(X) png_set_expand_gray_1_2_4_to_8(X)
659 #endif
660
661 /* !!! libpng 1.2.17-1.2.24 was losing extra chunks if there was no callback */
buggy_libpng_handler()662 static int buggy_libpng_handler()
663 {
664 return (0);
665 }
666
png_memread(png_structp png_ptr,png_bytep data,png_size_t length)667 static void png_memread(png_structp png_ptr, png_bytep data, png_size_t length)
668 {
669 memFILE *mf = (memFILE *)png_get_io_ptr(png_ptr);
670 // memFILE *mf = (memFILE *)png_ptr->io_ptr;
671 size_t l = mf->top - mf->m.here;
672
673 if (l > length) l = length;
674 memcpy(data, mf->m.buf + mf->m.here, l);
675 mf->m.here += l;
676 if (l < length) png_error(png_ptr, "Read Error");
677 }
678
png_memwrite(png_structp png_ptr,png_bytep data,png_size_t length)679 static void png_memwrite(png_structp png_ptr, png_bytep data, png_size_t length)
680 {
681 memFILE *mf = (memFILE *)png_get_io_ptr(png_ptr);
682 // memFILE *mf = (memFILE *)png_ptr->io_ptr;
683
684 if (getmemx2(&mf->m, length) < length)
685 png_error(png_ptr, "Write Error");
686 else
687 {
688 memcpy(mf->m.buf + mf->m.here, data, length);
689 mf->top = mf->m.here += length;
690 }
691 }
692
png_memflush(png_structp png_ptr)693 static void png_memflush(png_structp png_ptr)
694 {
695 /* Does nothing */
696 }
697
698 #define PNG_BYTES_TO_CHECK 8
699 #define PNG_HANDLE_CHUNK_NEVER 1
700 #define PNG_HANDLE_CHUNK_ALWAYS 3
701
702 static const char *chunk_names[NUM_CHANNELS] = { "", "alPh", "seLc", "maSk" };
703
load_png(char * file_name,ls_settings * settings,memFILE * mf,int frame)704 static int load_png(char *file_name, ls_settings *settings, memFILE *mf, int frame)
705 {
706 /* Description of PNG interlacing passes as X0, DX, Y0, DY */
707 static const unsigned char png_interlace[8][4] = {
708 {0, 1, 0, 1}, /* One pass for non-interlaced */
709 {0, 8, 0, 8}, /* Seven passes for Adam7 interlaced */
710 {4, 8, 0, 8},
711 {0, 4, 4, 8},
712 {2, 4, 0, 4},
713 {0, 2, 2, 4},
714 {1, 2, 0, 2},
715 {0, 1, 1, 2}
716 };
717 static png_bytep *row_pointers;
718 static char *msg;
719 png_structp png_ptr;
720 png_infop info_ptr;
721 png_unknown_chunkp uk_p;
722 png_uint_32 pwidth, pheight;
723 char buf[PNG_BYTES_TO_CHECK + 1];
724 unsigned char trans[256], *src, *dest, *dsta;
725 long dest_len;
726 FILE *fp = NULL;
727 int i, j, k, bit_depth, color_type, interlace_type, num_uk, res = -1;
728 int maxpass, x0, dx, y0, dy, n, nx, height, width, itrans = FALSE, anim = FALSE;
729
730 if (!mf)
731 {
732 if ((fp = fopen(file_name, "rb")) == NULL) return -1;
733 i = fread(buf, 1, PNG_BYTES_TO_CHECK, fp);
734 }
735 else i = mfread(buf, 1, PNG_BYTES_TO_CHECK, mf);
736 if (i != PNG_BYTES_TO_CHECK) goto fail;
737 if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK)) goto fail;
738
739 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
740 if (!png_ptr) goto fail;
741
742 row_pointers = NULL; msg = NULL;
743 info_ptr = png_create_info_struct(png_ptr);
744 if (!info_ptr) goto fail2;
745
746 if (setjmp(png_jmpbuf(png_ptr)))
747 {
748 res = settings->width ? FILE_LIB_ERROR : -1;
749 goto fail2;
750 }
751
752 /* Frame pseudo-files have wrong CRCs */
753 if (frame) png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
754 /* !!! libpng 1.2.17-1.2.24 needs this to read extra channels */
755 else png_set_read_user_chunk_fn(png_ptr, NULL, buggy_libpng_handler);
756
757 if (!mf) png_init_io(png_ptr, fp);
758 else png_set_read_fn(png_ptr, mf, png_memread);
759 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
760
761 /* Stupid libpng handles private chunks on all-or-nothing basis */
762 png_set_keep_unknown_chunks(png_ptr, frame ? PNG_HANDLE_CHUNK_NEVER :
763 PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
764
765 png_read_info(png_ptr, info_ptr);
766
767 /* Check whether the file is APNG */
768 num_uk = png_get_unknown_chunks(png_ptr, info_ptr, &uk_p);
769 for (i = 0; i < num_uk; i++)
770 {
771 if (strcmp(uk_p[i].name, "acTL")) continue;
772 anim = TRUE;
773 /* mtPaint does not write APNGs with extra channels, and
774 * no reason to waste memory on APNG frames now */
775 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0);
776 png_set_read_user_chunk_fn(png_ptr, NULL, NULL);
777 }
778
779 png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, &bit_depth, &color_type,
780 &interlace_type, NULL, NULL);
781 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
782 {
783 png_colorp png_palette;
784
785 png_get_PLTE(png_ptr, info_ptr, &png_palette, &settings->colors);
786 memcpy(settings->pal, png_palette, settings->colors * sizeof(png_color));
787 /* If palette is all we need */
788 res = 1;
789 if ((settings->mode == FS_PALETTE_LOAD) ||
790 (settings->mode == FS_PALETTE_DEF)) goto fail3;
791 }
792
793 res = TOO_BIG;
794 if ((pwidth > MAX_WIDTH) || (pheight > MAX_HEIGHT)) goto fail2;
795
796 /* Call allocator for image data */
797 settings->width = width = (int)pwidth;
798 settings->height = height = (int)pheight;
799 settings->bpp = 1;
800 if ((color_type != PNG_COLOR_TYPE_PALETTE) || (bit_depth > 8))
801 settings->bpp = 3;
802 i = CMASK_IMAGE;
803 if ((color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
804 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) i = CMASK_RGBA;
805 if ((res = allocate_image(settings, i))) goto fail2;
806 res = FILE_MEM_ERROR;
807
808 i = sizeof(png_bytep) * height;
809 row_pointers = malloc(i + width * 4);
810 if (!row_pointers) goto fail2;
811 row_pointers[0] = (char *)row_pointers + i;
812
813 if (!settings->silent)
814 {
815 switch(settings->mode)
816 {
817 case FS_PNG_LOAD:
818 msg = "PNG";
819 break;
820 case FS_CLIP_FILE:
821 case FS_CLIPBOARD:
822 msg = __("Clipboard");
823 break;
824 }
825 }
826 if (msg) ls_init(msg, 0);
827 res = -1;
828
829 /* RGB PNG file */
830 if (settings->bpp == 3)
831 {
832 png_set_strip_16(png_ptr);
833 png_set_gray_1_2_4_to_8(png_ptr);
834 png_set_palette_to_rgb(png_ptr);
835 png_set_gray_to_rgb(png_ptr);
836
837 /* Is there a transparent color? */
838 settings->rgb_trans = -1;
839 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
840 {
841 png_color_16p trans_rgb;
842
843 png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_rgb);
844 if (color_type == PNG_COLOR_TYPE_GRAY)
845 {
846 i = trans_rgb->gray;
847 switch (bit_depth)
848 {
849 case 1: i *= 0xFF; break;
850 case 2: i *= 0x55; break;
851 case 4: i *= 0x11; break;
852 case 8: default: break;
853 /* Hope libpng compiled w/o accurate transform */
854 case 16: i >>= 8; break;
855 }
856 settings->rgb_trans = RGB_2_INT(i, i, i);
857 }
858 else settings->rgb_trans = RGB_2_INT(trans_rgb->red,
859 trans_rgb->green, trans_rgb->blue);
860 }
861
862 if (settings->img[CHN_ALPHA]) /* RGBA */
863 {
864 nx = height;
865 /* Have to do deinterlacing myself */
866 if (interlace_type == PNG_INTERLACE_NONE)
867 {
868 k = 0; maxpass = 1;
869 }
870 else if (interlace_type == PNG_INTERLACE_ADAM7)
871 {
872 k = 1; maxpass = 8;
873 nx = (nx + 7) & ~7; nx += 7 * (nx >> 3);
874 }
875 else goto fail2; /* Unknown type */
876
877 for (n = 0; k < maxpass; k++)
878 {
879 x0 = png_interlace[k][0];
880 dx = png_interlace[k][1];
881 y0 = png_interlace[k][2];
882 dy = png_interlace[k][3];
883 for (i = y0; i < height; i += dy , n++)
884 {
885 png_read_rows(png_ptr, &row_pointers[0], NULL, 1);
886 src = row_pointers[0];
887 dest = settings->img[CHN_IMAGE] + (i * width + x0) * 3;
888 dsta = settings->img[CHN_ALPHA] + i * width;
889 for (j = x0; j < width; j += dx)
890 {
891 dest[0] = src[0];
892 dest[1] = src[1];
893 dest[2] = src[2];
894 dsta[j] = src[3];
895 src += 4; dest += 3 * dx;
896 }
897 if (msg && ((n * 20) % nx >= nx - 20))
898 progress_update((float)n / nx);
899 }
900 }
901 }
902 else /* RGB */
903 {
904 png_set_strip_alpha(png_ptr);
905 for (i = 0; i < height; i++)
906 {
907 row_pointers[i] = settings->img[CHN_IMAGE] + i * width * 3;
908 }
909 png_read_image(png_ptr, row_pointers);
910 }
911 }
912 /* Paletted PNG file */
913 else
914 {
915 /* Is there a transparent index? */
916 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
917 {
918 png_bytep ptrans;
919 int ltrans;
920
921 png_get_tRNS(png_ptr, info_ptr, &ptrans, <rans, NULL);
922 memset(trans, 255, 256);
923 memcpy(trans, ptrans, ltrans);
924 itrans = TRUE;
925 }
926 png_set_strip_16(png_ptr);
927 png_set_strip_alpha(png_ptr);
928 png_set_packing(png_ptr);
929 if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
930 png_set_gray_1_2_4_to_8(png_ptr);
931 for (i = 0; i < height; i++)
932 {
933 row_pointers[i] = settings->img[CHN_IMAGE] + i * width;
934 }
935 png_read_image(png_ptr, row_pointers);
936 }
937 if (msg) progress_update(1.0);
938
939 png_read_end(png_ptr, info_ptr);
940 res = 0;
941
942 /* Apply palette transparency */
943 if (itrans) res = palette_trans(settings, trans);
944
945 num_uk = png_get_unknown_chunks(png_ptr, info_ptr, &uk_p);
946 if (num_uk) /* File contains mtPaint's private chunks */
947 {
948 for (i = 0; i < num_uk; i++) /* Examine each chunk */
949 {
950 for (j = CHN_ALPHA; j < NUM_CHANNELS; j++)
951 {
952 if (!strcmp(uk_p[i].name, chunk_names[j])) break;
953 }
954 if (j >= NUM_CHANNELS) continue;
955
956 /* Try to allocate a channel */
957 if ((res = allocate_image(settings, CMASK_FOR(j)))) break;
958 /* Skip if not allocated */
959 if (!settings->img[j]) continue;
960
961 dest_len = width * height;
962 uncompress(settings->img[j], &dest_len, uk_p[i].data,
963 uk_p[i].size);
964 }
965 /* !!! Is this call really needed? */
966 png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, -1);
967 }
968 if (!res) res = anim ? FILE_HAS_FRAMES : 1;
969
970 #ifdef U_LCMS
971 #ifdef PNG_iCCP_SUPPORTED
972 /* Extract ICC profile if it's of use */
973 if (!settings->icc_size)
974 {
975 #if PNG_LIBPNG_VER >= 10600 /* 1.6+ */
976 png_bytep icc;
977 #else
978 png_charp icc;
979 #endif
980 png_charp name;
981 png_uint_32 len;
982 int comp;
983
984 if (png_get_iCCP(png_ptr, info_ptr, &name, &comp, &icc, &len) &&
985 (len < INT_MAX) && (settings->icc = malloc(len)))
986 {
987 settings->icc_size = len;
988 memcpy(settings->icc, icc, len);
989 }
990 }
991 #endif
992 #endif
993
994 fail2: if (msg) progress_end();
995 free(row_pointers);
996 fail3: png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
997 fail: if (fp) fclose(fp);
998 return (res);
999 }
1000
1001 #ifndef PNG_AFTER_IDAT
1002 #define PNG_AFTER_IDAT 8
1003 #endif
1004
save_png(char * file_name,ls_settings * settings,memFILE * mf)1005 static int save_png(char *file_name, ls_settings *settings, memFILE *mf)
1006 {
1007 png_unknown_chunk unknown0;
1008 png_structp png_ptr;
1009 png_infop info_ptr;
1010 FILE *fp = NULL;
1011 int h = settings->height, w = settings->width, bpp = settings->bpp;
1012 int i, j, res = -1;
1013 long uninit_(dest_len), res_len;
1014 char *mess = NULL;
1015 unsigned char trans[256], *tmp, *rgba_row = NULL;
1016 png_color_16 trans_rgb;
1017
1018 /* Baseline PNG format does not support alpha for indexed images, so
1019 * we have to convert them to RGBA for clipboard export - WJ */
1020 if (((settings->mode == FS_CLIPBOARD) || (bpp == 3)) &&
1021 settings->img[CHN_ALPHA])
1022 {
1023 rgba_row = malloc(w * 4);
1024 if (!rgba_row) return (-1);
1025 bpp = 4;
1026 }
1027
1028 if (!settings->silent)
1029 switch(settings->mode)
1030 {
1031 case FS_PNG_SAVE:
1032 mess = "PNG";
1033 break;
1034 case FS_CLIP_FILE:
1035 case FS_CLIPBOARD:
1036 mess = __("Clipboard");
1037 break;
1038 case FS_COMPOSITE_SAVE:
1039 mess = __("Layer");
1040 break;
1041 case FS_CHANNEL_SAVE:
1042 mess = __("Channel");
1043 break;
1044 default:
1045 settings->silent = TRUE;
1046 break;
1047 }
1048
1049 if (!mf && ((fp = fopen(file_name, "wb")) == NULL)) goto exit0;
1050
1051 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
1052
1053 if (!png_ptr) goto exit1;
1054
1055 info_ptr = png_create_info_struct(png_ptr);
1056 if (!info_ptr) goto exit2;
1057
1058 res = 0;
1059
1060 if (!mf) png_init_io(png_ptr, fp);
1061 else png_set_write_fn(png_ptr, mf, png_memwrite, png_memflush);
1062 png_set_compression_level(png_ptr, settings->png_compression);
1063
1064 if (bpp == 1)
1065 {
1066 png_set_IHDR(png_ptr, info_ptr, w, h,
1067 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
1068 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1069 png_set_PLTE(png_ptr, info_ptr, settings->pal, settings->colors);
1070 /* Transparent index in use */
1071 if ((settings->xpm_trans > -1) && (settings->xpm_trans < 256))
1072 {
1073 memset(trans, 255, 256);
1074 trans[settings->xpm_trans] = 0;
1075 png_set_tRNS(png_ptr, info_ptr, trans, settings->colors, 0);
1076 }
1077 }
1078 else
1079 {
1080 png_set_IHDR(png_ptr, info_ptr, w, h,
1081 8, bpp == 4 ? PNG_COLOR_TYPE_RGB_ALPHA :
1082 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
1083 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1084 if (settings->pal) png_set_PLTE(png_ptr, info_ptr, settings->pal,
1085 settings->colors);
1086 /* Transparent index in use */
1087 if ((settings->rgb_trans > -1) && !settings->img[CHN_ALPHA])
1088 {
1089 trans_rgb.red = INT_2_R(settings->rgb_trans);
1090 trans_rgb.green = INT_2_G(settings->rgb_trans);
1091 trans_rgb.blue = INT_2_B(settings->rgb_trans);
1092 png_set_tRNS(png_ptr, info_ptr, 0, 1, &trans_rgb);
1093 }
1094 }
1095
1096 png_write_info(png_ptr, info_ptr);
1097
1098 if (mess) ls_init(mess, 1);
1099
1100 for (j = 0; j < h; j++)
1101 {
1102 tmp = prepare_row(rgba_row, settings, bpp, j);
1103 png_write_row(png_ptr, (png_bytep)tmp);
1104 ls_progress(settings, j, 20);
1105 }
1106
1107 /* Save private chunks into PNG file if we need to */
1108 /* !!! Uncomment if default setting ever gets inadequate (in 1.7+) */
1109 // png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
1110 tmp = NULL;
1111 i = bpp == 1 ? CHN_ALPHA : CHN_ALPHA + 1;
1112 if (settings->mode == FS_CLIPBOARD) i = NUM_CHANNELS; // Disable extensions
1113 for (j = 0; i < NUM_CHANNELS; i++)
1114 {
1115 if (!settings->img[i]) continue;
1116 if (!tmp)
1117 {
1118 /* Get size required for each zlib compress */
1119 w = settings->width * settings->height;
1120 #if ZLIB_VERNUM >= 0x1200
1121 dest_len = compressBound(w);
1122 #else
1123 dest_len = w + (w >> 8) + 32;
1124 #endif
1125 res = -1;
1126 tmp = malloc(dest_len); // Temporary space for compression
1127 if (!tmp) break;
1128 res = 0;
1129 }
1130 res_len = dest_len;
1131 if (compress2(tmp, &res_len, settings->img[i], w,
1132 settings->png_compression) != Z_OK) continue;
1133 strncpy(unknown0.name, chunk_names[i], 5);
1134 unknown0.data = tmp;
1135 unknown0.size = res_len;
1136 unknown0.location = PNG_AFTER_IDAT;
1137 png_set_unknown_chunks(png_ptr, info_ptr, &unknown0, 1);
1138 #if PNG_LIBPNG_VER < 10600 /* before 1.6 */
1139 png_set_unknown_chunk_location(png_ptr, info_ptr,
1140 j++, PNG_AFTER_IDAT);
1141 #endif
1142 }
1143 free(tmp);
1144 png_write_end(png_ptr, info_ptr);
1145
1146 if (mess) progress_end();
1147
1148 /* Tidy up */
1149 exit2: png_destroy_write_struct(&png_ptr, &info_ptr);
1150 exit1: if (fp) fclose(fp);
1151 exit0: free(rgba_row);
1152 return (res);
1153 }
1154
1155 /* *** PREFACE ***
1156 * Contrary to what GIF89 docs say, all contemporary browser implementations
1157 * always render background in an animated GIF as transparent. So does mtPaint,
1158 * for some GIF animations depend on this rule.
1159 * An inter-frame delay of 0 normally means that the two (or more) frames
1160 * are parts of same animation frame and should be rendered as one resulting
1161 * frame; but some (ancient) GIFs have all delays set to 0, but still contain
1162 * animation sequences. So the handling of zero-delay frames is user-selectable
1163 * in mtPaint. */
1164
1165 /* Animation state */
1166 typedef struct {
1167 unsigned char lmap[MAX_DIM];
1168 image_frame prev;
1169 int prev_idx; // Frame index+1, so that 0 means None
1170 int have_frames; // Set after first
1171 int defw, defh, bk_rect[4];
1172 int mode;
1173 /* Extra fields for paletted images */
1174 int global_cols, newcols, newtrans;
1175 png_color global_pal[256], newpal[256];
1176 unsigned char xlat[513];
1177 /* Extra fields for RGBA images */
1178 int blend;
1179 unsigned char bkg[4];
1180 } ani_status;
1181
1182 /* Initialize palette remapping table */
ani_init_xlat(ani_status * stat)1183 static void ani_init_xlat(ani_status *stat)
1184 {
1185 int i;
1186
1187 for (i = 0; i < 256; i++) stat->xlat[i] = stat->xlat[i + 256] = i;
1188 stat->xlat[512] = stat->newtrans;
1189 }
1190
1191 /* Calculate new frame dimensions, and point-in-area bitmap */
ani_map_frame(ani_status * stat,ls_settings * settings)1192 static void ani_map_frame(ani_status *stat, ls_settings *settings)
1193 {
1194 unsigned char *lmap;
1195 int i, j, w, h;
1196
1197
1198 /* Calculate the new dimensions */
1199 // !!! Offsets considered nonnegative (as in GIF, WebP and APNG)
1200 w = settings->x + settings->width;
1201 h = settings->y + settings->height;
1202 if (!stat->have_frames) // Resize screen to fit the first frame
1203 {
1204 if (w > MAX_WIDTH) w = MAX_WIDTH;
1205 if (h > MAX_HEIGHT) h = MAX_HEIGHT;
1206 if (stat->defw < w) stat->defw = w;
1207 if (stat->defh < h) stat->defh = h;
1208 stat->have_frames = TRUE;
1209 }
1210 else // Clip all frames past the first to screen size
1211 {
1212 if (stat->defw < w) w = stat->defw;
1213 if (stat->defh < h) h = stat->defh;
1214 }
1215
1216 /* The bitmap works this way: "Xth byte & (Yth byte >> 4)" tells which
1217 * area(s) the pixel (X,Y) is in: bit 0 is for image (the new one),
1218 * bit 1 is for underlayer (the previous composited frame), and bit 2
1219 * is for hole in it (if "restore to background" was last) */
1220 j = stat->defw > stat->defh ? stat->defw : stat->defh;
1221 memset(lmap = stat->lmap, 0, j);
1222 // Mark new frame
1223 for (i = settings->x; i < w; i++) lmap[i] |= 0x01; // Image bit
1224 for (i = settings->y; i < h; i++) lmap[i] |= 0x10; // Image mask bit
1225 // Mark previous frame
1226 if (stat->prev_idx)
1227 {
1228 for (i = stat->prev.x , j = i + stat->prev.width; i < j; i++)
1229 lmap[i] |= 0x02; // Underlayer bit
1230 for (i = stat->prev.y , j = i + stat->prev.height; i < j; i++)
1231 lmap[i] |= 0x20; // Underlayer mask bit
1232 }
1233 // Mark disposal area
1234 if (clip(stat->bk_rect, 0, 0, stat->defw, stat->defh, stat->bk_rect))
1235 {
1236 for (i = stat->bk_rect[0] , j = stat->bk_rect[2]; i < j; i++)
1237 lmap[i] |= 0x04; // Background bit
1238 for (i = stat->bk_rect[1] , j = stat->bk_rect[3]; i < j; i++)
1239 lmap[i] |= 0x40; // Background mask bit
1240 }
1241 }
1242
1243 /* Allowed bpp: 0 - move, 1 - indexed, 3 - RGB, 4 - RGBA
1244 * Indexed+alpha not supported nor should be: cannot be saved as standard PNG */
add_frame(ani_settings * ani,ani_status * stat,ls_settings * settings,int bpp,int disposal)1245 static int add_frame(ani_settings *ani, ani_status *stat, ls_settings *settings,
1246 int bpp, int disposal)
1247 {
1248 int cmask = !bpp ? CMASK_NONE : bpp > 3 ? CMASK_RGBA : CMASK_IMAGE;
1249 int fbpp = !bpp ? settings->bpp : bpp > 3 ? 3 : bpp;
1250 image_frame *frame;
1251
1252 /* Allocate a new frame */
1253 if (!mem_add_frame(&ani->fset, stat->defw, stat->defh, fbpp, cmask,
1254 stat->newpal)) return (FILE_MEM_ERROR);
1255 frame = ani->fset.frames + (ani->fset.cnt - 1);
1256 frame->cols = stat->newcols;
1257 frame->trans = stat->newtrans;
1258 frame->delay = settings->gif_delay;
1259 frame->flags = disposal; // Pass to compositing
1260 /* Tag zero-delay frame for deletion if requested */
1261 if ((ani->lastzero = (stat->mode == ANM_NOZERO) &&
1262 !settings->gif_delay)) frame->flags |= FM_NUKE;
1263 if (!bpp) // Same bpp & dimensions - reassign the chanlist
1264 {
1265 memcpy(frame->img, settings->img, sizeof(chanlist));
1266 memset(settings->img, 0, sizeof(chanlist));
1267 }
1268 return (0);
1269 }
1270
done_frame(char * file_name,ani_settings * ani,int last)1271 static int done_frame(char *file_name, ani_settings *ani, int last)
1272 {
1273 int res = 1;
1274
1275 if ((ani->settings.mode == FS_EXPLODE_FRAMES) && (!last ^ ani->lastzero))
1276 res = write_out_frame(file_name, ani, NULL);
1277 return (res ? res : 1);
1278 }
1279
composite_indexed_frame(image_frame * frame,ani_status * stat,ls_settings * settings)1280 static void composite_indexed_frame(image_frame *frame, ani_status *stat,
1281 ls_settings *settings)
1282 {
1283 unsigned char *dest, *fg0, *bg0 = NULL, *lmap = stat->lmap;
1284 image_frame *bkf = &stat->prev;
1285 int w, fgw, bgw = 0, urgb = 0, tp = settings->xpm_trans;
1286
1287 w = frame->width;
1288 dest = frame->img[CHN_IMAGE];
1289 fgw = settings->width;
1290 fg0 = settings->img[CHN_IMAGE] ? settings->img[CHN_IMAGE] -
1291 (settings->y * fgw + settings->x) : dest; // Always indexed (1 bpp)
1292 /* Pointer to absent underlayer is no problem - it just won't get used */
1293 bgw = bkf->width;
1294 bg0 = bkf->img[CHN_IMAGE] - (bkf->y * bgw + bkf->x) * bkf->bpp;
1295 urgb = bkf->bpp != 1;
1296
1297 if (frame->bpp == 1) // To indexed
1298 {
1299 unsigned char *fg = fg0, *bg = bg0, *xlat = stat->xlat;
1300 int x, y;
1301
1302 for (y = 0; y < frame->height; y++)
1303 {
1304 int bmask = lmap[y] >> 4;
1305
1306 for (x = 0; x < w; x++)
1307 {
1308 int c0, bflag = lmap[x] & bmask;
1309
1310 if ((bflag & 1) && ((c0 = fg[x]) != tp)) // New frame
1311 c0 += 256;
1312 else if ((bflag & 6) == 2) // Underlayer
1313 c0 = bg[x];
1314 else c0 = 512; // Background (transparent)
1315 *dest++ = xlat[c0];
1316 }
1317 fg += fgw; bg += bgw;
1318 }
1319 }
1320 else // To RGB
1321 {
1322 unsigned char rgb[513 * 3], *fg = fg0, *bg = bg0;
1323 int x, y, bpp = urgb + urgb + 1;
1324
1325 /* Setup global palette map: underlayer, image, background */
1326 if (bkf->pal) pal2rgb(rgb, bkf->pal, 256, 0);
1327 pal2rgb(rgb + 256 * 3,
1328 settings->colors ? settings->pal : stat->global_pal, 256, 257);
1329 frame->trans = -1; // No color-key transparency
1330
1331 for (y = 0; y < frame->height; y++)
1332 {
1333 int bmask = lmap[y] >> 4;
1334
1335 for (x = 0; x < w; x++)
1336 {
1337 unsigned char *src;
1338 int c0, bflag = lmap[x] & bmask;
1339
1340 if ((bflag & 1) && ((c0 = fg[x]) != tp)) // New frame
1341 src = rgb + (256 * 3) + (c0 * 3);
1342 else if ((bflag & 6) == 2) // Underlayer
1343 src = urgb ? bg + x * 3 : rgb + bg[x] * 3;
1344 else src = rgb + 512 * 3; // Background (black)
1345 dest[0] = src[0];
1346 dest[1] = src[1];
1347 dest[2] = src[2];
1348 dest += 3;
1349 }
1350 fg += fgw; bg += bgw * bpp;
1351 }
1352 }
1353
1354 if (frame->img[CHN_ALPHA]) // To alpha
1355 {
1356 unsigned char *fg = fg0, *bg = NULL;
1357 int x, y, af = 0, utp = -1;
1358
1359 dest = frame->img[CHN_ALPHA];
1360 utp = bkf->bpp == 1 ? bkf->trans : -1;
1361 af = !!bkf->img[CHN_ALPHA]; // Underlayer has alpha
1362 bg = bkf->img[af ? CHN_ALPHA : CHN_IMAGE] - (bkf->y * bgw + bkf->x);
1363
1364 for (y = 0; y < frame->height; y++)
1365 {
1366 int bmask = lmap[y] >> 4;
1367
1368 for (x = 0; x < w; x++)
1369 {
1370 int c0, bflag = lmap[x] & bmask;
1371
1372 if ((bflag & 1) && (fg[x] != tp)) // New frame
1373 c0 = 255;
1374 else if ((bflag & 6) == 2) // Underlayer
1375 {
1376 c0 = bg[x];
1377 if (!af) c0 = c0 != utp ? 255 : 0;
1378 }
1379 else c0 = 0; // Background (transparent)
1380 *dest++ = c0;
1381 }
1382 fg += fgw; bg += bgw;
1383 }
1384 }
1385 }
1386
composite_rgba_frame(image_frame * frame,ani_status * stat,ls_settings * settings)1387 static void composite_rgba_frame(image_frame *frame, ani_status *stat,
1388 ls_settings *settings)
1389 {
1390 static unsigned char bkg0[4]; // Default transparent black
1391 unsigned char mask[MAX_WIDTH], alpha[MAX_WIDTH], pal[768];
1392 unsigned char *dest, *src, *dsta, *srca, *bg, *bga, *lmap = stat->lmap;
1393 image_frame *bkf = &stat->prev;
1394 int rxy[4] = { 0, 0, frame->width, frame->height };
1395 int x, y, w, bgw, bgoff, fgw, ww, fgoff, dstoff, bpp, tr;
1396
1397
1398 /* Do the mixing if source is present */
1399 if (!settings->img[CHN_IMAGE]) return;
1400
1401 w = frame->width;
1402 bgw = bkf->width;
1403 bgoff = bkf->y * bgw + bkf->x;
1404 bpp = bkf->bpp;
1405 if (bpp == 1) pal2rgb(pal, bkf->pal, bkf->cols, 256);
1406
1407 /* First, generate the destination RGB */
1408 dest = frame->img[CHN_IMAGE];
1409 bg = bkf->img[CHN_IMAGE] - bgoff * bpp; // Won't get used if not valid
1410 for (y = 0; y < frame->height; y++)
1411 {
1412 int bmask = lmap[y] >> 4;
1413
1414 for (x = 0; x < w; x++)
1415 {
1416 unsigned char *rgb = bkg0; // Default black
1417 int bflag = lmap[x] & bmask;
1418
1419 if (bflag & 4) rgb = stat->bkg; // Background in the hole
1420 else if (bflag & 2) // Underlayer
1421 rgb = bpp == 1 ? pal + bg[x] * 3 : bg + x * 3;
1422 dest[0] = rgb[0];
1423 dest[1] = rgb[1];
1424 dest[2] = rgb[2];
1425 dest += 3;
1426 }
1427 bg += bgw * bpp;
1428 }
1429
1430 /* Then, destination alpha */
1431 dsta = frame->img[CHN_ALPHA];
1432 bga = bkf->img[CHN_ALPHA] ? bkf->img[CHN_ALPHA] - bgoff : NULL;
1433 if (dsta) for (y = 0; y < frame->height; y++)
1434 {
1435 int bmask = lmap[y] >> 4;
1436
1437 for (x = 0; x < w; x++)
1438 {
1439 int bflag = lmap[x] & bmask, a = 0; // Default transparent
1440 if (bflag & 2) a = bga ? bga[x] : 255; // Underlayer
1441 if (bflag & 4) a = stat->bkg[3]; // Background in the hole
1442 *dsta++ = a;
1443 }
1444 if (bga) bga += bgw;
1445 }
1446
1447 /* Then, check if the new frame is in bounds */
1448 if (!clip(rxy, settings->x, settings->y,
1449 settings->x + settings->width, settings->y + settings->height, rxy)) return;
1450
1451 /* Then, paste it over */
1452 fgw = settings->width;
1453 ww = rxy[2] - rxy[0];
1454 fgoff = (rxy[1] - settings->y) * fgw + (rxy[0] - settings->x);
1455 dstoff = rxy[1] * w + rxy[0];
1456 memset(alpha, 255, ww);
1457 tr = settings->rgb_trans;
1458 for (y = rxy[1]; y < rxy[3]; y++)
1459 {
1460 dsta = frame->img[CHN_ALPHA] ? frame->img[CHN_ALPHA] + dstoff : NULL;
1461 srca = settings->img[CHN_ALPHA] ? settings->img[CHN_ALPHA] + fgoff : NULL;
1462 dest = frame->img[CHN_IMAGE] + dstoff * 3;
1463 src = settings->img[CHN_IMAGE] + fgoff * 3;
1464
1465 if (stat->blend) // Do alpha blend
1466 {
1467 memset(mask, 0, ww);
1468 if (tr >= 0) mem_mask_colors(mask, src, 255, ww, 1, 3, tr, tr);
1469 process_mask(0, 1, ww, mask, dsta, dsta, alpha, srca, 255, FALSE);
1470 process_img(0, 1, ww, mask, dest, dest, src, NULL, 3, BLENDF_SET);
1471 }
1472 else // Do a copy
1473 {
1474 memcpy(dest, src, ww * 3); // Copy image
1475 if (!dsta); // No alpha
1476 else if (srca) memcpy(dsta, srca, ww); // Copy alpha
1477 else
1478 {
1479 memset(dsta, 255, ww); // Fill alpha
1480 if (tr >= 0) mem_mask_colors(dsta, src, 0, ww, 1, 3, tr, tr);
1481 }
1482 }
1483 fgoff += fgw; dstoff += w;
1484 }
1485 }
1486
composite_frame(frameset * fset,ani_status * stat,ls_settings * settings)1487 static void composite_frame(frameset *fset, ani_status *stat, ls_settings *settings)
1488 {
1489 image_frame *frame = fset->frames + (fset->cnt - 1);
1490 int disposal;
1491
1492
1493 /* In raw mode, just store the offsets */
1494 if (stat->mode <= ANM_RAW)
1495 {
1496 frame->x = settings->x;
1497 frame->y = settings->y;
1498 }
1499 else
1500 {
1501 /* Read & clear disposal mode */
1502 disposal = frame->flags & FM_DISPOSAL;
1503 frame->flags ^= disposal ^ FM_DISP_REMOVE;
1504
1505 /* For WebP and RGB[A] APNG */
1506 if (settings->bpp == 3) composite_rgba_frame(frame, stat, settings);
1507 /* For GIF & indexed[+T] APNG */
1508 else
1509 {
1510 /* No blend means ignoring transparent color */
1511 if (!stat->blend) settings->xpm_trans = -1;
1512 composite_indexed_frame(frame, stat, settings);
1513 }
1514
1515 /* Drop alpha if not used */
1516 if (frame->img[CHN_ALPHA] && is_filled(frame->img[CHN_ALPHA], 255,
1517 frame->width * frame->height))
1518 {
1519 free(frame->img[CHN_ALPHA]);
1520 frame->img[CHN_ALPHA] = NULL;
1521 }
1522
1523 /* If transparent color and alpha are both present, convert the
1524 * color into alpha, as PNG does not allow combining them */
1525 if ((frame->trans >= 0) && frame->img[CHN_ALPHA])
1526 {
1527 /* RGBA: indexed+alpha blocked elsewhere for same reason */
1528 /* Use palette that add_frame() assigns */
1529 int tr = PNG_2_INT(stat->newpal[frame->trans]);
1530 mem_mask_colors(frame->img[CHN_ALPHA], frame->img[CHN_IMAGE],
1531 0, frame->width, frame->height, 3, tr, tr);
1532 frame->trans = -1;
1533 }
1534
1535 /* Prepare the disposal action */
1536 if (disposal == FM_DISP_REMOVE) // Dispose to background
1537 {
1538 // Image-sized hole in underlayer
1539 stat->bk_rect[2] = (stat->bk_rect[0] = settings->x) +
1540 settings->width;
1541 stat->bk_rect[3] = (stat->bk_rect[1] = settings->y) +
1542 settings->height;
1543 }
1544 if (disposal == FM_DISP_LEAVE) // Don't dispose
1545 memset(&stat->bk_rect, 0, sizeof(stat->bk_rect)); // Clear old
1546 if ((disposal == FM_DISP_REMOVE) || (disposal == FM_DISP_LEAVE))
1547 {
1548 stat->prev = *frame; // Current frame becomes underlayer
1549 if (!stat->prev.pal) stat->prev.pal = fset->pal;
1550 if (stat->prev_idx &&
1551 (fset->frames[stat->prev_idx - 1].flags & FM_NUKE))
1552 /* Remove the unref'd frame */
1553 mem_remove_frame(fset, stat->prev_idx - 1);
1554 stat->prev_idx = fset->cnt;
1555 }
1556 /* if (disposal == FM_DISP_RESTORE); // Dispose to previous
1557 // Underlayer and hole stay unchanged */
1558 }
1559 if ((fset->cnt > 1) && (stat->prev_idx != fset->cnt - 1) &&
1560 (fset->frames[fset->cnt - 2].flags & FM_NUKE))
1561 {
1562 /* Remove the next-to-last frame */
1563 mem_remove_frame(fset, fset->cnt - 2);
1564 if (stat->prev_idx > fset->cnt)
1565 stat->prev_idx = fset->cnt;
1566 }
1567 }
1568
analyze_rgba_frame(ani_status * stat,ls_settings * settings)1569 static int analyze_rgba_frame(ani_status *stat, ls_settings *settings)
1570 {
1571 int same_size, holes, alpha0, alpha1, alpha, bpp;
1572
1573 if (stat->mode <= ANM_RAW) // Raw frame mode
1574 {
1575 stat->defw = settings->width;
1576 stat->defh = settings->height;
1577 return (0); // Output matches input
1578 }
1579 else if ((stat->defw > MAX_WIDTH) || (stat->defh > MAX_HEIGHT))
1580 return (-1); // Too large
1581
1582 ani_map_frame(stat, settings);
1583 same_size = !(settings->x | settings->y |
1584 (stat->defw ^ settings->width) | (stat->defh ^ settings->height));
1585 holes = !same_size || stat->blend;
1586
1587 if (same_size && !holes) return (0); // New replaces old
1588
1589 /* Indexed with transparent color (from APNG) stay as they were:
1590 * no local palettes there, upgrade to RGB/RGBA never needed */
1591 if ((settings->bpp == 1) && (settings->xpm_trans >= 0))
1592 return (same_size ? 0 : 1);
1593
1594 /* Alpha transparency on underlayer */
1595 alpha0 = !stat->prev_idx || stat->prev.img[CHN_ALPHA];
1596 /* Transparency from disposal to background */
1597 if ((stat->bk_rect[0] < stat->bk_rect[2]) &&
1598 (stat->bk_rect[1] < stat->bk_rect[3]))
1599 alpha0 |= stat->bkg[3] < 255;
1600 /* Alpha transparency from this layer */
1601 alpha1 = !stat->blend && settings->img[CHN_ALPHA];
1602 /* Result */
1603 alpha = alpha1 | (alpha0 & holes);
1604
1605 /* Output bpp is max of underlayer & image */
1606 bpp = (stat->prev.bpp == 3) || (settings->bpp == 3) ? 3 : 1;
1607 /* Do not produce indexed+alpha as regular PNG does not support that */
1608 if (alpha) bpp = 4;
1609
1610 /* !!! composite_rgba_frame() as of now cannot handle frame == dest, so
1611 * do not return 0 even if same size, bpp & alpha, w/o rewriting that */
1612 return (bpp);
1613 }
1614
1615 /* In absence of library support, APNG files are read through building in memory
1616 * a regular PNG file for a frame, and then feeding that to libpng - WJ */
1617
1618 /* Macros for accessing values in Motorola byte order */
1619 #define GET16B(buf) (((buf)[0] << 8) + (buf)[1])
1620 #define GET32B(buf) (((unsigned)(buf)[0] << 24) + ((buf)[1] << 16) + \
1621 ((buf)[2] << 8) + (buf)[3])
1622 #define PUT16B(buf, v) (buf)[0] = (v) >> 8; (buf)[1] = (v) & 0xFF;
1623 #define PUT32B(buf, v) (buf)[0] = (v) >> 24; (buf)[1] = ((v) >> 16) & 0xFF; \
1624 (buf)[2] = ((v) >> 8) & 0xFF; (buf)[3] = (v) & 0xFF;
1625
1626 /* Macros for relevant PNG tags; big-endian */
1627 #define TAG4B_IHDR TAG4B('I', 'H', 'D', 'R')
1628 #define TAG4B_IDAT TAG4B('I', 'D', 'A', 'T')
1629 #define TAG4B_IEND TAG4B('I', 'E', 'N', 'D')
1630 #define TAG4B_acTL TAG4B('a', 'c', 'T', 'L')
1631 #define TAG4B_fcTL TAG4B('f', 'c', 'T', 'L')
1632 #define TAG4B_fdAT TAG4B('f', 'd', 'A', 'T')
1633
1634 /* PNG block header */
1635 #define PNG_SIZE 0 /* 32b */
1636 #define PNG_TAG 4 /* 32b */
1637 #define PNG_HSIZE 8
1638
1639 /* IHDR block */
1640 #define IHDR_W 0 /* 32b */
1641 #define IHDR_H 4 /* 32b */
1642 #define IHDR_SIZE 13
1643
1644 /* acTL block */
1645 #define acTL_FCNT 0 /* 32b */
1646 #define acTL_SIZE 8
1647
1648 /* fcTL block */
1649 #define fcTL_SEQ 0 /* 32b */
1650 #define fcTL_W 4 /* 32b */
1651 #define fcTL_H 8 /* 32b */
1652 #define fcTL_X 12 /* 32b */
1653 #define fcTL_Y 16 /* 32b */
1654 #define fcTL_DN 20 /* 16b */
1655 #define fcTL_DD 22 /* 16b */
1656 #define fcTL_DISP 24 /* 8b */
1657 #define fcTL_BLEND 25 /* 8b */
1658 #define fcTL_SIZE 26
1659
1660 typedef struct {
1661 int w, h, disp;
1662 f_long ihdr, idat0, fdat0, fdat1;
1663 unsigned frames;
1664 unsigned char fctl[fcTL_SIZE];
1665 int phase;
1666 unsigned char *png; // Buffer for fake file
1667 size_t sz; // Buffer size
1668 memFILE mf;
1669 } pnghead;
1670
1671 /* Build in-memory PNG from file header and frame data, ignoring CRCs */
assemble_png(FILE * fp,pnghead * pg)1672 static int assemble_png(FILE *fp, pnghead *pg)
1673 {
1674 size_t l = pg->idat0 + (pg->fdat1 - pg->fdat0) + PNG_HSIZE + 4;
1675 unsigned char *src, *dest, *wrk = pg->png;
1676 unsigned tag, tl, u, seq;
1677
1678
1679 /* Enlarge the buffer if needed */
1680 if (l > pg->sz)
1681 {
1682 if (l > MEMFILE_MAX) return (FILE_MEM_ERROR);
1683 dest = realloc(pg->png, l);
1684 if (!dest) return (FILE_MEM_ERROR);
1685 pg->png = dest;
1686 pg->sz = l;
1687 }
1688 /* Read in the header on first pass */
1689 if (!wrk)
1690 {
1691 fseek(fp, 0, SEEK_SET);
1692 if (!fread(pg->png, pg->idat0, 1, fp)) return (-1);
1693 }
1694 /* Modify the header */
1695 wrk = pg->png + pg->ihdr;
1696 memcpy(wrk + IHDR_W, pg->fctl + fcTL_W, 4);
1697 memcpy(wrk + IHDR_H, pg->fctl + fcTL_H, 4);
1698 /* Read in body */
1699 wrk = pg->png + pg->idat0;
1700 fseek(fp, pg->fdat0, SEEK_SET);
1701 l = pg->fdat1 - pg->fdat0;
1702 if (!fread(wrk, l, 1, fp)) return (-1);
1703 /* Reformat the body blocks if needed */
1704 seq = GET32B(pg->fctl + fcTL_SEQ);
1705 src = dest = wrk;
1706 while (l)
1707 {
1708 tag = GET32B(src + PNG_TAG);
1709 tl = GET32B(src + PNG_SIZE);
1710 if (tl > l - PNG_HSIZE - 4) return (-1); // Paranoia
1711 l -= u = PNG_HSIZE + tl + 4;
1712 if (tag == TAG4B_fdAT)
1713 {
1714 if (tl < 4) return (-1); // Paranoia
1715 if (GET32B(src + PNG_HSIZE) != ++seq) return (-1); // Sequence
1716 tl -= 4;
1717 PUT32B(dest + PNG_SIZE, tl);
1718 memcpy(dest + PNG_TAG, "IDAT", 4);
1719 memmove(dest + PNG_HSIZE, src + PNG_HSIZE + 4, tl);
1720 }
1721 else if (src != dest) memmove(dest, src, u);
1722 src += u;
1723 dest += PNG_HSIZE + tl + 4;
1724 }
1725 /* Add IEND */
1726 PUT32B(dest + PNG_SIZE, 0);
1727 memcpy(dest + PNG_TAG, "IEND", 4);
1728 /* Prepare file buffer */
1729 memset(&pg->mf, 0, sizeof(pg->mf));
1730 pg->mf.m.buf = pg->png;
1731 pg->mf.top = pg->mf.m.size = dest + PNG_HSIZE + 4 - pg->png;
1732 return (0);
1733 }
1734
png_scan(FILE * fp,pnghead * pg)1735 static int png_scan(FILE *fp, pnghead *pg)
1736 {
1737 /* APNG disposal codes mapping */
1738 static const unsigned short apng_disposal[3] = {
1739 FM_DISP_LEAVE, FM_DISP_REMOVE, FM_DISP_RESTORE };
1740 unsigned char buf[256];
1741 unsigned tag, tl, w, h;
1742 f_long p = ftell(fp);
1743
1744 if (p <= 0) return (-1); // Sanity check
1745
1746 /* Read block headers & see what we get */
1747 pg->phase = 0;
1748 while (TRUE)
1749 {
1750 if (fread(buf, 1, PNG_HSIZE, fp) < PNG_HSIZE)
1751 {
1752 if (pg->phase != 2) break; // Fail
1753 pg->phase = 4; // Improper end
1754 return (0); // Done
1755 }
1756 tag = GET32B(buf + PNG_TAG);
1757 tl = GET32B(buf + PNG_SIZE);
1758 if (tl > 0x7FFFFFFFU) break; // Limit
1759 if (p > F_LONG_MAX - tl - PNG_HSIZE - 4) break; // File too large
1760
1761 if (tag == TAG4B_IHDR)
1762 {
1763 if (tl < IHDR_SIZE) break; // Bad
1764 if (pg->ihdr) break; // There must be only one
1765 pg->ihdr = p + PNG_HSIZE;
1766 /* Get canvas dimensions */
1767 if (!fread(buf, IHDR_SIZE, 1, fp)) break; // Fail
1768 w = GET32B(buf + IHDR_W);
1769 h = GET32B(buf + IHDR_H);
1770 if ((w > 0x7FFFFFFFU) || (h > 0x7FFFFFFFU)) break; // Limit
1771 pg->w = w;
1772 pg->h = h;
1773 }
1774 else if (tag == TAG4B_IDAT)
1775 {
1776 if (!pg->ihdr) break; // Fail
1777 if (!pg->idat0) pg->idat0 = p;
1778 if (pg->phase == 1) // Had a fcTL
1779 {
1780 pg->fdat0 = p;
1781 pg->phase = 2;
1782 }
1783 if (pg->phase > 1)
1784 {
1785 if (pg->fdat0 != pg->idat0) break; // Mixed IDAT & fdAT
1786 pg->fdat1 = p + PNG_HSIZE + tl + 4;
1787 }
1788 }
1789 else if (tag == TAG4B_acTL)
1790 {
1791 if (tl < acTL_SIZE) break; // Bad
1792 if (!fread(buf, acTL_SIZE, 1, fp)) break; // Fail
1793 /* Store frames count */
1794 if (!pg->frames) pg->frames = GET32B(buf + acTL_FCNT);
1795 if (pg->frames > 0x7FFFFFFFU) break; // Limit
1796 if (!pg->frames) break; // Fail
1797 }
1798 else if (tag == TAG4B_fcTL)
1799 {
1800 if (pg->phase > 1)
1801 {
1802 /* End of frame data - step back & return */
1803 fseek(fp, p, SEEK_SET);
1804 return (0);
1805 }
1806 if (tl < fcTL_SIZE) break; // Bad
1807 /* Store for later use */
1808 if (!fread(pg->fctl, fcTL_SIZE, 1, fp)) break; // Fail
1809 if (pg->fctl[fcTL_DISP] > 2) break; // Unknown value
1810 pg->disp = apng_disposal[pg->fctl[fcTL_DISP]];
1811 pg->phase = 1; // Ready for a new frame
1812 }
1813 else if (tag == TAG4B_fdAT)
1814 {
1815 if (!pg->ihdr) break; // Fail
1816 if (!pg->phase) break; // Fail - no fcTL
1817 if (pg->phase == 1) // Had a fcTL
1818 {
1819 pg->fdat0 = p;
1820 pg->phase = 2;
1821 }
1822 if (pg->fdat0 == pg->idat0) break; // Mixed IDAT & fdAT
1823 pg->fdat1 = p + PNG_HSIZE + tl + 4;
1824 }
1825 else if (tag == TAG4B_IEND)
1826 {
1827 if (pg->phase != 2) break; // Fail
1828 pg->phase = 3; // End
1829 return (0); // Done
1830 }
1831 /* Skip tag header, data, & CRC field */
1832 p += PNG_HSIZE + tl + 4;
1833 if (fseek(fp, p, SEEK_SET)) break;
1834 }
1835 return (-1); // Failed
1836 }
1837
load_apng_frame(FILE * fp,pnghead * pg,ls_settings * settings)1838 static int load_apng_frame(FILE *fp, pnghead *pg, ls_settings *settings)
1839 {
1840 unsigned char *w;
1841 int l, res;
1842
1843 /* Try scanning the frame */
1844 res = png_scan(fp, pg);
1845 /* Prepare fake PNG */
1846 if (!res) res = assemble_png(fp, pg);
1847 /* Load the frame */
1848 if (!res) res = load_png(NULL, settings, &pg->mf, TRUE);
1849 if (res != 1) return (res); // Fail on any error
1850 /* Convert indexed+alpha to RGBA, to let it be regular PNG */
1851 w = settings->img[CHN_ALPHA];
1852 if ((settings->bpp == 1) && w)
1853 {
1854 l = settings->width * settings->height;
1855 w = malloc((size_t)l * 3);
1856 if (!w) return (FILE_MEM_ERROR); // No memory
1857 do_convert_rgb(0, 1, l, w, settings->img[CHN_IMAGE], settings->pal);
1858 free(settings->img[CHN_IMAGE]);
1859 settings->img[CHN_IMAGE] = w;
1860 settings->bpp = 3;
1861 }
1862 /* Ensure transparent color is in palette */
1863 else map_rgb_trans(settings);
1864 return (res);
1865 }
1866
load_apng_frames(char * file_name,ani_settings * ani)1867 static int load_apng_frames(char *file_name, ani_settings *ani)
1868 {
1869 char buf[PNG_BYTES_TO_CHECK + 1];
1870 pnghead pg;
1871 ani_status stat;
1872 ls_settings w_set;
1873 unsigned wx, wy;
1874 int n, d, bpp, frames = 0, res = -1;
1875 FILE *fp;
1876
1877
1878 if (!(fp = fopen(file_name, "rb"))) return (-1);
1879 memset(w_set.img, 0, sizeof(chanlist));
1880 memset(&pg, 0, sizeof(pg));
1881
1882 if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) goto fail;
1883 if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK)) goto fail;
1884
1885 w_set = ani->settings;
1886 res = load_apng_frame(fp, &pg, &w_set);
1887 if (res != 1) goto fail;
1888
1889 /* Init state structure */
1890 memset(&stat, 0, sizeof(stat));
1891 stat.mode = ani->mode;
1892 stat.defw = pg.w;
1893 stat.defh = pg.h;
1894 /* Use whatever palette we read */
1895 mem_pal_copy(stat.newpal, w_set.pal);
1896 stat.newcols = w_set.colors;
1897 stat.newtrans = w_set.xpm_trans;
1898 ani_init_xlat(&stat); // Init palette remapping to 1:1 and leave at that
1899
1900 /* Init frameset - palette in APNG is global */
1901 res = FILE_MEM_ERROR;
1902 if (!(ani->fset.pal = malloc(SIZEOF_PALETTE))) goto fail;
1903 mem_pal_copy(ani->fset.pal, stat.newpal);
1904
1905 /* Go through images */
1906 while (frames++ < pg.frames)
1907 {
1908 res = FILE_TOO_LONG;
1909 if (!check_next_frame(&ani->fset, ani->settings.mode, TRUE))
1910 goto fail;
1911
1912 /* Get the next frame, after the first */
1913 if (frames > 1)
1914 {
1915 w_set = ani->settings;
1916 res = load_apng_frame(fp, &pg, &w_set);
1917 if (res != 1) goto fail;
1918 }
1919 delete_alpha(&w_set, 255);
1920
1921 stat.blend = pg.fctl[fcTL_BLEND] && (w_set.img[CHN_ALPHA] ||
1922 (stat.newtrans >= 0));
1923 /* Within mtPaint delays are 1/100s granular */
1924 n = GET16B(pg.fctl + fcTL_DN);
1925 d = GET16B(pg.fctl + fcTL_DD);
1926 if (!d) d = 100;
1927 w_set.gif_delay = (n * 100 + d - 1) / d; // Round up
1928
1929 wx = GET32B(pg.fctl + fcTL_X);
1930 wy = GET32B(pg.fctl + fcTL_Y);
1931 if (wx > MAX_WIDTH) wx = MAX_WIDTH; // Out is out
1932 if (wy > MAX_HEIGHT) wy = MAX_HEIGHT; // Same
1933 w_set.x = wx;
1934 w_set.y = wy;
1935
1936 /* Analyze how we can merge the frames */
1937 res = TOO_BIG;
1938 bpp = analyze_rgba_frame(&stat, &w_set);
1939 if (bpp < 0) goto fail;
1940
1941 /* Allocate a new frame */
1942 res = add_frame(ani, &stat, &w_set, bpp, pg.disp);
1943 if (res) goto fail;
1944
1945 /* Do actual compositing, remember disposal method */
1946 composite_frame(&ani->fset, &stat, &w_set);
1947 mem_free_chanlist(w_set.img);
1948 memset(w_set.img, 0, sizeof(chanlist));
1949
1950 /* Write out those frames worthy to be stored */
1951 res = done_frame(file_name, ani, FALSE);
1952 if (res != 1) goto fail;
1953
1954 if (pg.phase > 2) break; // End of file
1955 }
1956 /* Write out the final frame if not written before */
1957 res = done_frame(file_name, ani, TRUE);
1958
1959 fail: free(pg.png);
1960 mem_free_chanlist(w_set.img);
1961 fclose(fp);
1962 return (res);
1963 }
1964
analyze_gif_frame(ani_status * stat,ls_settings * settings)1965 static int analyze_gif_frame(ani_status *stat, ls_settings *settings)
1966 {
1967 unsigned char cmap[513], *lmap, *fg, *bg;
1968 png_color *pal, *prev;
1969 int tmpal[257], same_size, show_under;
1970 int i, k, l, x, y, ul, lpal, lprev, fgw, bgw, prevtr = -1;
1971
1972
1973 /* Locate the new palette */
1974 pal = prev = stat->global_pal;
1975 lpal = lprev = stat->global_cols;
1976 if (settings->colors > 0)
1977 {
1978 pal = settings->pal;
1979 lpal = settings->colors;
1980 }
1981
1982 /* Accept new palette as final, for now */
1983 mem_pal_copy(stat->newpal, pal);
1984 stat->newcols = lpal;
1985 stat->newtrans = settings->xpm_trans;
1986
1987 /* Prepare for new frame */
1988 if (stat->mode <= ANM_RAW) // Raw frame mode
1989 {
1990 stat->defw = settings->width;
1991 stat->defh = settings->height;
1992 return (0);
1993 }
1994 else if ((stat->defw > MAX_WIDTH) || (stat->defh > MAX_HEIGHT))
1995 return (-1); // Too large
1996 ani_map_frame(stat, settings);
1997 same_size = !(settings->x | settings->y |
1998 (stat->defw ^ settings->width) | (stat->defh ^ settings->height));
1999
2000 ani_init_xlat(stat); // Init palette remapping to 1:1
2001
2002 /* First frame is exceptional */
2003 if (!stat->prev_idx)
2004 {
2005 // Trivial if no background gets drawn
2006 if (same_size) return (0);
2007 // Trivial if have transparent color
2008 if (settings->xpm_trans >= 0) return (1);
2009 }
2010
2011 /* Disable transparency by default, enable when needed */
2012 stat->newtrans = -1;
2013
2014 /* Now scan the dest area, filling colors bitmap */
2015 memset(cmap, 0, sizeof(cmap));
2016 fgw = settings->width;
2017 fg = settings->img[CHN_IMAGE] - (settings->y * fgw + settings->x);
2018 // Set underlayer pointer & step (ignore bpp!)
2019 bgw = stat->prev.width;
2020 bg = stat->prev.img[CHN_IMAGE] - (stat->prev.y * bgw + stat->prev.x);
2021 lmap = stat->lmap;
2022 for (y = 0; y < stat->defh; y++)
2023 {
2024 int ww = stat->defw, tp = settings->xpm_trans;
2025 int bmask = lmap[y] >> 4;
2026
2027 for (x = 0; x < ww; x++)
2028 {
2029 int c0, bflag = lmap[x] & bmask;
2030
2031 if ((bflag & 1) && ((c0 = fg[x]) != tp)) // New frame
2032 c0 += 256;
2033 else if ((bflag & 6) == 2) // Underlayer
2034 c0 = bg[x];
2035 else c0 = 512; // Background (transparency)
2036 cmap[c0] = 1;
2037 }
2038 fg += fgw; bg += bgw;
2039 }
2040
2041 /* If we have underlayer */
2042 show_under = 0;
2043 if (stat->prev_idx)
2044 {
2045 // Use per-frame palette if underlayer has it
2046 prev = stat->prev.pal;
2047 lprev = stat->prev.cols;
2048 prevtr = stat->prev.trans;
2049 // Move underlayer transparency to "transparent"
2050 if (prevtr >= 0)
2051 {
2052 cmap[512] |= cmap[prevtr];
2053 cmap[prevtr] = 0;
2054 }
2055 // Check if underlayer is at all visible
2056 show_under = !!memchr(cmap, 1, 256);
2057 // Visible RGB/RGBA underlayer means RGB/RGBA frame
2058 if (show_under && (stat->prev.bpp == 3)) goto RGB;
2059 }
2060
2061 /* Now, check if either frame's palette is enough */
2062 ul = 2; // Default is new palette
2063 if (show_under)
2064 {
2065 l = lprev > lpal ? lprev : lpal;
2066 k = lprev > lpal ? lpal : lprev;
2067 for (ul = 3 , i = 0; ul && (i < l); i++)
2068 {
2069 int tf2 = cmap[i] * 2 + cmap[256 + i];
2070 if (tf2 && ((i >= k) ||
2071 (PNG_2_INT(prev[i]) != PNG_2_INT(pal[i]))))
2072 ul &= ~tf2; // Exclude mismatched palette(s)
2073 }
2074 if (ul == 1) // Need old palette
2075 {
2076 mem_pal_copy(stat->newpal, prev);
2077 stat->newcols = lprev;
2078 }
2079 }
2080 while (ul) // Place transparency
2081 {
2082 if (cmap[512]) // Need transparency
2083 {
2084 int i, l = prevtr, nc = stat->newcols;
2085
2086 /* If cannot use old transparent index */
2087 if ((l < 0) || (l >= nc) || (cmap[l] | cmap[l + 256]))
2088 l = settings->xpm_trans;
2089 /* If cannot use new one either */
2090 if ((l < 0) || (l >= nc) || (cmap[l] | cmap[l + 256]))
2091 {
2092 /* Try to find unused palette slot */
2093 for (l = -1 , i = 0; (l < 0) && (i < nc); i++)
2094 if (!(cmap[i] | cmap[i + 256])) l = i;
2095 }
2096 if (l < 0) /* Try to add a palette slot */
2097 {
2098 png_color *c;
2099
2100 if (nc >= 256) break; // Failure
2101 l = stat->newcols++;
2102 c = stat->newpal + l;
2103 c->red = c->green = c->blue = 0;
2104 }
2105 // Modify mapping
2106 if (prevtr >= 0) stat->xlat[prevtr] = l;
2107 stat->xlat[512] = stat->newtrans = l;
2108 }
2109 // Successfully mapped everything - use paletted mode
2110 return (same_size ? 0 : 1);
2111 }
2112
2113 /* Try to build combined palette */
2114 for (ul = i = 0; (ul < 257) && (i < 512); i++)
2115 {
2116 png_color *c;
2117 int j, v;
2118
2119 if (!cmap[i]) continue;
2120 c = (i < 256 ? prev : pal - 256) + i;
2121 v = PNG_2_INT(*c);
2122 for (j = 0; (j < ul) && (tmpal[j] != v); j++);
2123 if (j == ul) tmpal[ul++] = v;
2124 stat->xlat[i] = j;
2125 }
2126 // Add transparent color
2127 if ((ul < 257) && cmap[512])
2128 {
2129 // Modify mapping
2130 if (prevtr >= 0) stat->xlat[prevtr] = ul;
2131 stat->xlat[512] = stat->newtrans = ul;
2132 tmpal[ul++] = 0;
2133 }
2134 if (ul < 257) // Success!
2135 {
2136 png_color *c = stat->newpal;
2137 for (i = 0; i < ul; i++ , c++) // Build palette
2138 {
2139 int v = tmpal[i];
2140 c->red = INT_2_R(v);
2141 c->green = INT_2_G(v);
2142 c->blue = INT_2_B(v);
2143 }
2144 stat->newcols = ul;
2145 // Use paletted mode
2146 return (same_size ? 0 : 1);
2147 }
2148
2149 /* Tried everything in vain - fall back to RGB/RGBA */
2150 RGB: if (stat->global_cols > 0) // Use default palette if present
2151 {
2152 mem_pal_copy(stat->newpal, stat->global_pal);
2153 stat->newcols = stat->global_cols;
2154 }
2155 stat->newtrans = -1; // No color-key transparency
2156 // RGBA if underlayer with alpha, or transparent backround, is visible
2157 if ((show_under && stat->prev.img[CHN_ALPHA]) || cmap[512])
2158 return (4);
2159 // RGB otherwise
2160 return (3);
2161 }
2162
2163 /* Macros for accessing values in Intel byte order */
2164 #define GET16(buf) (((buf)[1] << 8) + (buf)[0])
2165 #define GET32(buf) (((unsigned)(buf)[3] << 24) + ((buf)[2] << 16) + \
2166 ((buf)[1] << 8) + (buf)[0])
2167 #define GET32s(buf) (((signed char)(buf)[3] * 0x1000000) + ((buf)[2] << 16) + \
2168 ((buf)[1] << 8) + (buf)[0])
2169 #define PUT16(buf, v) (buf)[0] = (v) & 0xFF; (buf)[1] = (v) >> 8;
2170 #define PUT32(buf, v) (buf)[0] = (v) & 0xFF; (buf)[1] = ((v) >> 8) & 0xFF; \
2171 (buf)[2] = ((v) >> 16) & 0xFF; (buf)[3] = (v) >> 24;
2172
2173 #define GIF_ID "GIF87a"
2174 #define GIF_IDLEN 6
2175
2176 /* GIF header */
2177 #define GIF_VER 4 /* Where differing version digit goes */
2178 #define GIF_WIDTH 6 /* 16b */
2179 #define GIF_HEIGHT 8 /* 16b */
2180 #define GIF_GPBITS 10
2181 #define GIF_BKG 11
2182 #define GIF_ASPECT 12
2183 #define GIF_HDRLEN 13 /* Global palette starts here */
2184
2185 #define GIF_GPFLAG 0x80
2186 #define GIF_8BPC 0x70 /* Color resolution to write out */
2187
2188 /* Graphics Control Extension */
2189 #define GIF_GC_FLAGS 0
2190 #define GIF_GC_DELAY 1 /* 16b */
2191 #define GIF_GC_TRANS 3
2192 #define GIF_GC_LEN 4
2193
2194 #define GIF_GC_TFLAG 1
2195 #define GIF_GC_DISP 2 /* Shift amount */
2196
2197 /* Application Extension */
2198 #define GIF_AP_LEN 11
2199
2200 /* Image */
2201 #define GIF_IX 0 /* 16b */
2202 #define GIF_IY 2 /* 16b */
2203 #define GIF_IWIDTH 4 /* 16b */
2204 #define GIF_IHEIGHT 6 /* 16b */
2205 #define GIF_IBITS 8
2206 #define GIF_IHDRLEN 9
2207
2208 #define GIF_LPFLAG 0x80
2209 #define GIF_ILFLAG 0x40 /* Interlace */
2210
2211 /* Read body of GIF block into buffer (or skip if NULL), return length */
getblock(unsigned char * buf,FILE * fp)2212 static int getblock(unsigned char *buf, FILE *fp)
2213 {
2214 int l = getc(fp);
2215 if (l == EOF) l = -1;
2216 if (l > 0)
2217 {
2218 if (!buf) fseek(fp, l, SEEK_CUR); // Just skip
2219 else if (fread(buf, 1, l, fp) < l) l = -1; // Error
2220 }
2221 return (l);
2222 }
2223
2224 #ifdef U_LCMS /* No other uses for it now */
2225 /* Load a sequence of GIF blocks into memory */
getgifdata(FILE * fp,char ** res,int * len)2226 static int getgifdata(FILE *fp, char **res, int *len)
2227 {
2228 unsigned char *src, *dest, *mem;
2229 f_long r, p = ftell(fp);
2230 int l, size;
2231
2232 *res = NULL;
2233 *len = 0;
2234 if (p < 0) return (1); /* Leave 2Gb+ GIFs to systems with longer f_long */
2235
2236 /* Measure */
2237 while ((l = getblock(NULL, fp)) > 0);
2238 if (l < 0) return (-1); // Error
2239 r = ftell(fp);
2240 fseek(fp, p, SEEK_SET);
2241 if (r <= p) return (1); // Paranoia
2242 if (r - p > INT_MAX) return (1); // A 2Gb+ profile is unusable anyway :-)
2243
2244 /* Allocate */
2245 size = r - p;
2246 mem = malloc(size);
2247 if (!mem) return (1); // No memory for this
2248
2249 /* Read */
2250 if (fread(mem, 1, size, fp) < size) goto fail; // Error
2251
2252 /* Merge */
2253 src = dest = mem;
2254 while ((l = *src++))
2255 {
2256 if (src - mem >= size - l) goto fail; // Paranoia
2257 memmove(dest, src, l);
2258 src += l; dest += l;
2259 }
2260 size = dest - mem; // Maybe realloc?
2261
2262 /* Done */
2263 *res = mem;
2264 *len = size;
2265 return (0);
2266
2267 fail: free(mem);
2268 return (-1); // Someone overwrote the file damaging it
2269 }
2270 #endif
2271
2272 /* Space enough to hold palette, or longest block + longest decoded sequence */
2273 #define GIF_BUFSIZE (256 + 4096)
2274 typedef struct {
2275 FILE *f;
2276 int ptr, end, tail;
2277 int lc0, lc, nxc, clear, cmask;
2278 int w, bits, prev;
2279 short nxcode[4096 + 1];
2280 unsigned char buf[GIF_BUFSIZE], cchar[4096 + 1];
2281 } gifbuf;
2282
resetlzw(gifbuf * gif)2283 static void resetlzw(gifbuf *gif)
2284 {
2285 gif->nxc = gif->clear + 2; // First usable code
2286 gif->lc = gif->lc0 + 1; // Actual code size
2287 gif->cmask = (1 << gif->lc) - 1; // Actual code mask
2288 gif->prev = -1; // Previous code
2289 }
2290
initlzw(gifbuf * gif,FILE * fp)2291 static int initlzw(gifbuf *gif, FILE *fp)
2292 {
2293 int i;
2294
2295 gif->f = fp;
2296 gif->lc0 = i = getc(fp); // Min code size
2297 /* Enforce hard upper limit but allow wasteful encoding */
2298 if ((i == EOF) || (i > 11)) return (FALSE);
2299 gif->clear = i = 1 << i; // Clear code
2300 /* Initial 1-char codes */
2301 while (--i >= 0) gif->nxcode[i] = -1 , gif->cchar[i] = (unsigned char)i;
2302 resetlzw(gif);
2303 gif->w = gif->bits = 0; // Ready bits in shifter
2304 gif->ptr = gif->end = gif->tail = 0; // Ready data in buffer
2305 return (TRUE);
2306 }
2307
getlzw(unsigned char * dest,int cnt,gifbuf * gif)2308 static int getlzw(unsigned char *dest, int cnt, gifbuf *gif)
2309 {
2310 int l, c, cx, w, bits, lc, cmask, prev, nxc, tail = gif->tail;
2311
2312 while (TRUE)
2313 {
2314 l = tail > cnt ? cnt : tail;
2315 cnt -= l;
2316 l = tail - l;
2317 while (tail > l) *dest++ = gif->buf[GIF_BUFSIZE - tail--];
2318 if (cnt <= 0) break; // No tail past this point
2319 w = gif->w;
2320 bits = gif->bits;
2321 lc = gif->lc;
2322 while (bits < lc)
2323 {
2324 if (gif->ptr >= gif->end)
2325 {
2326 gif->end = getblock(gif->buf, gif->f);
2327 if (gif->end <= 0) return (FALSE); // No data
2328 gif->ptr = 0;
2329 }
2330 w |= gif->buf[gif->ptr++] << bits;
2331 bits += 8;
2332 }
2333 cmask = gif->cmask;
2334 c = w & cmask;
2335 gif->w = w >> lc;
2336 gif->bits = bits - lc;
2337 if (c == gif->clear)
2338 {
2339 resetlzw(gif);
2340 continue;
2341 }
2342 if (c == gif->clear + 1) return (FALSE); // Premature EOI
2343 /* Update for next code */
2344 prev = gif->prev;
2345 gif->prev = c;
2346 nxc = gif->nxc;
2347 gif->nxcode[nxc] = prev;
2348 if ((prev >= 0) && (nxc < 4096))
2349 {
2350 if ((++gif->nxc > cmask) && (cmask < 4096 - 1))
2351 gif->cmask = (1 << ++gif->lc) - 1;
2352 }
2353 /* Decode this one */
2354 if (c > nxc) return (FALSE); // Broken code
2355 if ((c == nxc) && (prev < 0)) return (FALSE); // Too early
2356 for (cx = c; cx >= 0; cx = gif->nxcode[cx])
2357 gif->buf[GIF_BUFSIZE - ++tail] = gif->cchar[cx];
2358 gif->cchar[nxc] = gif->buf[GIF_BUFSIZE - tail];
2359 /* In case c == nxc, its char was garbage till now, so reread it */
2360 gif->buf[GIF_BUFSIZE - 1] = gif->cchar[c];
2361 }
2362 gif->tail = tail;
2363 return (TRUE);
2364 }
2365
load_gif_frame(FILE * fp,ls_settings * settings)2366 static int load_gif_frame(FILE *fp, ls_settings *settings)
2367 {
2368 /* GIF interlace pattern: Y0, DY, ... */
2369 static const unsigned char interlace[10] =
2370 { 0, 1, 0, 8, 4, 8, 2, 4, 1, 2 };
2371 unsigned char hdr[GIF_IHDRLEN];
2372 gifbuf gif;
2373 int i, k, kx, n, w, h, dy, res;
2374
2375
2376 /* Read the header */
2377 if (fread(hdr, 1, GIF_IHDRLEN, fp) < GIF_IHDRLEN) return (-1);
2378
2379 /* Get local palette if any */
2380 if (hdr[GIF_IBITS] & GIF_LPFLAG)
2381 {
2382 int cols = 2 << (hdr[GIF_IBITS] & 7);
2383 if (fread(gif.buf, 3, cols, fp) < cols) return (-1);
2384 rgb2pal(settings->pal, gif.buf, settings->colors = cols);
2385 }
2386 if (settings->colors < 0) return (-1); // No palette at all
2387 /* If palette is all we need */
2388 if ((settings->mode == FS_PALETTE_LOAD) ||
2389 (settings->mode == FS_PALETTE_DEF)) return (EXPLODE_FAILED);
2390
2391 if (!initlzw(&gif, fp)) return (-1);
2392
2393 /* Store actual image parameters */
2394 settings->x = GET16(hdr + GIF_IX);
2395 settings->y = GET16(hdr + GIF_IY);
2396 settings->width = w = GET16(hdr + GIF_IWIDTH);
2397 settings->height = h = GET16(hdr + GIF_IHEIGHT);
2398 settings->bpp = 1;
2399
2400 if ((res = allocate_image(settings, CMASK_IMAGE))) return (res);
2401 res = FILE_LIB_ERROR;
2402
2403 if (!settings->silent) ls_init("GIF", 0);
2404
2405 if (hdr[GIF_IBITS] & GIF_ILFLAG) k = 2 , kx = 10; /* Interlace */
2406 else k = 0 , kx = 2;
2407
2408 for (n = 0; k < kx; k += 2)
2409 {
2410 dy = interlace[k + 1];
2411 for (i = interlace[k]; i < h; n++ , i += dy)
2412 {
2413 if (!getlzw(settings->img[CHN_IMAGE] + i * w, w, &gif))
2414 goto fail;
2415 ls_progress(settings, n, 10);
2416 }
2417 }
2418 /* Skip data blocks till 0 */
2419 while ((i = getblock(NULL, fp)) > 0);
2420 if (!i) res = 1;
2421 fail: if (!settings->silent) progress_end();
2422 return (res);
2423 }
2424
load_gif_frames(char * file_name,ani_settings * ani)2425 static int load_gif_frames(char *file_name, ani_settings *ani)
2426 {
2427 /* GIF disposal codes mapping */
2428 static const unsigned short gif_disposal[8] = {
2429 FM_DISP_LEAVE, FM_DISP_LEAVE, FM_DISP_REMOVE, FM_DISP_RESTORE,
2430 /* Handling (reserved) "4" same as "3" is what Mozilla does */
2431 FM_DISP_RESTORE, FM_DISP_LEAVE, FM_DISP_LEAVE, FM_DISP_LEAVE
2432 };
2433 unsigned char hdr[GIF_HDRLEN], buf[768];
2434 png_color w_pal[256];
2435 ani_status stat;
2436 ls_settings w_set, init_set;
2437 int l, id, disposal, bpp, res = -1;
2438 FILE *fp;
2439
2440 if (!(fp = fopen(file_name, "rb"))) return (-1);
2441 memset(w_set.img, 0, sizeof(chanlist));
2442
2443 /* Read the header */
2444 if (fread(hdr, 1, GIF_HDRLEN, fp) < GIF_HDRLEN) goto fail;
2445
2446 /* Check signature */
2447 if (hdr[GIF_VER] == '9') hdr[GIF_VER] = '7'; // Does not matter anyway
2448 if (memcmp(hdr, GIF_ID, GIF_IDLEN)) goto fail;
2449
2450 /* Init state structure */
2451 memset(&stat, 0, sizeof(stat));
2452 stat.mode = ani->mode;
2453 stat.defw = GET16(hdr + GIF_WIDTH);
2454 stat.defh = GET16(hdr + GIF_HEIGHT);
2455 stat.global_cols = -1;
2456 /* Get global palette */
2457 if (hdr[GIF_GPBITS] & GIF_GPFLAG)
2458 {
2459 int cols = 2 << (hdr[GIF_GPBITS] & 7);
2460 if (fread(buf, 3, cols, fp) < cols) goto fail;
2461 rgb2pal(stat.global_pal, buf, stat.global_cols = cols);
2462 }
2463 stat.blend = TRUE; // No other case in GIF
2464
2465 /* Init temp container */
2466 init_set = ani->settings;
2467 init_set.colors = 0; // Nonzero will signal local palette
2468 init_set.pal = w_pal;
2469 init_set.xpm_trans = -1;
2470 init_set.gif_delay = 0;
2471 disposal = FM_DISP_LEAVE;
2472
2473 /* Init frameset */
2474 if (stat.global_cols > 0) // Set default palette
2475 {
2476 res = FILE_MEM_ERROR;
2477 if (!(ani->fset.pal = malloc(SIZEOF_PALETTE))) goto fail;
2478 mem_pal_copy(ani->fset.pal, stat.global_pal);
2479 }
2480
2481 /* Go through images */
2482 while (TRUE)
2483 {
2484 res = -1;
2485 id = getc(fp);
2486 if (!id) continue; // Extra end-blocks do happen sometimes
2487 if (id == ';') break; // Trailer block
2488 if (id == '!') // Extension block
2489 {
2490 if ((id = getc(fp)) == EOF) goto fail;
2491 if (id == 0xF9) // Graphics control - read it
2492 {
2493 if (getblock(buf, fp) < GIF_GC_LEN) goto fail;
2494 /* !!! In practice, Graphics Control Extension
2495 * affects not only "the first block to follow"
2496 * as docs say, but EVERY following block - WJ */
2497 init_set.xpm_trans = buf[GIF_GC_FLAGS] & GIF_GC_TFLAG ?
2498 buf[GIF_GC_TRANS] : -1;
2499 init_set.gif_delay = GET16(buf + GIF_GC_DELAY);
2500 disposal = gif_disposal[(buf[GIF_GC_FLAGS] >> GIF_GC_DISP) & 7];
2501 }
2502 while ((l = getblock(NULL, fp)) > 0); // Skip till end
2503 if (l < 0) goto fail;
2504 }
2505 else if (id == ',') // Image
2506 {
2507 res = FILE_TOO_LONG;
2508 if (!check_next_frame(&ani->fset, ani->settings.mode, TRUE))
2509 goto fail;
2510 w_set = init_set;
2511 res = load_gif_frame(fp, &w_set);
2512 if (res != 1) goto fail;
2513 /* Analyze how we can merge the frames */
2514 res = TOO_BIG;
2515 bpp = analyze_gif_frame(&stat, &w_set);
2516 if (bpp < 0) goto fail;
2517
2518 /* Allocate a new frame */
2519 res = add_frame(ani, &stat, &w_set, bpp, disposal);
2520 if (res) goto fail;
2521
2522 /* Do actual compositing, remember disposal method */
2523 composite_frame(&ani->fset, &stat, &w_set);
2524 mem_free_chanlist(w_set.img);
2525 memset(w_set.img, 0, sizeof(chanlist));
2526
2527 /* Write out those frames worthy to be stored */
2528 res = done_frame(file_name, ani, FALSE);
2529 if (res != 1) goto fail;
2530 }
2531 else goto fail; // Garbage or EOF
2532 }
2533 /* Write out the final frame if not written before */
2534 res = done_frame(file_name, ani, TRUE);
2535
2536 fail: mem_free_chanlist(w_set.img);
2537 fclose(fp);
2538 return (res);
2539 }
2540
load_gif(char * file_name,ls_settings * settings)2541 static int load_gif(char *file_name, ls_settings *settings)
2542 {
2543 unsigned char hdr[GIF_HDRLEN], buf[768];
2544 int trans = -1, delay = settings->gif_delay, frame = 0;
2545 int l, id, res = -1;
2546 FILE *fp;
2547
2548 if (!(fp = fopen(file_name, "rb"))) return (-1);
2549
2550 /* Read the header */
2551 if (fread(hdr, 1, GIF_HDRLEN, fp) < GIF_HDRLEN) goto fail;
2552
2553 /* Check signature */
2554 if (hdr[GIF_VER] == '9') hdr[GIF_VER] = '7'; // Does not matter anyway
2555 if (memcmp(hdr, GIF_ID, GIF_IDLEN)) goto fail;
2556
2557 /* Get global palette */
2558 settings->colors = -1;
2559 if (hdr[GIF_GPBITS] & GIF_GPFLAG)
2560 {
2561 int cols = 2 << (hdr[GIF_GPBITS] & 7);
2562 if (fread(buf, 3, cols, fp) < cols) goto fail;
2563 rgb2pal(settings->pal, buf, settings->colors = cols);
2564 }
2565
2566 /* Go read the first image */
2567 while (TRUE)
2568 {
2569 res = frame ? FILE_LIB_ERROR : -1;
2570 id = getc(fp);
2571 if (!id) continue; // Extra end-blocks do happen sometimes
2572 if (id == ';') break; // Trailer block
2573 if (id == '!') // Extension block
2574 {
2575 if ((id = getc(fp)) == EOF) goto fail;
2576 if (id == 0xF9) // Graphics control - read it
2577 {
2578 if (getblock(buf, fp) < GIF_GC_LEN) goto fail;
2579 trans = buf[GIF_GC_FLAGS] & GIF_GC_TFLAG ?
2580 buf[GIF_GC_TRANS] : -1;
2581 delay = GET16(buf + GIF_GC_DELAY);
2582 }
2583 #ifdef U_LCMS
2584 /* Yes GIF can have a color profile - imagine that */
2585 else if ((id == 0xFF) // Application extension
2586 && !settings->icc_size // No need of it otherwise
2587 && (getblock(buf, fp) >= GIF_AP_LEN) // Not broken
2588 && !memcmp(buf, "ICCRGBG1012", GIF_AP_LEN)) // The right ID
2589 {
2590 l = getgifdata(fp, &settings->icc, &settings->icc_size);
2591 if (l < 0) goto fail;
2592 if (!l) continue; // No trailing blocks to skip
2593 }
2594 #endif
2595 while ((l = getblock(NULL, fp)) > 0); // Skip till end
2596 if (l < 0) goto fail;
2597 }
2598 else if (id == ',') // Image
2599 {
2600 if (frame++) /* Multipage GIF - notify user */
2601 {
2602 res = FILE_HAS_FRAMES;
2603 goto fail;
2604 }
2605 settings->gif_delay = delay;
2606 settings->xpm_trans = trans;
2607 res = load_gif_frame(fp, settings);
2608 if (res != 1) goto fail;
2609 }
2610 else goto fail; // Garbage or EOF
2611 }
2612 if (frame) res = 1; // No images is fail
2613 fail: fclose(fp);
2614 return (res);
2615 }
2616
2617 /* Space enough to hold palette and all headers, or longest block */
2618 #define GIF_WBUFSIZE (768 + GIF_HDRLEN + (GIF_GC_LEN + 4) + (GIF_IHDRLEN + 2))
2619
2620 /* A cuckoo hash would take 4x less space, but need much more code */
2621 #define GIF_CODESSIZE ((4096 * 2 * 16) * sizeof(short))
2622 typedef struct {
2623 FILE *f;
2624 int cnt, nxmap;
2625 int lc0, lc, nxc, clear, nxc2;
2626 int w, bits, prev;
2627 short *codes;
2628 unsigned char buf[GIF_WBUFSIZE];
2629 } gifcbuf;
2630
resetclzw(gifcbuf * gif)2631 static void resetclzw(gifcbuf *gif)
2632 {
2633 /* Send clear code at current length */
2634 gif->w |= gif->clear << gif->bits;
2635 gif->bits += gif->lc;
2636 /* Reset parameters */
2637 gif->nxc = gif->clear + 2; // First usable code
2638 gif->lc = gif->lc0 + 1; // Actual code size
2639 gif->nxc2 = 1 << gif->lc; // For next code size
2640 memset(gif->codes, 0, GIF_CODESSIZE); // Maps
2641 gif->nxmap = 1; // First usable intermediate map
2642 }
2643
initclzw(gifcbuf * gif,int lc0,FILE * fp)2644 static void initclzw(gifcbuf *gif, int lc0, FILE *fp)
2645 {
2646 if (lc0 < 2) lc0 = 2; // Minimum allowed
2647 gif->f = fp;
2648 gif->lc0 = lc0;
2649 fputc(lc0, fp);
2650 gif->clear = 1 << lc0; // Clear code
2651 gif->prev = -1; // No previous code
2652 gif->cnt = gif->w = gif->bits = 0; // No data yet
2653 gif->lc = gif->lc0 + 1; // Actual code size
2654 resetclzw(gif); // Initial clear
2655 }
2656
emitlzw(gifcbuf * gif,int c)2657 static void emitlzw(gifcbuf *gif, int c)
2658 {
2659 int bits = gif->bits, w = gif->w | (c << bits);
2660
2661 bits += gif->lc;
2662 while (bits >= 8)
2663 {
2664 gif->buf[++gif->cnt] = (unsigned char)w;
2665 w >>= 8;
2666 bits -= 8;
2667 if (gif->cnt >= 255)
2668 {
2669 gif->buf[0] = 255;
2670 fwrite(gif->buf, 1, 256, gif->f);
2671 gif->cnt = 0;
2672 }
2673 }
2674 gif->bits = bits;
2675 gif->w = w;
2676 /* Extend code size if needed */
2677 if (gif->nxc >= gif->nxc2) gif->nxc2 = 1 << ++gif->lc;
2678 }
2679
putlzw(gifcbuf * gif,unsigned char * src,int cnt)2680 static void putlzw(gifcbuf *gif, unsigned char *src, int cnt)
2681 {
2682 short *codes = gif->codes;
2683 int i, j, c, prev = gif->prev;
2684
2685 while (cnt-- > 0)
2686 {
2687 c = *src++;
2688 if (prev < 0) /* Begin */
2689 {
2690 prev = c;
2691 continue;
2692 }
2693 /* Try compression */
2694 i = prev * 16 + (c >> 4) + 4096 * 16;
2695 j = codes[i] * 16 + (c & 0xF);
2696 j = codes[j];
2697 if (j) // Have match
2698 {
2699 prev = j - 4096;
2700 continue;
2701 }
2702 /* Emit the code */
2703 emitlzw(gif, prev);
2704 prev = c;
2705 /* Do a clear if needed */
2706 if (gif->nxc >= 4096 - 1)
2707 {
2708 resetclzw(gif);
2709 continue;
2710 }
2711 /* Add new code */
2712 if (!codes[i]) codes[i] = gif->nxmap++;
2713 j = codes[i] * 16 + (c & 0xF);
2714 codes[j] = gif->nxc++ + 4096;
2715 }
2716 gif->prev = prev;
2717 }
2718
donelzw(gifcbuf * gif)2719 static void donelzw(gifcbuf *gif) /* Flush */
2720 {
2721 emitlzw(gif, gif->prev);
2722 emitlzw(gif, gif->clear + 1); // EOD
2723 if (gif->bits) gif->buf[++gif->cnt] = gif->w;
2724 // gif->w = gif->bits = 0;
2725 gif->buf[0] = gif->cnt;
2726 gif->buf[gif->cnt + 1] = 0; // Block terminator
2727 fwrite(gif->buf, 1, gif->cnt + 2, gif->f);
2728 // gif->cnt = 0;
2729 }
2730
save_gif(char * file_name,ls_settings * settings)2731 static int save_gif(char *file_name, ls_settings *settings)
2732 {
2733 gifcbuf gif;
2734 unsigned char *tmp;
2735 FILE *fp = NULL;
2736 int i, nc, ext = FALSE, w = settings->width, h = settings->height;
2737
2738
2739 /* GIF save must be on indexed image */
2740 if (settings->bpp != 1) return WRONG_FORMAT;
2741
2742 gif.codes = malloc(GIF_CODESSIZE);
2743 if (!gif.codes) return (-1);
2744
2745 if (!(fp = fopen(file_name, "wb")))
2746 {
2747 free(gif.codes);
2748 return (-1);
2749 }
2750
2751 /* Get colormap size bits */
2752 nc = nlog2(settings->colors) - 1;
2753 if (nc < 0) nc = 0;
2754
2755 /* Prepare header */
2756 tmp = gif.buf;
2757 memset(tmp, 0, GIF_HDRLEN);
2758 memcpy(tmp, GIF_ID, GIF_IDLEN);
2759 PUT16(tmp + GIF_WIDTH, w);
2760 PUT16(tmp + GIF_HEIGHT, h);
2761 tmp[GIF_GPBITS] = GIF_GPFLAG | GIF_8BPC | nc;
2762 tmp += GIF_HDRLEN;
2763
2764 /* Prepare global palette */
2765 i = 2 << nc;
2766 pal2rgb(tmp, settings->pal, settings->colors, i);
2767 tmp += i * 3;
2768
2769 /* Prepare extension */
2770 if (settings->xpm_trans >= 0)
2771 {
2772 ext = TRUE;
2773 *tmp++ = '!'; // Extension block
2774 *tmp++ = 0xF9; // Graphics control
2775 *tmp++ = GIF_GC_LEN;
2776 memset(tmp, 0, GIF_GC_LEN + 1); // W/block terminator
2777 tmp[GIF_GC_FLAGS] = GIF_GC_TFLAG;
2778 tmp[GIF_GC_TRANS] = settings->xpm_trans;
2779 tmp += GIF_GC_LEN + 1;
2780 }
2781
2782 /* Prepare image header */
2783 *tmp++ = ',';
2784 memset(tmp, 0, GIF_IHDRLEN);
2785 PUT16(tmp + GIF_IWIDTH, w);
2786 PUT16(tmp + GIF_IHEIGHT, h);
2787 tmp += GIF_IHDRLEN;
2788
2789 if (ext) gif.buf[GIF_VER] = '9'; // If we use extension
2790
2791 /* Write out all the headers */
2792 fwrite(gif.buf, 1, tmp - gif.buf, fp);
2793
2794 if (!settings->silent) ls_init("GIF", 1);
2795
2796 initclzw(&gif, nc + 1, fp); // "Min code size" = palette index bits
2797 for (i = 0; i < h; i++)
2798 {
2799 putlzw(&gif, settings->img[CHN_IMAGE] + i * w, w);
2800 ls_progress(settings, i, 20);
2801 }
2802 donelzw(&gif);
2803 fputc(';', fp); // Trailer block
2804 fclose(fp);
2805
2806 if (!settings->silent) progress_end();
2807
2808 free(gif.codes);
2809 return 0;
2810 }
2811
2812 #ifdef NEED_CMYK
2813 #ifdef U_LCMS
2814 /* Guard against cmsHTRANSFORM changing into something overlong in the future */
2815 typedef char cmsHTRANSFORM_Does_Not_Fit_Into_Pointer[2 * (sizeof(cmsHTRANSFORM) <= sizeof(char *)) - 1];
2816
init_cmyk2rgb(ls_settings * settings,unsigned char * icc,int len,int inverted)2817 static int init_cmyk2rgb(ls_settings *settings, unsigned char *icc, int len,
2818 int inverted)
2819 {
2820 cmsHPROFILE from, to;
2821 cmsHTRANSFORM how = NULL;
2822
2823 from = cmsOpenProfileFromMem((void *)icc, len);
2824 if (!from) return (TRUE); // Unopenable now, unopenable ever
2825 to = cmsCreate_sRGBProfile();
2826 if (cmsGetColorSpace(from) == icSigCmykData)
2827 how = cmsCreateTransform(from, inverted ? TYPE_CMYK_8_REV :
2828 TYPE_CMYK_8, to, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
2829 if (from) cmsCloseProfile(from);
2830 cmsCloseProfile(to);
2831 if (!how) return (FALSE); // Better luck the next time
2832
2833 settings->icc = (char *)how;
2834 settings->icc_size = -2;
2835 return (TRUE);
2836 }
2837
done_cmyk2rgb(ls_settings * settings)2838 static void done_cmyk2rgb(ls_settings *settings)
2839 {
2840 if (settings->icc_size != -2) return;
2841 cmsDeleteTransform((cmsHTRANSFORM)settings->icc);
2842 settings->icc = NULL;
2843 settings->icc_size = -1; // Not need profiles anymore
2844 }
2845
2846 #else /* No LCMS */
2847 #define done_cmyk2rgb(X)
2848 #endif
2849 #endif
2850
cmyk2rgb(unsigned char * dest,unsigned char * src,int cnt,int inverted,ls_settings * settings)2851 static void cmyk2rgb(unsigned char *dest, unsigned char *src, int cnt,
2852 int inverted, ls_settings *settings)
2853 {
2854 unsigned char xb;
2855 int j, k, r, g, b;
2856
2857 #ifdef U_LCMS
2858 /* Convert CMYK to RGB using LCMS if possible */
2859 if (settings->icc_size == -2)
2860 {
2861 cmsDoTransform((cmsHTRANSFORM)settings->icc, src, dest, cnt);
2862 return;
2863 }
2864 #endif
2865 /* Simple CMYK->RGB conversion */
2866 xb = inverted ? 0 : 255;
2867 for (j = 0; j < cnt; j++ , src += 4 , dest += 3)
2868 {
2869 k = src[3] ^ xb;
2870 r = (src[0] ^ xb) * k;
2871 dest[0] = (r + (r >> 8) + 1) >> 8;
2872 g = (src[1] ^ xb) * k;
2873 dest[1] = (g + (g >> 8) + 1) >> 8;
2874 b = (src[2] ^ xb) * k;
2875 dest[2] = (b + (b >> 8) + 1) >> 8;
2876 }
2877 }
2878
2879 #ifdef U_JPEG
2880 struct my_error_mgr
2881 {
2882 struct jpeg_error_mgr pub; // "public" fields
2883 jmp_buf setjmp_buffer; // for return to caller
2884 };
2885
2886 typedef struct my_error_mgr *my_error_ptr;
2887
my_error_exit(j_common_ptr cinfo)2888 METHODDEF(void) my_error_exit (j_common_ptr cinfo)
2889 {
2890 my_error_ptr myerr = (my_error_ptr) cinfo->err;
2891 longjmp(myerr->setjmp_buffer, 1);
2892 }
2893 struct my_error_mgr jerr;
2894
load_jpeg(char * file_name,ls_settings * settings)2895 static int load_jpeg(char *file_name, ls_settings *settings)
2896 {
2897 static int pr;
2898 struct jpeg_decompress_struct cinfo;
2899 unsigned char *memp, *memx = NULL;
2900 FILE *fp;
2901 int i, width, height, bpp, res = -1, inv = 0;
2902 #ifdef U_LCMS
2903 unsigned char *icc = NULL;
2904 #endif
2905
2906 if ((fp = fopen(file_name, "rb")) == NULL) return (-1);
2907
2908 pr = 0;
2909 jpeg_create_decompress(&cinfo);
2910 cinfo.err = jpeg_std_error(&jerr.pub);
2911 jerr.pub.error_exit = my_error_exit;
2912 if (setjmp(jerr.setjmp_buffer))
2913 {
2914 res = settings->width ? FILE_LIB_ERROR : -1;
2915 goto fail;
2916 }
2917 jpeg_stdio_src(&cinfo, fp);
2918
2919 #ifdef U_LCMS
2920 /* Request ICC profile aka APP2 data be preserved */
2921 if (!settings->icc_size)
2922 jpeg_save_markers(&cinfo, JPEG_APP0 + 2, 0xFFFF);
2923 #endif
2924
2925 jpeg_read_header(&cinfo, TRUE);
2926 jpeg_start_decompress(&cinfo);
2927
2928 bpp = 3;
2929 switch (cinfo.out_color_space)
2930 {
2931 case JCS_RGB: break;
2932 case JCS_GRAYSCALE:
2933 set_gray(settings);
2934 bpp = 1;
2935 break;
2936 case JCS_CMYK:
2937 /* Photoshop writes CMYK data inverted */
2938 inv = cinfo.saw_Adobe_marker;
2939 if ((memx = malloc(cinfo.output_width * 4))) break;
2940 res = FILE_MEM_ERROR;
2941 // Fallthrough
2942 default: goto fail; /* Unsupported colorspace */
2943 }
2944
2945 settings->width = width = cinfo.output_width;
2946 settings->height = height = cinfo.output_height;
2947 settings->bpp = bpp;
2948 if ((res = allocate_image(settings, CMASK_IMAGE))) goto fail;
2949 res = -1;
2950 pr = !settings->silent;
2951
2952 #ifdef U_LCMS
2953 #define PARTHDR 14
2954 while (!settings->icc_size)
2955 {
2956 jpeg_saved_marker_ptr mk;
2957 unsigned char *tmp, *parts[256];
2958 int i, part, nparts = -1, icclen = 0, lparts[256];
2959
2960 /* List parts */
2961 memset(parts, 0, sizeof(parts));
2962 for (mk = cinfo.marker_list; mk; mk = mk->next)
2963 {
2964 if ((mk->marker != JPEG_APP0 + 2) ||
2965 (mk->data_length < PARTHDR) ||
2966 strcmp(mk->data, "ICC_PROFILE")) continue;
2967 part = GETJOCTET(mk->data[13]);
2968 if (nparts < 0) nparts = part;
2969 if (nparts != part) break;
2970 part = GETJOCTET(mk->data[12]);
2971 if (!part-- || (part >= nparts) || parts[part]) break;
2972 parts[part] = (unsigned char *)(mk->data + PARTHDR);
2973 icclen += lparts[part] = mk->data_length - PARTHDR;
2974 }
2975 if (nparts < 0) break;
2976
2977 icc = tmp = malloc(icclen);
2978 if (!icc) break;
2979
2980 /* Assemble parts */
2981 for (i = 0; i < nparts; i++)
2982 {
2983 if (!parts[i]) break;
2984 memcpy(tmp, parts[i], lparts[i]);
2985 tmp += lparts[i];
2986 }
2987 if (i < nparts) break; // Sequence had a hole
2988
2989 /* If profile is needed right now, for CMYK->RGB */
2990 if (memx && init_cmyk2rgb(settings, icc, icclen, inv))
2991 break; // Transform is ready, so drop the profile
2992
2993 settings->icc = icc;
2994 settings->icc_size = icclen;
2995 icc = NULL; // Leave the profile be
2996 break;
2997 }
2998 free(icc);
2999 #undef PARTHDR
3000 #endif
3001
3002 if (pr) ls_init("JPEG", 0);
3003
3004 for (i = 0; i < height; i++)
3005 {
3006 memp = settings->img[CHN_IMAGE] + width * i * bpp;
3007 jpeg_read_scanlines(&cinfo, memx ? &memx : &memp, 1);
3008 if (memx) cmyk2rgb(memp, memx, width, inv, settings);
3009 ls_progress(settings, i, 20);
3010 }
3011 done_cmyk2rgb(settings);
3012 jpeg_finish_decompress(&cinfo);
3013 res = 1;
3014
3015 fail: if (pr) progress_end();
3016 jpeg_destroy_decompress(&cinfo);
3017 fclose(fp);
3018 free(memx);
3019 return (res);
3020 }
3021
save_jpeg(char * file_name,ls_settings * settings)3022 static int save_jpeg(char *file_name, ls_settings *settings)
3023 {
3024 struct jpeg_compress_struct cinfo;
3025 JSAMPROW row_pointer;
3026 FILE *fp;
3027 int i;
3028
3029
3030 if (settings->bpp == 1) return WRONG_FORMAT;
3031
3032 if ((fp = fopen(file_name, "wb")) == NULL) return -1;
3033
3034 cinfo.err = jpeg_std_error(&jerr.pub);
3035 jerr.pub.error_exit = my_error_exit;
3036 if (setjmp(jerr.setjmp_buffer))
3037 {
3038 jpeg_destroy_compress(&cinfo);
3039 fclose(fp);
3040 return -1;
3041 }
3042
3043 jpeg_create_compress(&cinfo);
3044
3045 jpeg_stdio_dest( &cinfo, fp );
3046 cinfo.image_width = settings->width;
3047 cinfo.image_height = settings->height;
3048 cinfo.input_components = 3;
3049 cinfo.in_color_space = JCS_RGB;
3050 jpeg_set_defaults(&cinfo);
3051 jpeg_set_quality(&cinfo, settings->jpeg_quality, TRUE );
3052 jpeg_start_compress( &cinfo, TRUE );
3053
3054 row_pointer = settings->img[CHN_IMAGE];
3055 if (!settings->silent) ls_init("JPEG", 1);
3056 for (i = 0; i < settings->height; i++ )
3057 {
3058 jpeg_write_scanlines(&cinfo, &row_pointer, 1);
3059 row_pointer += 3 * settings->width;
3060 ls_progress(settings, i, 20);
3061 }
3062 jpeg_finish_compress( &cinfo );
3063
3064 if (!settings->silent) progress_end();
3065
3066 jpeg_destroy_compress( &cinfo );
3067 fclose(fp);
3068
3069 return 0;
3070 }
3071 #endif
3072
3073 #ifdef NEED_FILE2MEM
3074 /* Read in the entire file, up to max size if given */
file2mem(char * file_name,unsigned char ** where,size_t * len,size_t max)3075 static int file2mem(char *file_name, unsigned char **where, size_t *len, size_t max)
3076 {
3077 FILE *fp;
3078 unsigned char *buf;
3079 f_long l;
3080 int res = -1;
3081
3082 if (!(fp = fopen(file_name, "rb"))) return (-1);
3083 fseek(fp, 0, SEEK_END);
3084 l = ftell(fp);
3085 /* Where a f_long is too short to hold the file's size, address space is
3086 * too small to usefully hold the whole file anyway - WJ */
3087 /* And when a hard limit is set, it should be honored */
3088 if ((l > 0) && (!max || (l <= max)))
3089 {
3090 fseek(fp, 0, SEEK_SET);
3091 res = FILE_MEM_ERROR;
3092 if ((buf = malloc(l)))
3093 {
3094 res = -1;
3095 if (fread(buf, 1, l, fp) < l) free(buf);
3096 else *where = buf , *len = l , res = 0;
3097 }
3098 }
3099 fclose(fp);
3100 return (res);
3101 }
3102 #endif
3103
3104 #ifdef U_JP2
3105
3106 /* *** PREFACE ***
3107 * OpenJPEG 1.x is wasteful in the extreme, with memory overhead of about
3108 * 7 times the unpacked image size. So it can fail to handle even such
3109 * resolutions that fit into available memory with lots of room to spare.
3110 * Still, JasPer is an even worse memory hog, if a somewhat faster one.
3111 * Another thing - Linux builds of OpenJPEG cannot properly encode an opacity
3112 * channel (fixed in SVN on 06.11.09, revision 541)
3113 * And JP2 images with 4 channels, produced by OpenJPEG, cause JasPer
3114 * to die horribly.
3115 * Version 2.3.0 (04.10.17) was a sharp improvement, being twice faster than
3116 * JasPer when decompressing and less memory hungry (overhead of 5x size). When
3117 * compressing however, as of 2.3.1 still was about twice slower than JasPer.
3118 * Version 2.4.0 (28.12.20) fixed that, becoming about twice faster than JasPer
3119 * when compressing too.
3120 * Decompression speedup happened only for 64-bit builds, but on 32-bit with
3121 * multiple cores, multithreading still can let it overtake JasPer - WJ */
3122
parse_opj(opj_image_t * image,ls_settings * settings)3123 static int parse_opj(opj_image_t *image, ls_settings *settings)
3124 {
3125 opj_image_comp_t *comp;
3126 unsigned char xtb[256], *dest;
3127 int i, j, k, w, h, w0, nc, step, shift;
3128 unsigned delta;
3129 int *src, cmask = CMASK_IMAGE, res;
3130
3131 if (image->numcomps < 3) /* Guess this is paletted */
3132 {
3133 set_gray(settings);
3134 settings->bpp = 1;
3135 }
3136 else settings->bpp = 3;
3137 if ((nc = settings->bpp) < image->numcomps) nc++ , cmask = CMASK_RGBA;
3138 comp = image->comps;
3139 settings->width = w = (comp->w + (1 << comp->factor) - 1) >> comp->factor;
3140 settings->height = h = (comp->h + (1 << comp->factor) - 1) >> comp->factor;
3141 for (i = 1; i < nc; i++) /* Check if all components are the same size */
3142 {
3143 comp++;
3144 if ((w != (comp->w + (1 << comp->factor) - 1) >> comp->factor) ||
3145 (h != (comp->h + (1 << comp->factor) - 1) >> comp->factor))
3146 return (-1);
3147 }
3148 if ((res = allocate_image(settings, cmask))) return (res);
3149
3150 /* Unpack data */
3151 for (i = 0 , comp = image->comps; i < nc; i++ , comp++)
3152 {
3153 if (i < settings->bpp) /* Image */
3154 {
3155 dest = settings->img[CHN_IMAGE] + i;
3156 step = settings->bpp;
3157 }
3158 else /* Alpha */
3159 {
3160 dest = settings->img[CHN_ALPHA];
3161 if (!dest) break; /* No alpha allocated */
3162 step = 1;
3163 }
3164 w0 = comp->w;
3165 delta = comp->sgnd ? 1U << (comp->prec - 1) : 0;
3166 shift = comp->prec > 8 ? comp->prec - 8 : 0;
3167 set_xlate(xtb, comp->prec - shift);
3168 for (j = 0; j < h; j++)
3169 {
3170 src = comp->data + j * w0;
3171 for (k = 0; k < w; k++)
3172 {
3173 *dest = xtb[(src[k] + delta) >> shift];
3174 dest += step;
3175 }
3176 }
3177 }
3178
3179 #ifdef U_LCMS
3180 #if U_JP2 >= 2 /* 2.x */
3181 /* Extract ICC profile if it's of use */
3182 if (!settings->icc_size && image->icc_profile_buf &&
3183 (image->icc_profile_len < INT_MAX) &&
3184 (settings->icc = malloc(image->icc_profile_len)))
3185 memcpy(settings->icc, image->icc_profile_buf,
3186 settings->icc_size = image->icc_profile_len);
3187 #endif
3188 #endif
3189 return (1);
3190 }
3191
prepare_opj(ls_settings * settings)3192 static opj_image_t *prepare_opj(ls_settings *settings)
3193 {
3194 opj_image_cmptparm_t channels[4];
3195 opj_image_t *image;
3196 unsigned char *src;
3197 int i, j, k, nc, step;
3198 int *dest, w = settings->width, h = settings->height;
3199
3200 nc = settings->img[CHN_ALPHA] ? 4 : 3;
3201 memset(channels, 0, sizeof(channels));
3202 for (i = 0; i < nc; i++)
3203 {
3204 channels[i].prec = channels[i].bpp = 8;
3205 channels[i].dx = channels[i].dy = 1;
3206 channels[i].w = w;
3207 channels[i].h = h;
3208 }
3209
3210 image = opj_image_create(nc, channels,
3211 #if U_JP2 < 2 /* 1.x */
3212 CLRSPC_SRGB);
3213 #else /* 2.x */
3214 OPJ_CLRSPC_SRGB);
3215 #endif
3216 if (!image) return (NULL);
3217 image->x0 = image->y0 = 0;
3218 image->x1 = w; image->y1 = h;
3219
3220 /* Fill it */
3221 k = w * h;
3222 for (i = 0; i < nc; i++)
3223 {
3224 if (i < 3)
3225 {
3226 src = settings->img[CHN_IMAGE] + i;
3227 step = 3;
3228 }
3229 else
3230 {
3231 src = settings->img[CHN_ALPHA];
3232 step = 1;
3233 }
3234 dest = image->comps[i].data;
3235 for (j = 0; j < k; j++ , src += step) dest[j] = *src;
3236 }
3237
3238 return (image);
3239 }
3240
3241 #if U_JP2 < 2 /* 1.x */
3242
stupid_callback(const char * msg,void * client_data)3243 static void stupid_callback(const char *msg, void *client_data)
3244 {
3245 }
3246
load_jpeg2000(char * file_name,ls_settings * settings)3247 static int load_jpeg2000(char *file_name, ls_settings *settings)
3248 {
3249 opj_dparameters_t par;
3250 opj_dinfo_t *dinfo;
3251 opj_cio_t *cio = NULL;
3252 opj_image_t *image = NULL;
3253 opj_event_mgr_t useless_events; // !!! Silently made mandatory in v1.2
3254 unsigned char *buf = NULL;
3255 size_t l;
3256 int pr, res;
3257
3258
3259 /* Read in the entire file, provided its size fits into int */
3260 if ((res = file2mem(file_name, &buf, &l, INT_MAX))) return (res);
3261
3262 /* Decompress it */
3263 dinfo = opj_create_decompress(settings->ftype == FT_J2K ? CODEC_J2K :
3264 CODEC_JP2);
3265 if (!dinfo) goto lfail;
3266 memset(&useless_events, 0, sizeof(useless_events));
3267 useless_events.error_handler = useless_events.warning_handler =
3268 useless_events.info_handler = stupid_callback;
3269 opj_set_event_mgr((opj_common_ptr)dinfo, &useless_events, stderr);
3270 opj_set_default_decoder_parameters(&par);
3271 opj_setup_decoder(dinfo, &par);
3272 cio = opj_cio_open((opj_common_ptr)dinfo, buf, l);
3273 if (!cio) goto lfail;
3274 if ((pr = !settings->silent)) ls_init("JPEG2000", 0);
3275 image = opj_decode(dinfo, cio);
3276 opj_cio_close(cio);
3277 opj_destroy_decompress(dinfo);
3278 free(buf);
3279 if (!image) goto ifail;
3280
3281 /* Analyze what we got */
3282 // !!! OpenJPEG 1.1.1 does *NOT* properly set image->color_space !!!
3283 res = parse_opj(image, settings);
3284
3285 ifail: if (pr) progress_end();
3286 opj_image_destroy(image);
3287 return (res);
3288 lfail: opj_destroy_decompress(dinfo);
3289 free(buf);
3290 return (res);
3291 }
3292
save_jpeg2000(char * file_name,ls_settings * settings)3293 static int save_jpeg2000(char *file_name, ls_settings *settings)
3294 {
3295 opj_cparameters_t par;
3296 opj_cinfo_t *cinfo;
3297 opj_cio_t *cio = NULL;
3298 opj_image_t *image;
3299 opj_event_mgr_t useless_events; // !!! Silently made mandatory in v1.2
3300 FILE *fp;
3301 int k, res = -1;
3302
3303
3304 if (settings->bpp == 1) return WRONG_FORMAT;
3305
3306 if ((fp = fopen(file_name, "wb")) == NULL) return -1;
3307
3308 /* Create intermediate structure */
3309 image = prepare_opj(settings);
3310 if (!image) goto ffail;
3311
3312 /* Compress it */
3313 if (!settings->silent) ls_init("JPEG2000", 1);
3314 cinfo = opj_create_compress(settings->ftype == FT_JP2 ? CODEC_JP2 :
3315 CODEC_J2K);
3316 if (!cinfo) goto fail;
3317 memset(&useless_events, 0, sizeof(useless_events));
3318 useless_events.error_handler = useless_events.warning_handler =
3319 useless_events.info_handler = stupid_callback;
3320 opj_set_event_mgr((opj_common_ptr)cinfo, &useless_events, stderr);
3321 opj_set_default_encoder_parameters(&par);
3322 par.tcp_numlayers = 1;
3323 par.tcp_rates[0] = settings->jp2_rate;
3324 par.cp_disto_alloc = 1;
3325 opj_setup_encoder(cinfo, &par, image);
3326 cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
3327 if (!cio) goto fail;
3328 if (!opj_encode(cinfo, cio, image, NULL)) goto fail;
3329
3330 /* Write it */
3331 k = cio_tell(cio);
3332 if (fwrite(cio->buffer, 1, k, fp) == k) res = 0;
3333
3334 fail: if (cio) opj_cio_close(cio);
3335 opj_destroy_compress(cinfo);
3336 opj_image_destroy(image);
3337 if (!settings->silent) progress_end();
3338 ffail: fclose(fp);
3339 return (res);
3340 }
3341
3342 #else /* 2.x */
3343
load_jpeg2000(char * file_name,ls_settings * settings)3344 static int load_jpeg2000(char *file_name, ls_settings *settings)
3345 {
3346 opj_dparameters_t par;
3347 opj_codec_t *dinfo;
3348 opj_stream_t *inp = NULL;
3349 opj_image_t *image = NULL;
3350 int i, pr, res = -1;
3351 #if !OPJ_VERSION_MINOR /* 2.0.x */
3352 FILE *fp;
3353 #endif
3354
3355
3356 #if !OPJ_VERSION_MINOR /* 2.0.x */
3357 if ((fp = fopen(file_name, "rb")) == NULL) return (-1);
3358 if (!(inp = opj_stream_create_default_file_stream(fp, TRUE))) goto ffail;
3359 #else /* 2.1+ */
3360 if (!(inp = opj_stream_create_default_file_stream(file_name, TRUE)))
3361 return (-1);
3362 #endif
3363
3364 /* Decompress it */
3365 dinfo = opj_create_decompress(settings->ftype == FT_J2K ? OPJ_CODEC_J2K :
3366 OPJ_CODEC_JP2);
3367 if (!dinfo) goto ffail;
3368 opj_set_default_decoder_parameters(&par);
3369 if (!opj_setup_decoder(dinfo, &par)) goto dfail;
3370 #if defined(U_THREADS) && (OPJ_VERSION_MINOR >= 2) /* 2.2+ */
3371 /* Not much effect on 64 bit as of 2.3.0 - only 10% faster from a 2nd core
3372 * But since 2.3.1, 1.3x faster with 2 cores, 1.7x with 4+ */
3373 opj_codec_set_threads(dinfo, helper_threads());
3374 #endif
3375 if ((pr = !settings->silent)) ls_init("JPEG2000", 0);
3376 i = opj_read_header(inp, dinfo, &image) &&
3377 opj_decode(dinfo, inp, image) &&
3378 opj_end_decompress(dinfo, inp);
3379 opj_destroy_codec(dinfo);
3380 opj_stream_destroy(inp);
3381 if (!i) goto ifail;
3382
3383 /* Parse what we got */
3384 if (image->color_space >= OPJ_CLRSPC_SYCC)
3385 goto ifail; // sYCC and CMYK - unsupported till seen in the wild
3386 res = parse_opj(image, settings);
3387
3388 ifail: if (pr) progress_end();
3389 opj_image_destroy(image);
3390 return (res);
3391 dfail: opj_destroy_codec(dinfo);
3392 ffail: opj_stream_destroy(inp);
3393 #if !OPJ_VERSION_MINOR /* 2.0.x */
3394 fclose(fp);
3395 #endif
3396 return (res);
3397 }
3398
save_jpeg2000(char * file_name,ls_settings * settings)3399 static int save_jpeg2000(char *file_name, ls_settings *settings)
3400 {
3401 opj_cparameters_t par;
3402 opj_codec_t *cinfo;
3403 opj_stream_t *outp = NULL;
3404 opj_image_t *image;
3405 int res = -1;
3406 #if !OPJ_VERSION_MINOR /* 2.0.x */
3407 FILE *fp;
3408 #endif
3409
3410 if (settings->bpp == 1) return WRONG_FORMAT;
3411
3412 #if !OPJ_VERSION_MINOR /* 2.0.x */
3413 if ((fp = fopen(file_name, "wb")) == NULL) return (-1);
3414 if (!(outp = opj_stream_create_default_file_stream(fp, FALSE))) goto ffail;
3415 #else /* 2.1+ */
3416 if (!(outp = opj_stream_create_default_file_stream(file_name, FALSE)))
3417 return (-1);
3418 #endif
3419
3420 /* Create intermediate structure */
3421 image = prepare_opj(settings);
3422 if (!image) goto ffail;
3423
3424 /* Compress it */
3425 if (!settings->silent) ls_init("JPEG2000", 1);
3426 cinfo = opj_create_compress(settings->ftype == FT_JP2 ? OPJ_CODEC_JP2 :
3427 OPJ_CODEC_J2K);
3428 if (!cinfo) goto fail;
3429 opj_set_default_encoder_parameters(&par);
3430 par.tcp_numlayers = 1;
3431 par.tcp_rates[0] = settings->jp2_rate;
3432 par.cp_disto_alloc = 1;
3433 opj_setup_encoder(cinfo, &par, image);
3434 #if defined(U_THREADS) && (OPJ_VERSION_MINOR >= 4) /* 2.4+ */
3435 /* As of 2.4.0, 1.4x faster with 2 cores, 1.7x with 4+ */
3436 opj_codec_set_threads(cinfo, helper_threads());
3437 #endif
3438 if (opj_start_compress(cinfo, image, outp) &&
3439 opj_encode(cinfo, outp) &&
3440 opj_end_compress(cinfo, outp)) res = 0;
3441 fail: opj_destroy_codec(cinfo);
3442 opj_image_destroy(image);
3443 if (!settings->silent) progress_end();
3444 ffail: opj_stream_destroy(outp);
3445 #if !OPJ_VERSION_MINOR /* 2.0.x */
3446 fclose(fp);
3447 #endif
3448 return (res);
3449 }
3450 #endif
3451 #endif
3452
3453 #ifdef U_JASPER
3454
3455 /* *** PREFACE ***
3456 * JasPer is QUITE a memory waster, with peak memory usage nearly TEN times the
3457 * unpacked image size. But what is worse, its API is 99% undocumented.
3458 * And to add insult to injury, it reacts to some invalid JP2 files (4-channel
3459 * ones written by OpenJPEG) by abort()ing, instead of returning error - WJ */
3460
3461 static int jasper_init;
3462
load_jpeg2000(char * file_name,ls_settings * settings)3463 static int load_jpeg2000(char *file_name, ls_settings *settings)
3464 {
3465 jas_image_t *img;
3466 jas_stream_t *inp;
3467 jas_matrix_t *mx;
3468 jas_seqent_t *src;
3469 char *fmt;
3470 unsigned char xtb[256], *dest;
3471 int nc, cspace, mode, slots[4];
3472 int bits, shift, chan, step;
3473 unsigned delta;
3474 int i, j, k, n, nx, w, h, bpp, pr = 0, res = -1;
3475
3476
3477 /* Init the dumb library */
3478 if (!jasper_init) jas_init();
3479 jasper_init = TRUE;
3480 /* Open the file */
3481 inp = jas_stream_fopen(file_name, "rb");
3482 if (!inp) return (-1);
3483 /* Validate format */
3484 fmt = jas_image_fmttostr(jas_image_getfmt(inp));
3485 if (!fmt || strcmp(fmt, settings->ftype == FT_JP2 ? "jp2" : "jpc"))
3486 goto ffail;
3487
3488 /* Decode the file into a halfbaked pile of bytes */
3489 if ((pr = !settings->silent)) ls_init("JPEG2000", 0);
3490 img = jas_image_decode(inp, -1, NULL);
3491 jas_stream_close(inp);
3492 if (!img) goto dfail;
3493 /* Analyze the pile's contents */
3494 nc = jas_image_numcmpts(img);
3495 mode = jas_clrspc_fam(cspace = jas_image_clrspc(img));
3496 if (mode == JAS_CLRSPC_FAM_GRAY) bpp = 1;
3497 else if (mode == JAS_CLRSPC_FAM_RGB) bpp = 3;
3498 else goto ifail;
3499 if (bpp == 3)
3500 {
3501 slots[0] = jas_image_getcmptbytype(img,
3502 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
3503 slots[1] = jas_image_getcmptbytype(img,
3504 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
3505 slots[2] = jas_image_getcmptbytype(img,
3506 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
3507 if ((slots[1] < 0) | (slots[2] < 0)) goto ifail;
3508 }
3509 else
3510 {
3511 slots[0] = jas_image_getcmptbytype(img,
3512 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
3513 set_gray(settings);
3514 }
3515 if (slots[0] < 0) goto ifail;
3516 if (nc > bpp)
3517 {
3518 slots[bpp] = jas_image_getcmptbytype(img, JAS_IMAGE_CT_OPACITY);
3519 /* !!! JasPer has a bug - it doesn't write out component definitions if color
3520 * channels are in natural order, thus losing the types of any extra components.
3521 * (See where variable "needcdef" in src/libjasper/jp2/jp2_enc.c gets unset.)
3522 * Then on reading, type will be replaced by component's ordinal number - WJ */
3523 if (slots[bpp] < 0) slots[bpp] = jas_image_getcmptbytype(img, bpp);
3524 /* Use an unlabeled extra component for alpha if no labeled one */
3525 if (slots[bpp] < 0)
3526 slots[bpp] = jas_image_getcmptbytype(img, JAS_IMAGE_CT_UNKNOWN);
3527 nc = bpp + (slots[bpp] >= 0); // Ignore extra channels if no alpha
3528 }
3529 w = jas_image_cmptwidth(img, slots[0]);
3530 h = jas_image_cmptheight(img, slots[0]);
3531 for (i = 1; i < nc; i++) /* Check if all components are the same size */
3532 {
3533 if ((jas_image_cmptwidth(img, slots[i]) != w) ||
3534 (jas_image_cmptheight(img, slots[i]) != h)) goto ifail;
3535 }
3536
3537 /* Allocate "matrix" */
3538 res = FILE_MEM_ERROR;
3539 mx = jas_matrix_create(1, w);
3540 if (!mx) goto ifail;
3541 /* Allocate image */
3542 settings->width = w;
3543 settings->height = h;
3544 settings->bpp = bpp;
3545 if ((res = allocate_image(settings, nc > bpp ? CMASK_RGBA : CMASK_IMAGE)))
3546 goto mfail;
3547 if (!settings->img[CHN_ALPHA]) nc = bpp;
3548 res = 1;
3549 #if U_LCMS
3550 /* JasPer implements CMS internally, but without lcms, it makes no sense
3551 * to provide all the interface stuff for this one rare format - WJ */
3552 while (!settings->icc_size && (bpp == 3) && (cspace != JAS_CLRSPC_SRGB))
3553 {
3554 jas_cmprof_t *prof;
3555 jas_image_t *timg;
3556
3557 res = FILE_LIB_ERROR;
3558 prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);
3559 if (!prof) break;
3560 timg = jas_image_chclrspc(img, prof, JAS_CMXFORM_INTENT_PER);
3561 jas_cmprof_destroy(prof);
3562 if (!timg) break;
3563 jas_image_destroy(img);
3564 img = timg;
3565 res = 1; // Success - further code is fail-proof
3566 break;
3567 }
3568 #endif
3569
3570 /* Unravel the ugly thing into proper format */
3571 nx = h * nc;
3572 for (i = n = 0; i < nc; i++)
3573 {
3574 if (i < bpp) /* Image */
3575 {
3576 dest = settings->img[CHN_IMAGE] + i;
3577 step = settings->bpp;
3578 }
3579 else /* Alpha */
3580 {
3581 dest = settings->img[CHN_ALPHA];
3582 step = 1;
3583 }
3584 chan = slots[i];
3585 bits = jas_image_cmptprec(img, chan);
3586 delta = jas_image_cmptsgnd(img, chan) ? 1U << (bits - 1) : 0;
3587 shift = bits > 8 ? bits - 8 : 0;
3588 set_xlate(xtb, bits - shift);
3589 for (j = 0; j < h; j++ , n++)
3590 {
3591 jas_image_readcmpt(img, chan, 0, j, w, 1, mx);
3592 src = jas_matrix_getref(mx, 0, 0);
3593 for (k = 0; k < w; k++)
3594 {
3595 *dest = xtb[(src[k] + delta) >> shift];
3596 dest += step;
3597 }
3598 if (pr && ((n * 10) % nx >= nx - 10))
3599 progress_update((float)n / nx);
3600 }
3601 }
3602
3603 mfail: jas_matrix_destroy(mx);
3604 ifail: jas_image_destroy(img);
3605 dfail: if (pr) progress_end();
3606 return (res);
3607 ffail: jas_stream_close(inp);
3608 return (-1);
3609 }
3610
save_jpeg2000(char * file_name,ls_settings * settings)3611 static int save_jpeg2000(char *file_name, ls_settings *settings)
3612 {
3613 static const jas_image_cmpttype_t chans[4] = {
3614 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R),
3615 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G),
3616 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B),
3617 JAS_IMAGE_CT_OPACITY };
3618 jas_image_cmptparm_t cp[4];
3619 jas_image_t *img;
3620 jas_stream_t *outp;
3621 jas_matrix_t *mx;
3622 jas_seqent_t *dest;
3623 char buf[256], *opts = NULL;
3624 unsigned char *src;
3625 int w = settings->width, h = settings->height, res = -1;
3626 int i, j, k, n, nx, nc, step, pr;
3627
3628
3629 if (settings->bpp == 1) return WRONG_FORMAT;
3630
3631 /* Init the dumb library */
3632 if (!jasper_init) jas_init();
3633 jasper_init = TRUE;
3634 /* Open the file */
3635 outp = jas_stream_fopen(file_name, "wb");
3636 if (!outp) return (-1);
3637 /* Setup component parameters */
3638 memset(cp, 0, sizeof(cp)); // Zero out all that needs zeroing
3639 cp[0].hstep = cp[0].vstep = 1;
3640 cp[0].width = w; cp[0].height = h;
3641 cp[0].prec = 8;
3642 cp[3] = cp[2] = cp[1] = cp[0];
3643 /* Create image structure */
3644 nc = 3 + !!settings->img[CHN_ALPHA];
3645 img = jas_image_create(nc, cp, JAS_CLRSPC_SRGB);
3646 if (!img) goto fail;
3647 /* Allocate "matrix" */
3648 mx = jas_matrix_create(1, w);
3649 if (!mx) goto fail2;
3650
3651 if ((pr = !settings->silent)) ls_init("JPEG2000", 1);
3652
3653 /* Fill image structure */
3654 nx = h * nc;
3655 nx += nx / 10 + 1; // Show "90% done" while compressing
3656 for (i = n = 0; i < nc; i++)
3657 {
3658 /* !!! The only workaround for JasPer losing extra components' types on
3659 * write is to reorder the RGB components - but then, dumb readers, such
3660 * as ones in Mozilla and GTK+, would read them in wrong order - WJ */
3661 jas_image_setcmpttype(img, i, chans[i]);
3662 if (i < 3) /* Image */
3663 {
3664 src = settings->img[CHN_IMAGE] + i;
3665 step = settings->bpp;
3666 }
3667 else /* Alpha */
3668 {
3669 src = settings->img[CHN_ALPHA];
3670 step = 1;
3671 }
3672 for (j = 0; j < h; j++ , n++)
3673 {
3674 dest = jas_matrix_getref(mx, 0, 0);
3675 for (k = 0; k < w; k++)
3676 {
3677 dest[k] = *src;
3678 src += step;
3679 }
3680 jas_image_writecmpt(img, i, 0, j, w, 1, mx);
3681 if (pr && ((n * 10) % nx >= nx - 10))
3682 if (progress_update((float)n / nx)) goto fail3;
3683 }
3684 }
3685
3686 /* Compress it */
3687 if (pr) progress_update(0.9);
3688 if (settings->jp2_rate) // Lossless if NO "rate" option passed
3689 sprintf(opts = buf, "rate=%g", 1.0 / settings->jp2_rate);
3690 if (!jas_image_encode(img, outp, jas_image_strtofmt(
3691 settings->ftype == FT_JP2 ? "jp2" : "jpc"), opts)) res = 0;
3692 jas_stream_flush(outp);
3693 if (pr) progress_update(1.0);
3694
3695 fail3: if (pr) progress_end();
3696 jas_matrix_destroy(mx);
3697 fail2: jas_image_destroy(img);
3698 fail: jas_stream_close(outp);
3699 return (res);
3700 }
3701 #endif
3702
3703 /* Slow-but-sure universal bitstream parsers; may read extra byte at the end */
stream_MSB(unsigned char * src,unsigned char * dest,int cnt,int bits,int bit0,int bitstep,int step)3704 static void stream_MSB(unsigned char *src, unsigned char *dest, int cnt,
3705 int bits, int bit0, int bitstep, int step)
3706 {
3707 int i, j, v, mask = (1 << bits) - 1;
3708
3709 for (i = 0; i < cnt; i++)
3710 {
3711 j = bit0 >> 3;
3712 v = (src[j] << 8) | src[j + 1];
3713 v >>= 16 - bits - (bit0 & 7);
3714 *dest = (unsigned char)(v & mask);
3715 bit0 += bitstep;
3716 dest += step;
3717 }
3718 }
3719
stream_LSB(unsigned char * src,unsigned char * dest,int cnt,int bits,int bit0,int bitstep,int step)3720 static void stream_LSB(unsigned char *src, unsigned char *dest, int cnt,
3721 int bits, int bit0, int bitstep, int step)
3722 {
3723 int i, j, v, mask = (1 << bits) - 1;
3724
3725 for (i = 0; i < cnt; i++)
3726 {
3727 j = bit0 >> 3;
3728 v = (src[j + 1] << 8) | src[j];
3729 v >>= bit0 & 7;
3730 *dest = (unsigned char)(v & mask);
3731 bit0 += bitstep;
3732 dest += step;
3733 }
3734 }
3735
pack_MSB(unsigned char * dest,unsigned char * src,int len,int bw)3736 static void pack_MSB(unsigned char *dest, unsigned char *src, int len, int bw)
3737 {
3738 int i;
3739
3740 memset(dest, 0, (len + 7) >> 3);
3741 for (i = 0; i < len; i++)
3742 dest[i >> 3] |= (*src++ == bw) << (~i & 7);
3743 }
3744
3745 static void copy_bytes(unsigned char *dest, unsigned char *src, int len,
3746 int bpp, int step);
3747
3748 #ifdef U_TIFF
3749
3750 /* *** PREFACE ***
3751 * TIFF is a bitch, and libtiff is a joke. An unstable and buggy joke, at that.
3752 * It's a fact of life - and when some TIFFs don't load or are mangled, that
3753 * also is a fact of life. Installing latest libtiff may help - or not; sending
3754 * a bugreport with the offending file attached may help too - but again, it's
3755 * not guaranteed. But the common varieties of TIFF format should load OK. */
3756
3757 tiff_format tiff_formats[TIFF_MAX_TYPES] = {
3758 { _("None"), COMPRESSION_NONE, TIFFLAGS, XF_COMPT },
3759 { "Group 3", COMPRESSION_CCITTFAX3, FF_BW | TIFF0FLAGS, XF_COMPT },
3760 { "Group 4", COMPRESSION_CCITTFAX4, FF_BW | TIFF0FLAGS, XF_COMPT },
3761 { "PackBits", COMPRESSION_PACKBITS, TIFFLAGS, XF_COMPT },
3762 { "LZW", COMPRESSION_LZW, TIFFLAGS, XF_COMPT, 1 },
3763 { "ZIP", COMPRESSION_ADOBE_DEFLATE, TIFFLAGS, XF_COMPT | XF_COMPZT, 1 },
3764 #ifdef COMPRESSION_LZMA
3765 { "LZMA2", COMPRESSION_LZMA, TIFFLAGS, XF_COMPT | XF_COMPLZ, 1 },
3766 #endif
3767 #ifdef COMPRESSION_ZSTD
3768 { "ZSTD", COMPRESSION_ZSTD, TIFFLAGS, XF_COMPT | XF_COMPZS, 1 },
3769 #endif
3770 { "JPEG", COMPRESSION_JPEG, FF_RGB | TIFF0FLAGS, XF_COMPT | XF_COMPJ },
3771 #ifdef COMPRESSION_WEBP
3772 { "WebP", COMPRESSION_WEBP, FF_RGB | FF_ALPHAR | TIFF0FLAGS, XF_COMPT | XF_COMPWT },
3773 #endif
3774 { NULL }
3775 };
3776
3777 int tiff_lzma, tiff_zstd; /* FALSE by default */
3778
init_tiff_formats()3779 void init_tiff_formats() // Check what libtiff can handle
3780 {
3781 tiff_format *src, *dest;
3782
3783 /* Try all compiled-in formats */
3784 src = dest = tiff_formats + 1; // COMPRESSION_NONE is always there
3785 while (src->name)
3786 {
3787 if (TIFFIsCODECConfigured(src->id)) *dest++ = *src;
3788 src++;
3789 }
3790 /* Zero out extra slots */
3791 while (dest != src) *dest++ = *src;
3792 /* Set flag variables */
3793 #ifdef COMPRESSION_LZMA
3794 tiff_lzma = TIFFIsCODECConfigured(COMPRESSION_LZMA);
3795 #endif
3796 #ifdef COMPRESSION_ZSTD
3797 tiff_zstd = TIFFIsCODECConfigured(COMPRESSION_ZSTD);
3798 #endif
3799 }
3800
load_tiff_frame(TIFF * tif,ls_settings * settings)3801 static int load_tiff_frame(TIFF *tif, ls_settings *settings)
3802 {
3803 char cbuf[1024];
3804 uint16 bpsamp, sampp, xsamp, pmetric, planar, orient, sform;
3805 uint16 *sampinfo, *red16, *green16, *blue16;
3806 uint32 width, height, tw = 0, th = 0, rps = 0;
3807 uint32 *tr, *raster = NULL;
3808 unsigned char *tmp, *buf = NULL;
3809 int bpp = 3, cmask = CMASK_IMAGE, argb = FALSE, pr = FALSE;
3810 int i, j, mirror, res;
3811
3812
3813 /* Let's learn what we've got */
3814 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &sampp);
3815 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &xsamp, &sampinfo);
3816 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmetric))
3817 {
3818 /* Defaults like in libtiff */
3819 if (sampp - xsamp == 1) pmetric = PHOTOMETRIC_MINISBLACK;
3820 else if (sampp - xsamp == 3) pmetric = PHOTOMETRIC_RGB;
3821 else return (-1);
3822 }
3823 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sform);
3824 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
3825 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
3826 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bpsamp);
3827 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar);
3828 planar = planar != PLANARCONFIG_CONTIG;
3829 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &orient);
3830 switch (orient)
3831 {
3832 case ORIENTATION_TOPLEFT:
3833 case ORIENTATION_LEFTTOP: mirror = 0; break;
3834 case ORIENTATION_TOPRIGHT:
3835 case ORIENTATION_RIGHTTOP: mirror = 1; break;
3836 default:
3837 case ORIENTATION_BOTLEFT:
3838 case ORIENTATION_LEFTBOT: mirror = 2; break;
3839 case ORIENTATION_BOTRIGHT:
3840 case ORIENTATION_RIGHTBOT: mirror = 3; break;
3841 }
3842 if (TIFFIsTiled(tif))
3843 {
3844 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
3845 TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
3846 }
3847 else
3848 {
3849 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rps);
3850 }
3851
3852 /* Extract position from it */
3853 settings->x = settings->y = 0;
3854 while (TRUE)
3855 {
3856 float xres, yres, dxu = 0, dyu = 0;
3857
3858 if (!TIFFGetField(tif, TIFFTAG_XPOSITION, &dxu) &&
3859 !TIFFGetField(tif, TIFFTAG_YPOSITION, &dyu)) break;
3860 // Have position, now need resolution
3861 if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)) break;
3862 // X resolution we have, what about Y?
3863 yres = xres; // Default
3864 TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
3865 // Convert ResolutionUnits (whatever they are) to pixels
3866 settings->x = rint(dxu * xres);
3867 settings->y = rint(dyu * yres);
3868 break;
3869 }
3870
3871 /* Let's decide how to store it */
3872 if ((width > MAX_WIDTH) || (height > MAX_HEIGHT)) return (TOO_BIG);
3873 settings->width = width;
3874 settings->height = height;
3875 if ((sform != SAMPLEFORMAT_UINT) && (sform != SAMPLEFORMAT_INT) &&
3876 (sform != SAMPLEFORMAT_VOID)) argb = TRUE;
3877 else switch (pmetric)
3878 {
3879 case PHOTOMETRIC_PALETTE:
3880 {
3881 png_color *cp = settings->pal;
3882 int i, j, k, na = 0, nd = 1; /* Old palette format */
3883
3884 if (bpsamp > 8)
3885 {
3886 argb = TRUE;
3887 break;
3888 }
3889 if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
3890 &red16, &green16, &blue16)) return (-1);
3891
3892 settings->colors = j = 1 << bpsamp;
3893 /* Analyze palette */
3894 for (k = i = 0; i < j; i++)
3895 {
3896 k |= red16[i] | green16[i] | blue16[i];
3897 }
3898 if (k > 255) na = 128 , nd = 257; /* New palette format */
3899
3900 for (i = 0; i < j; i++ , cp++)
3901 {
3902 cp->red = (red16[i] + na) / nd;
3903 cp->green = (green16[i] + na) / nd;
3904 cp->blue = (blue16[i] + na) / nd;
3905 }
3906 /* If palette is all we need */
3907 if ((settings->mode == FS_PALETTE_LOAD) ||
3908 (settings->mode == FS_PALETTE_DEF))
3909 return (EXPLODE_FAILED);
3910 /* Fallthrough */
3911 }
3912 case PHOTOMETRIC_MINISWHITE:
3913 case PHOTOMETRIC_MINISBLACK:
3914 bpp = 1; break;
3915 case PHOTOMETRIC_RGB:
3916 break;
3917 case PHOTOMETRIC_SEPARATED:
3918 /* Leave non-CMYK separations to libtiff */
3919 if (sampp - xsamp == 4) break;
3920 default:
3921 argb = TRUE;
3922 }
3923
3924 /* libtiff can't handle this and neither can we */
3925 if (argb && !TIFFRGBAImageOK(tif, cbuf)) return (-1);
3926
3927 settings->bpp = bpp;
3928 /* Photoshop writes alpha as EXTRASAMPLE_UNSPECIFIED anyway */
3929 if (xsamp) cmask = CMASK_RGBA;
3930
3931 /* !!! No alpha support for RGB mode yet */
3932 if (argb) cmask = CMASK_IMAGE;
3933
3934 if ((res = allocate_image(settings, cmask))) return (res);
3935 res = -1;
3936
3937 #ifdef U_LCMS
3938 #ifdef TIFFTAG_ICCPROFILE
3939 /* Extract ICC profile if it's of use */
3940 if (!settings->icc_size)
3941 {
3942 uint32 size;
3943 unsigned char *data;
3944
3945 /* TIFFTAG_ICCPROFILE was broken beyond hope in libtiff 3.8.0
3946 * (see libtiff 3.8.1+ changelog entry for 2006-01-04) */
3947 if (!strstr(TIFFGetVersion(), " 3.8.0") &&
3948 TIFFGetField(tif, TIFFTAG_ICCPROFILE, &size, &data) &&
3949 (size < INT_MAX) &&
3950 /* If profile is needed right now, for CMYK->RGB */
3951 !((pmetric == PHOTOMETRIC_SEPARATED) && !argb &&
3952 init_cmyk2rgb(settings, data, size, FALSE)) &&
3953 (settings->icc = malloc(size)))
3954 {
3955 settings->icc_size = size;
3956 memcpy(settings->icc, data, size);
3957 }
3958 }
3959 #endif
3960 #endif
3961
3962 if ((pr = !settings->silent)) ls_init("TIFF", 0);
3963
3964 /* Read it as ARGB if can't understand it ourselves */
3965 if (argb)
3966 {
3967 /* libtiff is too much of a moving target if finer control is
3968 * needed, so let's trade memory for stability */
3969 raster = (uint32 *)_TIFFmalloc(width * height * sizeof(uint32));
3970 res = FILE_MEM_ERROR;
3971 if (!raster) goto fail2;
3972 res = FILE_LIB_ERROR;
3973 if (!TIFFReadRGBAImage(tif, width, height, raster, 0)) goto fail2;
3974 res = -1;
3975
3976 /* Parse the RGB part only - alpha might be eaten by bugs */
3977 tr = raster;
3978 for (i = height - 1; i >= 0; i--)
3979 {
3980 tmp = settings->img[CHN_IMAGE] + width * i * bpp;
3981 j = width;
3982 while (j--)
3983 {
3984 tmp[0] = TIFFGetR(*tr);
3985 tmp[1] = TIFFGetG(*tr);
3986 tmp[2] = TIFFGetB(*tr);
3987 tmp += 3; tr++;
3988 }
3989 ls_progress(settings, height - i, 10);
3990 }
3991
3992 _TIFFfree(raster);
3993 raster = NULL;
3994
3995 /* !!! Now it would be good to read in alpha ourselves - but not yet... */
3996
3997 res = 1;
3998 }
3999
4000 /* Read & interpret it ourselves */
4001 else
4002 {
4003 unsigned char xtable[256], *src, *tbuf = NULL;
4004 uint32 x0, y0, xstep = tw ? tw : width, ystep = th ? th : rps;
4005 int aalpha, tsz = 0, wbpp = bpp;
4006 int bpr, bits1, bit0, db, n, nx;
4007 int j, k, bsz, plane, nplanes;
4008
4009
4010 if (pmetric == PHOTOMETRIC_SEPARATED) // Needs temp buffer
4011 tsz = xstep * ystep * (wbpp = 4);
4012 nplanes = planar ? wbpp + !!settings->img[CHN_ALPHA] : 1;
4013
4014 bsz = (tw ? TIFFTileSize(tif) : TIFFStripSize(tif)) + 1;
4015 bpr = tw ? TIFFTileRowSize(tif) : TIFFScanlineSize(tif);
4016
4017 buf = _TIFFmalloc(bsz + tsz);
4018 res = FILE_MEM_ERROR;
4019 if (!buf) goto fail2;
4020 res = FILE_LIB_ERROR;
4021 if (tsz) tbuf = buf + bsz; // Temp buffer for CMYK->RGB
4022
4023 /* Flag associated alpha */
4024 aalpha = settings->img[CHN_ALPHA] &&
4025 (pmetric != PHOTOMETRIC_PALETTE) &&
4026 (sampinfo[0] == EXTRASAMPLE_ASSOCALPHA);
4027
4028 bits1 = bpsamp > 8 ? 8 : bpsamp;
4029
4030 /* Setup greyscale palette */
4031 if ((bpp == 1) && (pmetric != PHOTOMETRIC_PALETTE))
4032 {
4033 /* Demultiplied values are 0..255 */
4034 j = aalpha ? 256 : 1 << bits1;
4035 settings->colors = j--;
4036 k = pmetric == PHOTOMETRIC_MINISBLACK ? 0 : j;
4037 mem_bw_pal(settings->pal, k, j ^ k);
4038 }
4039
4040 /* !!! Assume 16-, 32- and 64-bit data follow machine's
4041 * endianness, and everything else is packed big-endian way -
4042 * like TIFF 6.0 spec says; but TIFF 5.0 and before specs said
4043 * differently, so let's wait for examples to see if I'm right
4044 * or not; as for 24- and 128-bit, even different libtiff
4045 * versions handle them differently, so I leave them alone
4046 * for now - WJ */
4047
4048 bit0 = (G_BYTE_ORDER == G_LITTLE_ENDIAN) &&
4049 ((bpsamp == 16) || (bpsamp == 32) ||
4050 (bpsamp == 64)) ? bpsamp - 8 : 0;
4051 db = (planar ? 1 : sampp) * bpsamp;
4052
4053 /* Prepare to rescale what we've got */
4054 memset(xtable, 0, 256);
4055 set_xlate(xtable, bits1);
4056
4057 /* Progress steps */
4058 nx = ((width + xstep - 1) / xstep) * nplanes * height;
4059
4060 /* Read image tile by tile - considering strip a wide tile */
4061 for (n = y0 = 0; y0 < height; y0 += ystep)
4062 for (x0 = 0; x0 < width; x0 += xstep)
4063 for (plane = 0; plane < nplanes; plane++)
4064 {
4065 unsigned char *tmp, *tmpa;
4066 uint32 x, y, w, h, l;
4067 int i, k, dx, dxa, dy, dys;
4068
4069 /* Read one piece */
4070 if (tw)
4071 {
4072 if (TIFFReadTile(tif, buf, x0, y0, 0, plane) < 0)
4073 goto fail2;
4074 }
4075 else
4076 {
4077 if (TIFFReadEncodedStrip(tif,
4078 TIFFComputeStrip(tif, y0, plane),
4079 buf, bsz) < 0) goto fail2;
4080 }
4081
4082 /* Prepare decoding loops */
4083 if (mirror & 1) /* X mirror */
4084 {
4085 x = width - x0;
4086 w = x < xstep ? x : xstep;
4087 x -= w;
4088 }
4089 else
4090 {
4091 x = x0;
4092 w = x + xstep > width ? width - x : xstep;
4093 }
4094 if (mirror & 2) /* Y mirror */
4095 {
4096 y = height - y0;
4097 h = y < ystep ? y : ystep;
4098 y -= h;
4099 }
4100 else
4101 {
4102 y = y0;
4103 h = y + ystep > height ? height - y : ystep;
4104 }
4105
4106 /* Prepare pointers */
4107 dx = dxa = 1; dy = width;
4108 i = y * width + x;
4109 tmp = tmpa = settings->img[CHN_ALPHA] + i;
4110 if (plane >= wbpp); // Alpha
4111 else if (tbuf) // CMYK
4112 {
4113 dx = 4; dy = w;
4114 tmp = tbuf + plane;
4115 }
4116 else // RGB/indexed
4117 {
4118 dx = bpp;
4119 tmp = settings->img[CHN_IMAGE] + plane + i * bpp;
4120 }
4121 dy *= dx; dys = bpr;
4122 src = buf;
4123 /* Account for horizontal mirroring */
4124 if (mirror & 1)
4125 {
4126 // Write bytes backward
4127 tmp += (w - 1) * dx; tmpa += w - 1;
4128 dx = -dx; dxa = -1;
4129 }
4130 /* Account for vertical mirroring */
4131 if (mirror & 2)
4132 {
4133 // Read rows backward
4134 src += (h - 1) * dys;
4135 dys = -dys;
4136 }
4137
4138 /* Decode it */
4139 for (l = 0; l < h; l++ , n++ , src += dys , tmp += dy)
4140 {
4141 if (pr && ((n * 10) % nx >= nx - 10))
4142 progress_update((float)n / nx);
4143
4144 stream_MSB(src, tmp, w, bits1, bit0, db, dx);
4145 if (planar) continue;
4146 for (k = 1; k < wbpp; k++)
4147 {
4148 stream_MSB(src, tmp + k, w, bits1,
4149 bit0 + bpsamp * k, db, dx);
4150 }
4151 if (settings->img[CHN_ALPHA])
4152 {
4153 stream_MSB(src, tmpa, w, bits1,
4154 bit0 + bpsamp * wbpp, db, dxa);
4155 tmpa += width;
4156 }
4157 }
4158
4159 /* Convert CMYK to RGB if needed */
4160 if (!tbuf || (planar && (plane != 3))) continue;
4161 if (bits1 < 8) // Rescale to 8-bit
4162 do_xlate(xtable, tbuf, w * h * 4);
4163 cmyk2rgb(tbuf, tbuf, w * h, FALSE, settings);
4164 src = tbuf;
4165 tmp = settings->img[CHN_IMAGE] + (y * width + x) * 3;
4166 w *= 3;
4167 for (l = 0; l < h; l++ , tmp += width * 3 , src += w)
4168 memcpy(tmp, src, w);
4169 }
4170 done_cmyk2rgb(settings);
4171
4172 j = width * height;
4173 tmp = settings->img[CHN_IMAGE];
4174 src = settings->img[CHN_ALPHA];
4175
4176 /* Unassociate alpha */
4177 if (aalpha)
4178 {
4179 if (wbpp > 3) // Converted from CMYK
4180 {
4181 unsigned char *img = tmp;
4182 int i, k, a;
4183
4184 if (bits1 < 8) do_xlate(xtable, src, j);
4185 bits1 = 8; // No further rescaling needed
4186
4187 /* Remove white background */
4188 for (i = 0; i < j; i++ , img += 3)
4189 {
4190 a = src[i] - 255;
4191 k = a + img[0];
4192 img[0] = k < 0 ? 0 : k;
4193 k = a + img[1];
4194 img[1] = k < 0 ? 0 : k;
4195 k = a + img[2];
4196 img[2] = k < 0 ? 0 : k;
4197 }
4198 }
4199 mem_demultiply(tmp, src, j, bpp);
4200 tmp = NULL; // Image is done
4201 }
4202
4203 if (bits1 < 8)
4204 {
4205 /* Rescale alpha */
4206 if (src) do_xlate(xtable, src, j);
4207 /* Rescale RGB */
4208 if (tmp && (wbpp == 3)) do_xlate(xtable, tmp, j * 3);
4209 }
4210 res = 1;
4211 }
4212
4213 fail2: if (pr) progress_end();
4214 if (raster) _TIFFfree(raster);
4215 if (buf) _TIFFfree(buf);
4216 return (res);
4217 }
4218
load_tiff_frames(char * file_name,ani_settings * ani)4219 static int load_tiff_frames(char *file_name, ani_settings *ani)
4220 {
4221 TIFF *tif;
4222 ls_settings w_set;
4223 int res;
4224
4225
4226 /* We don't want any echoing to the output */
4227 TIFFSetErrorHandler(NULL);
4228 TIFFSetWarningHandler(NULL);
4229
4230 if (!(tif = TIFFOpen(file_name, "r"))) return (-1);
4231
4232 while (TRUE)
4233 {
4234 res = FILE_TOO_LONG;
4235 if (!check_next_frame(&ani->fset, ani->settings.mode, FALSE))
4236 goto fail;
4237 w_set = ani->settings;
4238 w_set.gif_delay = -1; // Multipage
4239 res = load_tiff_frame(tif, &w_set);
4240 if (res != 1) goto fail;
4241 res = process_page_frame(file_name, ani, &w_set);
4242 if (res) goto fail;
4243 /* Try to get next frame */
4244 if (!TIFFReadDirectory(tif)) break;
4245 }
4246 res = 1;
4247 fail: TIFFClose(tif);
4248 return (res);
4249 }
4250
4251 #ifndef TIFF_VERSION_BIG /* The ONLY useful way to detect libtiff 4.x vs 3.x */
4252 #define tmsize_t tsize_t
4253 #endif
4254
mTIFFread(thandle_t fd,void * buf,tmsize_t size)4255 static tmsize_t mTIFFread(thandle_t fd, void* buf, tmsize_t size)
4256 {
4257 return mfread(buf, 1, size, (memFILE *)fd);
4258 }
4259
mTIFFwrite(thandle_t fd,void * buf,tmsize_t size)4260 static tmsize_t mTIFFwrite(thandle_t fd, void* buf, tmsize_t size)
4261 {
4262 return mfwrite(buf, 1, size, (memFILE *)fd);
4263 }
4264
mTIFFlseek(thandle_t fd,toff_t off,int whence)4265 static toff_t mTIFFlseek(thandle_t fd, toff_t off, int whence)
4266 {
4267 return mfseek((memFILE *)fd, (f_long)off, whence) ? -1 : ((memFILE *)fd)->m.here;
4268 }
4269
mTIFFclose(thandle_t fd)4270 static int mTIFFclose(thandle_t fd)
4271 {
4272 return 0;
4273 }
4274
mTIFFsize(thandle_t fd)4275 static toff_t mTIFFsize(thandle_t fd)
4276 {
4277 return ((memFILE *)fd)->top;
4278 }
4279
mTIFFmap(thandle_t fd,void ** base,toff_t * size)4280 static int mTIFFmap(thandle_t fd, void** base, toff_t* size)
4281 {
4282 *base = ((memFILE *)fd)->m.buf;
4283 *size = ((memFILE *)fd)->top;
4284 return 1;
4285 }
4286
mTIFFunmap(thandle_t fd,void * base,toff_t size)4287 static void mTIFFunmap(thandle_t fd, void* base, toff_t size)
4288 {
4289 }
4290
load_tiff(char * file_name,ls_settings * settings,memFILE * mf)4291 static int load_tiff(char *file_name, ls_settings *settings, memFILE *mf)
4292 {
4293 TIFF *tif;
4294 int res;
4295
4296
4297 /* We don't want any echoing to the output */
4298 TIFFSetErrorHandler(NULL);
4299 TIFFSetWarningHandler(NULL);
4300
4301 if (!mf) tif = TIFFOpen(file_name, "r");
4302 else tif = TIFFClientOpen("", "r", (void *)mf, mTIFFread, mTIFFwrite,
4303 mTIFFlseek, mTIFFclose, mTIFFsize, mTIFFmap, mTIFFunmap);
4304 if (!tif) return (-1);
4305 res = load_tiff_frame(tif, settings);
4306 if ((res == 1) && TIFFReadDirectory(tif)) res = FILE_HAS_FRAMES;
4307 TIFFClose(tif);
4308 return (res);
4309 }
4310
save_tiff(char * file_name,ls_settings * settings,memFILE * mf)4311 static int save_tiff(char *file_name, ls_settings *settings, memFILE *mf)
4312 {
4313 unsigned char buf[MAX_WIDTH / 8], *src, *row = NULL;
4314 uint16 rgb[256 * 3];
4315 unsigned int tflags, sflags, xflags;
4316 int i, l, type, bw, af, pf, res = 0, pmetric = -1;
4317 int w = settings->width, h = settings->height, bpp = settings->bpp;
4318 TIFF *tif;
4319
4320
4321 /* Select output mode */
4322 sflags = FF_SAVE_MASK_FOR(*settings);
4323 type = settings->tiff_type;
4324 if (type < 0) type = bpp == 3 ? tiff_rtype : // RGB
4325 settings->colors <= 2 ? tiff_btype : // BW
4326 tiff_itype; // Indexed
4327 if (settings->mode == FS_CLIPBOARD)
4328 {
4329 type = 0; // Uncompressed
4330 /* RGB for clipboard mask */
4331 if (settings->img[CHN_ALPHA]) sflags = FF_RGB , bpp = 3;
4332 }
4333 tflags = tiff_formats[type].flags;
4334 sflags &= tflags;
4335 bw = !(sflags & (FF_256 | FF_RGB));
4336 if (!sflags) return WRONG_FORMAT; // Paranoia
4337
4338 af = settings->img[CHN_ALPHA] && (tflags & FF_ALPHA);
4339
4340 /* Use 1-bit mode where possible */
4341 if (!bw && !af && (sflags & FF_BW))
4342 {
4343 /* No need of palette if the colors are full white and black */
4344 i = PNG_2_INT(settings->pal[0]);
4345 bw = (!i ? 0xFFFFFF : i == 0xFFFFFF ? 0 : -1) ==
4346 PNG_2_INT(settings->pal[1]) ? 1 : -1;
4347 }
4348
4349 /* !!! When using predictor, libtiff 3.8 modifies row buffer in-place */
4350 pf = tiff_predictor && !bw && tiff_formats[type].pflag;
4351 if (af || pf || (bpp > settings->bpp))
4352 {
4353 row = malloc(w * (bpp + af));
4354 if (!row) return -1;
4355 }
4356
4357 TIFFSetErrorHandler(NULL); // We don't want any echoing to the output
4358 TIFFSetWarningHandler(NULL);
4359 if (!mf) tif = TIFFOpen(file_name, "w");
4360 else tif = TIFFClientOpen("", "w", (void *)mf, mTIFFread, mTIFFwrite,
4361 mTIFFlseek, mTIFFclose, mTIFFsize, mTIFFmap, mTIFFunmap);
4362 if (!tif)
4363 {
4364 free(row);
4365 return -1;
4366 }
4367
4368 /* Write regular tags */
4369 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
4370 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
4371 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, bpp + af);
4372 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bw ? 1 : 8);
4373 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
4374
4375 /* Write compression-specific tags */
4376 TIFFSetField(tif, TIFFTAG_COMPRESSION, tiff_formats[type].id);
4377 xflags = tiff_formats[type].xflags;
4378 if (xflags & XF_COMPZT)
4379 TIFFSetField(tif, TIFFTAG_ZIPQUALITY, settings->png_compression);
4380 #ifdef COMPRESSION_LZMA
4381 if (xflags & XF_COMPLZ)
4382 TIFFSetField(tif, TIFFTAG_LZMAPRESET, settings->lzma_preset);
4383 #endif
4384 #ifdef COMPRESSION_ZSTD
4385 if (xflags & XF_COMPZS)
4386 TIFFSetField(tif, TIFFTAG_ZSTD_LEVEL, settings->zstd_level);
4387 #endif
4388 #ifdef COMPRESSION_WEBP
4389 if (xflags & XF_COMPWT)
4390 {
4391 TIFFSetField(tif, TIFFTAG_WEBP_LEVEL, settings->webp_quality);
4392 // !!! libtiff 4.0.10 *FAILS* to do it losslessly despite trying
4393 if (settings->webp_quality == 100)
4394 TIFFSetField(tif, TIFFTAG_WEBP_LOSSLESS, 1);
4395 }
4396 #endif
4397 if (xflags & XF_COMPJ)
4398 {
4399 TIFFSetField(tif, TIFFTAG_JPEGQUALITY, settings->jpeg_quality);
4400 TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4401 pmetric = PHOTOMETRIC_YCBCR;
4402 }
4403 if (pf) TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
4404
4405 if (bw > 0) pmetric = get_bw(settings) ? PHOTOMETRIC_MINISWHITE :
4406 PHOTOMETRIC_MINISBLACK;
4407 else if (bpp == 1)
4408 {
4409 pmetric = PHOTOMETRIC_PALETTE;
4410 memset(rgb, 0, sizeof(rgb));
4411 l = bw ? 2 : 256;
4412 for (i = 0; i < settings->colors; i++)
4413 {
4414 rgb[i] = settings->pal[i].red * 257;
4415 rgb[i + l] = settings->pal[i].green * 257;
4416 rgb[i + l * 2] = settings->pal[i].blue * 257;
4417 }
4418 TIFFSetField(tif, TIFFTAG_COLORMAP, rgb, rgb + l, rgb + l * 2);
4419 }
4420 else if (pmetric < 0) pmetric = PHOTOMETRIC_RGB;
4421 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, pmetric);
4422 if (af)
4423 {
4424 rgb[0] = EXTRASAMPLE_UNASSALPHA;
4425 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, rgb);
4426 }
4427
4428 /* Actually write the image */
4429 if (!settings->silent) ls_init("TIFF", 1);
4430 for (i = 0; i < h; i++)
4431 {
4432 src = settings->img[CHN_IMAGE] + w * i * settings->bpp;
4433 if (bw) /* Pack the bits */
4434 {
4435 pack_MSB(buf, src, w, 1);
4436 src = buf;
4437 }
4438 else if (row) /* Fill the buffer */
4439 src = prepare_row(row, settings, bpp + af, i);
4440 if (TIFFWriteScanline(tif, src, i, 0) == -1)
4441 {
4442 res = -1;
4443 break;
4444 }
4445 ls_progress(settings, i, 20);
4446 }
4447 TIFFClose(tif);
4448
4449 if (!settings->silent) progress_end();
4450
4451 free(row);
4452 return (res);
4453 }
4454 #endif
4455
4456 #ifdef U_WEBP
4457
4458 /* *** PREFACE ***
4459 * WebP Demux API is exceedingly cumbersome in case you don't feed the entire
4460 * file to it in one single memory block. Stepping through the RIFF container to
4461 * pick individual chunks is more manageable. */
4462
4463 /* Macro for little-endian tags (RIFF) */
4464 #define TAG4(A,B,C,D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))
4465
4466 #define GET24(buf) (((buf)[2] << 16) + ((buf)[1] << 8) + (buf)[0])
4467 #define PUT24(buf, v) (buf)[0] = (v) & 0xFF; (buf)[1] = ((v) >> 8) & 0xFF; \
4468 (buf)[2] = ((v) >> 16) & 0xFF;
4469
4470 /* !!! In documentation, bit fields are written in reverse; actual flag values
4471 * used by libwebp are as if bits are numbered right to left instead - WJ */
4472
4473 /* Macros for WEBP tags */
4474 #define TAG4_RIFF TAG4('R', 'I', 'F', 'F')
4475 #define TAG4_WEBP TAG4('W', 'E', 'B', 'P')
4476 #define TAG4_VP8X TAG4('V', 'P', '8', 'X')
4477 #define TAG4_ANIM TAG4('A', 'N', 'I', 'M')
4478 #define TAG4_ANMF TAG4('A', 'N', 'M', 'F')
4479 #define TAG4_VP8 TAG4('V', 'P', '8', ' ')
4480 #define TAG4_VP8L TAG4('V', 'P', '8', 'L')
4481 #define TAG4_ALPH TAG4('A', 'L', 'P', 'H')
4482 #define TAG4_ICCP TAG4('I', 'C', 'C', 'P')
4483 #define TAG4_EXIF TAG4('E', 'X', 'I', 'F')
4484 #define TAG4_XMP TAG4('X', 'M', 'P', ' ')
4485
4486 #define RIFF_TAGSIZE 4
4487
4488 /* RIFF block header */
4489 #define RIFF_TAG 0 /* 32b */
4490 #define RIFF_SIZE 4 /* 32b */
4491 #define RIFF_HSIZE 8
4492
4493 /* WEBP header block (VP8X tag) */
4494 #define VP8X_FLAGS 0 /* 8b */
4495 #define VP8X_W1 4 /* 24b */
4496 #define VP8X_H1 7 /* 24b */
4497 #define VP8X_SIZE 10
4498
4499 /* VP8X flags (ignore on read) */
4500 #define VP8XF_ANIM 2
4501 #define VP8XF_ALPHA 16
4502 #define VP8XF_ICC 32
4503
4504 /* ANIM block */
4505 /* !!! Background color & alpha are ignored by vwebp */
4506 #define ANIM_BKG_B 0 /* 8b */
4507 #define ANIM_BKG_G 1 /* 8b */
4508 #define ANIM_BKG_R 2 /* 8b */
4509 #define ANIM_BKG_A 3 /* 8b */
4510 #define ANIM_LOOP 4 /* 16b */
4511 #define ANIM_SIZE 6
4512
4513 /* ANMF block header */
4514 #define ANMF_X2 0 /* 24b */
4515 #define ANMF_Y2 3 /* 24b */
4516 #define ANMF_W1 6 /* 24b */
4517 #define ANMF_H1 9 /* 24b */
4518 #define ANMF_DELAY 12 /* 24b */
4519 #define ANMF_FLAGS 15 /* 8b */
4520 #define ANMF_HSIZE 16
4521
4522 /* ANMF flags */
4523 #define ANMF_F_NOBLEND 2
4524 #define ANMF_F_BKG 1 /* Dispose to background */
4525
4526 #define HAVE_IMG 0x01
4527 #define HAVE_VP8X 0x02
4528 #define HAVE_ANIM 0x04
4529 #define HAVE_XTRA 0x08
4530 #define HAVE_ALPH 0x10
4531 #define HAVE_ANMF 0x20
4532
4533 typedef struct {
4534 FILE *f;
4535 unsigned len; // File data left unparsed
4536 unsigned size; // How much to read for this frame
4537 int blocks;
4538 unsigned char hdr[VP8X_SIZE], bkg[4];
4539 unsigned char anmf[ANMF_HSIZE + RIFF_TAGSIZE];
4540 } webphead;
4541
load_webp_frame(webphead * wp,ls_settings * settings)4542 static int load_webp_frame(webphead *wp, ls_settings *settings)
4543 {
4544 WebPDecoderConfig dconf;
4545 unsigned char *buf;
4546 int wh, bpp, wbpp = 3, cmask = CMASK_IMAGE, res = -1;
4547
4548
4549 if (!WebPInitDecoderConfig(&dconf)) return (-1); // Wrong lib version
4550 if (!(buf = malloc(wp->size))) return (FILE_MEM_ERROR);
4551 if (fread(buf, 1, wp->size, wp->f) != wp->size) goto fail;
4552 if (WebPGetFeatures((void *)buf, wp->size, &dconf.input) != VP8_STATUS_OK)
4553 goto fail;
4554
4555 if (dconf.input.has_alpha) wbpp = 4 , cmask = CMASK_RGBA;
4556 wh = dconf.input.width * dconf.input.height;
4557 settings->width = dconf.input.width;
4558 settings->height = dconf.input.height;
4559 settings->bpp = wbpp;
4560
4561 /* Get the extras from frame header */
4562 if (wp->blocks & HAVE_ANMF)
4563 {
4564 settings->x = GET24(wp->anmf + ANMF_X2) * 2;
4565 settings->y = GET24(wp->anmf + ANMF_Y2) * 2;
4566 /* Within mtPaint delays are 1/100s granular */
4567 settings->gif_delay = (GET24(wp->anmf + ANMF_DELAY) + 9) / 10; // Round up
4568 }
4569
4570 if ((res = allocate_image(settings, cmask))) goto fail;
4571
4572 bpp = settings->img[CHN_ALPHA] ? 4 : 3;
4573 dconf.output.colorspace = bpp > 3 ? MODE_RGBA : MODE_RGB;
4574 dconf.output.u.RGBA.rgba = settings->img[CHN_IMAGE];
4575 dconf.output.u.RGBA.stride = settings->width * bpp;
4576 dconf.output.u.RGBA.size = wh * bpp;
4577 dconf.output.is_external_memory = 1;
4578
4579 if (!settings->silent) ls_init("WebP", 0);
4580 res = FILE_LIB_ERROR;
4581 if (WebPDecode(buf, wp->size, &dconf) == VP8_STATUS_OK)
4582 {
4583 if (bpp == 4) /* Separate out alpha from RGBA */
4584 {
4585 copy_bytes(settings->img[CHN_ALPHA],
4586 settings->img[CHN_IMAGE] + 3, wh, 1, 4);
4587 copy_bytes(settings->img[CHN_IMAGE],
4588 settings->img[CHN_IMAGE], wh, 3, 4);
4589 }
4590 if (wbpp > 3) /* Downsize image channel */
4591 {
4592 unsigned char *w = realloc(settings->img[CHN_IMAGE], wh * 3);
4593 if (w) settings->img[CHN_IMAGE] = w;
4594 }
4595 res = 1;
4596 }
4597 if (!settings->silent) progress_end();
4598 WebPFreeDecBuffer(&dconf.output);
4599
4600 fail: free(buf);
4601 return (res);
4602 }
4603
webp_scan(webphead * wp,ls_settings * settings)4604 static int webp_scan(webphead *wp, ls_settings *settings)
4605 {
4606 unsigned char buf[256];
4607 FILE *fp = wp->f;
4608 unsigned tag, tl;
4609 f_long alph = -1;
4610
4611 if (!settings) // Next-frame mode
4612 {
4613 /* If a regular image was first, believe there are no other frames */
4614 if (!(wp->blocks & HAVE_ANMF)) return (FALSE);
4615
4616 wp->blocks &= ~(HAVE_ALPH | HAVE_IMG); // Prepare for new frame
4617 }
4618
4619 /* Read block headers & see what we get */
4620 while ((wp->len >= RIFF_HSIZE) && (fread(buf, 1, RIFF_HSIZE, fp) == RIFF_HSIZE))
4621 {
4622 tag = GET32(buf);
4623 tl = GET32(buf + RIFF_SIZE);
4624 if (tl > 0xFFFFFFFFU - 1 - RIFF_HSIZE) break; // MAX_CHUNK_PAYLOAD
4625 if (tl >= F_LONG_MAX) break; // Limit for what can be handled
4626 tl += tl & 1; // Pad
4627 if (wp->len < tl + RIFF_HSIZE) break; // Does not fit in RIFF
4628 wp->len -= tl + RIFF_HSIZE;
4629
4630 if (tag == TAG4_ANMF)
4631 {
4632 if (tl < ANMF_HSIZE + RIFF_HSIZE) break;
4633 if (fread(wp->anmf, 1, ANMF_HSIZE + RIFF_TAGSIZE, fp) !=
4634 ANMF_HSIZE + RIFF_TAGSIZE) break;
4635 fseek(fp, -RIFF_TAGSIZE, SEEK_CUR);
4636 wp->blocks |= HAVE_ANMF;
4637 tag = GET32(wp->anmf + ANMF_HSIZE);
4638 if (tag == TAG4_ALPH) wp->blocks |= HAVE_ALPH;
4639 else if ((tag != TAG4_VP8) && (tag != TAG4_VP8L)) break; // Damaged?
4640 wp->size = tl - ANMF_HSIZE;
4641 wp->blocks |= HAVE_IMG;
4642 break; // Done
4643 }
4644 /* Be extra accepting - skip duplicates of header chunks w/o failing */
4645 else if (!settings && ((tag == TAG4_VP8X) || (tag == TAG4_ANIM) ||
4646 (tag == TAG4_ICCP)));
4647 /* Fail on encountering image chunk where a frame should be */
4648 else if (!settings && ((tag == TAG4_VP8) || (tag == TAG4_VP8L) ||
4649 (tag == TAG4_ALPH))) break;
4650 else if (tag == TAG4_VP8X)
4651 {
4652 if (tl != VP8X_SIZE) break;
4653 if (fread(wp->hdr, 1, VP8X_SIZE, fp) != VP8X_SIZE) break;
4654 wp->blocks |= HAVE_VP8X;
4655 continue;
4656 }
4657 else if (tag == TAG4_ANIM)
4658 {
4659 if (tl != ANIM_SIZE) break;
4660 if (fread(buf, 1, ANIM_SIZE, fp) != ANIM_SIZE) break;
4661 /* Rearrange the bytes the sane way */
4662 wp->bkg[0] = buf[ANIM_BKG_R];
4663 wp->bkg[1] = buf[ANIM_BKG_G];
4664 wp->bkg[2] = buf[ANIM_BKG_B];
4665 wp->bkg[3] = buf[ANIM_BKG_A];
4666 wp->blocks |= HAVE_ANIM;
4667 continue;
4668 }
4669 #ifdef U_LCMS
4670 else if (tag == TAG4_ICCP)
4671 {
4672 unsigned char *tmp = NULL;
4673
4674 wp->blocks |= HAVE_XTRA;
4675 if (!settings->icc_size &&
4676 (tl < INT_MAX) && // For sanity (and icc_size size)
4677 (tmp = malloc(tl)) &&
4678 (fread(tmp, 1, tl, fp) == tl))
4679 {
4680 settings->icc = tmp;
4681 settings->icc_size = tl;
4682 continue;
4683 }
4684 if (tmp) /* Failed to read */
4685 {
4686 free(tmp);
4687 break;
4688 }
4689 }
4690 #endif
4691 else if (tag == TAG4_ALPH)
4692 {
4693 wp->blocks |= HAVE_ALPH;
4694 alph = ftell(fp);
4695 if (alph < 0) break;
4696 }
4697 else if ((tag == TAG4_VP8) || (tag == TAG4_VP8L))
4698 {
4699 fseek(fp, -RIFF_HSIZE, SEEK_CUR);
4700 wp->size = tl + RIFF_HSIZE;
4701 if (alph > 0) // Need to start with alpha
4702 {
4703 f_long here = ftell(fp);
4704 if (here < 0) break; // Too long for us
4705 /* From ALPH header to this block's end */
4706 wp->size += here - alph + RIFF_HSIZE;
4707 fseek(fp, alph - RIFF_HSIZE, SEEK_SET);
4708 }
4709 wp->blocks |= HAVE_IMG;
4710 break;
4711 }
4712 else wp->blocks |= HAVE_XTRA;
4713 /* Default: skip (the rest of) tag data */
4714 if (tl && fseek(fp, tl, SEEK_CUR)) break;
4715 }
4716 return (wp->blocks & HAVE_IMG);
4717 }
4718
webp_behead(FILE * fp,webphead * wp,ls_settings * settings)4719 static int webp_behead(FILE *fp, webphead *wp, ls_settings *settings)
4720 {
4721 unsigned char buf[RIFF_HSIZE + RIFF_TAGSIZE];
4722 unsigned tl;
4723
4724
4725 memset(wp, 0, sizeof(webphead));
4726 wp->f = fp;
4727
4728 /* Read the RIFF header & check signature */
4729 if (fread(buf, 1, RIFF_HSIZE + RIFF_TAGSIZE, fp) < RIFF_HSIZE + RIFF_TAGSIZE)
4730 return (FALSE);
4731 if ((GET32(buf) != TAG4_RIFF) || (GET32(buf + RIFF_HSIZE) != TAG4_WEBP))
4732 return (FALSE);
4733
4734 tl = GET32(buf + RIFF_SIZE);
4735 if (tl < RIFF_TAGSIZE + RIFF_HSIZE) return (FALSE);
4736 tl -= RIFF_TAGSIZE;
4737 tl += tl & 1; // Pad
4738 wp->len = tl;
4739
4740 webp_scan(wp, settings);
4741 return (wp->blocks & HAVE_IMG);
4742 }
4743
load_webp_frames(char * file_name,ani_settings * ani)4744 static int load_webp_frames(char *file_name, ani_settings *ani)
4745 {
4746 webphead wp;
4747 ani_status stat;
4748 ls_settings w_set, init_set;
4749 FILE *fp;
4750 int bpp, disposal, res = -1;
4751
4752
4753 if (!(fp = fopen(file_name, "rb"))) return (-1);
4754 memset(w_set.img, 0, sizeof(chanlist));
4755
4756 /* Init temp container */
4757 init_set = ani->settings;
4758 if (!webp_behead(fp, &wp, &init_set)) goto fail;
4759
4760 /* Need to have them to read them */
4761 if ((wp.blocks & (HAVE_VP8X | HAVE_ANMF)) != (HAVE_VP8X | HAVE_ANMF))
4762 goto fail;
4763
4764 /* Init state structure */
4765 memset(&stat, 0, sizeof(stat));
4766 stat.mode = ani->mode;
4767 stat.defw = GET24(wp.hdr + VP8X_W1) + 1;
4768 stat.defh = GET24(wp.hdr + VP8X_H1) + 1;
4769 /* WebP has no palette of its own, use the default one */
4770 mem_pal_copy(stat.newpal, ani->settings.pal);
4771 stat.newcols = ani->settings.colors;
4772 stat.newtrans = -1; // No color-key transparency
4773 /* !!! vwebp ignores the value by default, and one example animation
4774 * expects transparency despite background set to opaque white - WJ */
4775 // memcpy(stat.bkg, wp.bkg, 4); // RGBA background
4776
4777 /* Go through images */
4778 while (TRUE)
4779 {
4780 res = FILE_TOO_LONG;
4781 if (!check_next_frame(&ani->fset, ani->settings.mode, TRUE))
4782 goto fail;
4783 w_set = init_set;
4784 res = load_webp_frame(&wp, &w_set);
4785 if (res != 1) goto fail;
4786 disposal = wp.anmf[ANMF_FLAGS] & ANMF_F_BKG ? FM_DISP_REMOVE :
4787 FM_DISP_LEAVE;
4788 delete_alpha(&w_set, 255);
4789 stat.blend = !(wp.anmf[ANMF_FLAGS] & ANMF_F_NOBLEND) && w_set.img[CHN_ALPHA];
4790 /* Analyze how we can merge the frames */
4791 res = TOO_BIG;
4792 bpp = analyze_rgba_frame(&stat, &w_set);
4793 if (bpp < 0) goto fail;
4794
4795 /* Allocate a new frame */
4796 res = add_frame(ani, &stat, &w_set, bpp, disposal);
4797 if (res) goto fail;
4798
4799 /* Do actual compositing, remember disposal method */
4800 composite_frame(&ani->fset, &stat, &w_set);
4801 mem_free_chanlist(w_set.img);
4802 memset(w_set.img, 0, sizeof(chanlist));
4803
4804 /* Write out those frames worthy to be stored */
4805 res = done_frame(file_name, ani, FALSE);
4806 if (res != 1) goto fail;
4807
4808 /* Step to the next frame, if any */
4809 if (!webp_scan(&wp, NULL)) break;
4810 }
4811 /* Write out the final frame if not written before */
4812 res = done_frame(file_name, ani, TRUE);
4813
4814 fail: mem_free_chanlist(w_set.img);
4815 fclose(fp);
4816 return (res);
4817 }
4818
load_webp(char * file_name,ls_settings * settings)4819 static int load_webp(char *file_name, ls_settings *settings)
4820 {
4821 webphead wp;
4822 FILE *fp;
4823 int res = -1;
4824
4825
4826 if (!(fp = fopen(file_name, "rb"))) return (-1);
4827 if (webp_behead(fp, &wp, settings))
4828 {
4829 res = load_webp_frame(&wp, settings);
4830 if ((res == 1) && webp_scan(&wp, NULL)) res = FILE_HAS_FRAMES;
4831 }
4832 fclose(fp);
4833 return (res);
4834 }
4835
webp_fwrite(const uint8_t * data,size_t data_size,const WebPPicture * picture)4836 static int webp_fwrite(const uint8_t *data, size_t data_size, const WebPPicture *picture)
4837 {
4838 return (fwrite(data, sizeof(uint8_t), data_size, picture->custom_ptr) == data_size);
4839 }
4840
webp_progress(int percent,const WebPPicture * picture)4841 static int webp_progress(int percent, const WebPPicture *picture)
4842 {
4843 return (!progress_update((float)percent / 100));
4844 }
4845
4846 char *webp_presets[] = { _("Lossless"), _("Default"), _("Picture"), _("Photo"),
4847 _("Drawing"), _("Icon"), _("Text"), NULL };
4848
4849 // !!! Min version 0.5.0
4850
save_webp(char * file_name,ls_settings * settings)4851 static int save_webp(char *file_name, ls_settings *settings)
4852 {
4853 static const signed char presets[] = {
4854 WEBP_PRESET_DEFAULT, /* Lossless */
4855 WEBP_PRESET_DEFAULT,
4856 WEBP_PRESET_PICTURE,
4857 WEBP_PRESET_PHOTO,
4858 WEBP_PRESET_DRAWING,
4859 WEBP_PRESET_ICON,
4860 WEBP_PRESET_TEXT };
4861 WebPConfig conf;
4862 WebPPicture pic;
4863 FILE *fp;
4864 unsigned char *rgba;
4865 int wh, st, res = -1;
4866
4867 if (settings->bpp == 1) return WRONG_FORMAT;
4868
4869 if ((fp = fopen(file_name, "wb")) == NULL) return (-1);
4870
4871 if (!WebPConfigPreset(&conf, presets[settings->webp_preset],
4872 settings->webp_quality)) goto ffail; // Lib failure
4873 if (!settings->webp_preset)
4874 WebPConfigLosslessPreset(&conf, settings->webp_compression);
4875 conf.exact = TRUE; // Preserve invisible parts
4876
4877 /* Prepare intermediate container */
4878 if (!WebPPictureInit(&pic)) goto ffail; // Lib failure
4879 pic.use_argb = TRUE;
4880 pic.width = settings->width;
4881 pic.height = settings->height;
4882 wh = pic.width * pic.height;
4883 pic.writer = webp_fwrite;
4884 pic.custom_ptr = (void *)fp;
4885 if (!settings->silent) pic.progress_hook = webp_progress;
4886 if (settings->img[CHN_ALPHA]) /* Need RGBA */
4887 {
4888 rgba = malloc(wh * 4);
4889 if (!rgba) goto ffail;
4890 copy_bytes(rgba, settings->img[CHN_IMAGE], wh, 4, 3);
4891 copy_bytes(rgba + 3, settings->img[CHN_ALPHA], wh, 4, 1);
4892 st = WebPPictureImportRGBA(&pic, rgba, pic.width * 4);
4893 free(rgba);
4894 }
4895 /* RGB is enough */
4896 else st = WebPPictureImportRGB(&pic, settings->img[CHN_IMAGE], pic.width * 3);
4897
4898 /* Do encode */
4899 if (st)
4900 {
4901 if (!settings->silent) ls_init("WebP", 1);
4902 if (WebPEncode(&conf, &pic)) res = 0;
4903 WebPPictureFree(&pic);
4904 if (!settings->silent) progress_end();
4905 }
4906
4907 ffail: fclose(fp);
4908 return (res);
4909 }
4910 #endif
4911
4912 /* Version 2 fields */
4913 #define BMP_FILESIZE 2 /* 32b */
4914 #define BMP_XHOT 6 /* 16b */
4915 #define BMP_YHOT 8 /* 16b */
4916 #define BMP_DATAOFS 10 /* 32b */
4917 #define BMP_HDR2SIZE 14 /* 32b */
4918 #define BMP_WIDTH 18 /* s32b */
4919 #define BMP_HEIGHT 22 /* s32b */
4920 #define BMP_PLANES 26 /* 16b */
4921 #define BMP_BPP 28 /* 16b */
4922 #define BMP2_HSIZE 30
4923 /* Version 3 fields */
4924 #define BMP_COMPRESS 30 /* 32b */
4925 #define BMP_DATASIZE 34 /* 32b */
4926 #define BMP_XDPI 38 /* s32b */
4927 #define BMP_YDPI 42 /* s32b */
4928 #define BMP_COLORS 46 /* 32b */
4929 #define BMP_ICOLORS 50 /* 32b */
4930 #define BMP3_HSIZE 54
4931 /* Version 4 fields */
4932 #define BMP_RMASK 54 /* 32b */
4933 #define BMP_GMASK 58 /* 32b */
4934 #define BMP_BMASK 62 /* 32b */
4935 #define BMP_AMASK 66 /* 32b */
4936 #define BMP_CSPACE 70 /* 32b */
4937 #define BMP4_HSIZE 122
4938 /* Version 5 fields */
4939 #define BMP_INTENT 122 /* 32b */
4940 #define BMP_ICCOFS 126 /* 32b */
4941 #define BMP_ICCSIZE 130 /* 32b */
4942 #define BMP5_HSIZE 138
4943 #define BMP_MAXHSIZE (BMP5_HSIZE + 256 * 4)
4944
4945 /* OS/2 1.x alternative fields */
4946 #define OS2BMP_WIDTH 18 /* 16b */
4947 #define OS2BMP_HEIGHT 20 /* 16b */
4948 #define OS2BMP_PLANES 22 /* 16b */
4949 #define OS2BMP_BPP 24 /* 16b */
4950 #define OS2BMP_HSIZE 26
4951
4952 /* OS/2 2.x bitmap header is version 3 fields plus some extra */
4953 #define OS2BMP2_HSIZE 78
4954 /* Shortened header variant encountered in the wild */
4955 #define OS2BMP2_HSIZE_S 38
4956
4957 /* OS/2 bitmap array fields */
4958 #define OS2BA_HDRSIZE 2 /* 32b */
4959 #define OS2BA_NEXT 6 /* 32b */
4960 #define OS2BA_HSIZE 14
4961
4962 /* In OS/2 files, BMP_FILESIZE may instead contain header size */
4963
4964 /* Colorspace tags */
4965 #define BMPCS_WIN TAG4B('W', 'i', 'n', ' ')
4966 #define BMPCS_SRGB TAG4B('s', 'R', 'G', 'B')
4967 #define BMPCS_LINK TAG4B('L', 'I', 'N', 'K')
4968 #define BMPCS_EMBED TAG4B('M', 'B', 'E', 'D')
4969
load_bmp(char * file_name,ls_settings * settings,memFILE * mf)4970 static int load_bmp(char *file_name, ls_settings *settings, memFILE *mf)
4971 {
4972 guint32 masks[4];
4973 unsigned char hdr[BMP5_HSIZE], xlat[256], *dest, *tmp, *buf = NULL;
4974 memFILE fake_mf;
4975 FILE *fp = NULL;
4976 unsigned l, ofs;
4977 int shifts[4], bpps[4];
4978 int def_alpha = FALSE, cmask = CMASK_IMAGE, comp = 0, ba = 0, rle = 0, res = -1;
4979 int i, j, k, n, ii, w, h, bpp, wbpp;
4980 int bl, rl, step, skip, dx, dy;
4981
4982
4983 if (!mf)
4984 {
4985 if (!(fp = fopen(file_name, "rb"))) return (-1);
4986 memset(mf = &fake_mf, 0, sizeof(fake_mf));
4987 fake_mf.file = fp;
4988 }
4989
4990 /* Read the largest header */
4991 k = mfread(hdr, 1, BMP5_HSIZE, mf);
4992
4993 /* Bitmap array? */
4994 if ((k > OS2BA_HSIZE) && (hdr[0] == 'B') && (hdr[1] == 'A'))
4995 {
4996 /* Just skip the header to go for 1st bitmap: no example files
4997 * with more than one bitmap anyway */
4998 ba = OS2BA_HSIZE;
4999 memmove(hdr, hdr + ba, k -= ba);
5000 }
5001 /* Check general validity */
5002 if (k < OS2BMP_HSIZE) goto fail; /* Least supported header size */
5003 if ((hdr[0] != 'B') || (hdr[1] != 'M')) goto fail; /* Signature */
5004 l = GET32(hdr + BMP_HDR2SIZE);
5005 if (k - BMP_HDR2SIZE < l) goto fail;
5006 l += BMP_HDR2SIZE;
5007 if (ba && (l > OS2BMP2_HSIZE)) goto fail; /* Should not exist */
5008 ofs = GET32(hdr + BMP_DATAOFS);
5009 if (l + ba > ofs) goto fail; // Overlap
5010 if (ofs > F_LONG_MAX) goto fail; // Cannot handle this length
5011
5012 /* Check format type: OS/2 or Windows */
5013 if (l == OS2BMP_HSIZE)
5014 {
5015 w = GET16(hdr + OS2BMP_WIDTH);
5016 h = GET16(hdr + OS2BMP_HEIGHT);
5017 bpp = GET16(hdr + OS2BMP_BPP);
5018 }
5019 else if (l >= BMP2_HSIZE)
5020 {
5021 w = GET32s(hdr + BMP_WIDTH);
5022 h = GET32s(hdr + BMP_HEIGHT);
5023 bpp = GET16(hdr + BMP_BPP);
5024 }
5025 else goto fail;
5026
5027 /* Check format */
5028 if (l >= BMP3_HSIZE) comp = GET32(hdr + BMP_COMPRESS);
5029 /* !!! Some 8bpp OS/2 BMPs in the wild have compression not marked */
5030 if (!comp && (bpp == 8) && (h > 0) && (l == OS2BMP2_HSIZE_S))
5031 {
5032 unsigned fsize = GET32(hdr + BMP_DATASIZE);
5033 if (fsize && (fsize != w * h)) comp = 1;
5034 }
5035 /* Only 1, 4, 8, 16, 24 and 32 bpp allowed */
5036 rle = comp;
5037 switch (bpp)
5038 {
5039 case 1: if (comp) goto fail; /* No compression */
5040 break;
5041 case 4: if (comp && (comp != 2)) goto fail; /* RLE4 */
5042 break;
5043 case 8: if (comp && (comp != 1)) goto fail; /* RLE8 */
5044 break;
5045 case 24: if (comp == 4) /* RLE24 or JPEG */
5046 {
5047 /* If not definitely OS/2 header, consider it JPEG */
5048 if ((l != OS2BMP2_HSIZE) && (l != OS2BMP2_HSIZE_S)) goto fail;
5049 break;
5050 }
5051 // Fallthrough
5052 case 16: case 32:
5053 rle = 0;
5054 if (comp && (comp != 3)) goto fail; /* Bitfields */
5055 shifts[3] = bpps[3] = masks[3] = 0; /* No alpha by default */
5056 if (comp == 3)
5057 {
5058 /* V3-style bitfields? */
5059 if ((l == BMP3_HSIZE) && (ofs >= BMP_AMASK)) l = BMP_AMASK;
5060 if (l < BMP_AMASK) goto fail;
5061 masks[0] = GET32(hdr + BMP_RMASK);
5062 masks[1] = GET32(hdr + BMP_GMASK);
5063 masks[2] = GET32(hdr + BMP_BMASK);
5064 if (l >= BMP_AMASK + 4)
5065 masks[3] = GET32(hdr + BMP_AMASK);
5066 if (masks[3]) cmask = CMASK_RGBA;
5067
5068 /* Convert masks into bit lengths and offsets */
5069 for (i = 0; i < 4; i++)
5070 {
5071 /* Bit length - just count bits */
5072 j = bitcount(masks[i]);
5073 /* Bit offset - add in bits _before_ mask */
5074 k = bitcount(masks[i] - 1) + 1;
5075 if (j > 8) j = 8;
5076 shifts[i] = k - j;
5077 bpps[i] = j;
5078 }
5079 }
5080 else if (bpp == 16)
5081 {
5082 shifts[0] = 10;
5083 shifts[1] = 5;
5084 shifts[2] = 0;
5085 bpps[0] = bpps[1] = bpps[2] = 5;
5086 }
5087 else
5088 {
5089 shifts[0] = 16;
5090 shifts[1] = 8;
5091 shifts[2] = 0;
5092 bpps[0] = bpps[1] = bpps[2] = 8;
5093 if (bpp == 32) /* Consider alpha present by default */
5094 {
5095 shifts[3] = 24;
5096 bpps[3] = 8;
5097 cmask = CMASK_RGBA;
5098 def_alpha = TRUE; /* Uncertain if alpha */
5099 }
5100 }
5101 break;
5102 default: goto fail;
5103 }
5104 if (rle && (h < 0)) goto fail; // Forbidden
5105
5106 /* Load palette if needed */
5107 if (bpp < 16)
5108 {
5109 unsigned char tbuf[1024];
5110 unsigned n, j = 0;
5111
5112 if (l >= BMP_COLORS + 4) j = GET32(hdr + BMP_COLORS);
5113 if (!j) j = 1 << bpp;
5114
5115 n = ofs - l - ba;
5116 k = l < BMP2_HSIZE ? 3 : 4;
5117 /* !!! Some OS/2 2.x BMPs have 3-bpc palettes too */
5118 if ((l == OS2BMP2_HSIZE) && (n < j * 4) && (n >= j * 3)) k = 3;
5119 n /= k;
5120 if (n < j) j = n;
5121 if (!j) goto fail; /* Wrong palette size */
5122 if (j > 256) j = 256; /* Let overlarge palette be */
5123 settings->colors = j;
5124 mfseek(mf, l + ba, SEEK_SET);
5125 i = mfread(tbuf, 1, j * k, mf);
5126 if (i < j * k) goto fail; /* Cannot read palette */
5127 tmp = tbuf;
5128 for (i = 0; i < j; i++)
5129 {
5130 settings->pal[i].red = tmp[2];
5131 settings->pal[i].green = tmp[1];
5132 settings->pal[i].blue = tmp[0];
5133 tmp += k;
5134 }
5135 /* If palette is all we need */
5136 res = 1;
5137 if ((settings->mode == FS_PALETTE_LOAD) ||
5138 (settings->mode == FS_PALETTE_DEF)) goto fail;
5139 }
5140 res = -1;
5141
5142 /* Allocate buffer and image */
5143 settings->width = w;
5144 settings->height = abs(h);
5145 settings->bpp = wbpp = bpp < 16 ? 1 : 3;
5146 rl = ((w * bpp + 31) >> 3) & ~3; /* Row data length */
5147 bl = rl; /* By default, only one row at a time */
5148 /* For RLE, load all compressed data at once */
5149 if (rle)
5150 {
5151 unsigned fsize = GET32(hdr + BMP_DATASIZE);
5152 if (fsize > INT_MAX - 1) goto fail;
5153 bl = fsize;
5154 }
5155 /* Sanity check */
5156 if (bl <= 0) goto fail;
5157 /* To accommodate bitparser's extra step */
5158 buf = malloc(bl + 1);
5159 res = FILE_MEM_ERROR;
5160 if (!buf) goto fail;
5161 if ((res = allocate_image(settings, cmask))) goto fail2;
5162
5163 #ifdef U_LCMS
5164 /* V5 can have embedded ICC profile */
5165 while (!settings->icc_size && (l == BMP5_HSIZE) &&
5166 (GET32(hdr + BMP_CSPACE) == BMPCS_EMBED))
5167 {
5168 unsigned char *icc = NULL;
5169 unsigned n, size = GET32(hdr + BMP_ICCSIZE), ofs = GET32(hdr + BMP_ICCOFS);
5170
5171 if (!size || (size > INT_MAX)) break; // Avoid the totally crazy
5172 if (ofs > F_LONG_MAX - BMP_HDR2SIZE) break; // Too far
5173 if (mfseek(mf, ofs + BMP_HDR2SIZE, SEEK_SET)) break; // Cannot go there
5174 icc = malloc(size);
5175 if (!icc) break;
5176 n = mfread(icc, 1, size, mf);
5177 if (n != size) free(icc); // Failed
5178 else settings->icc_size = size , settings->icc = icc; // Got it
5179 break;
5180 }
5181 #endif
5182
5183 if (!settings->silent) ls_init("BMP", 0);
5184
5185 mfseek(mf, ofs, SEEK_SET); /* Seek to data */
5186 if (h < 0) /* Prepare row loop */
5187 {
5188 step = 1;
5189 i = 0;
5190 h = -h;
5191 }
5192 else
5193 {
5194 step = -1;
5195 i = h - 1;
5196 }
5197 res = FILE_LIB_ERROR;
5198
5199 if (!rle) /* No RLE */
5200 {
5201 for (n = 0; (i < h) && (i >= 0); n++ , i += step)
5202 {
5203 j = mfread(buf, 1, rl, mf);
5204 if (j < rl) goto fail3;
5205 dest = settings->img[CHN_IMAGE] + w * i * wbpp;
5206 if (bpp < 16) /* Indexed */
5207 stream_MSB(buf, dest, w, bpp, 0, bpp, 1);
5208 else /* RGB */
5209 {
5210 stream_LSB(buf, dest + 0, w, bpps[0],
5211 shifts[0], bpp, 3);
5212 stream_LSB(buf, dest + 1, w, bpps[1],
5213 shifts[1], bpp, 3);
5214 stream_LSB(buf, dest + 2, w, bpps[2],
5215 shifts[2], bpp, 3);
5216 if (settings->img[CHN_ALPHA])
5217 stream_LSB(buf, settings->img[CHN_ALPHA] +
5218 w * i, w, bpps[3], shifts[3], bpp, 1);
5219 }
5220 ls_progress(settings, n, 10);
5221 }
5222
5223 /* Rescale shorter-than-byte RGBA components */
5224 if (bpp > 8)
5225 for (i = 0; i < 4; i++)
5226 {
5227 if (bpps[i] >= 8) continue;
5228 k = 3;
5229 if (i == 3)
5230 {
5231 tmp = settings->img[CHN_ALPHA];
5232 if (!tmp) continue;
5233 k = 1;
5234 }
5235 else tmp = settings->img[CHN_IMAGE] + i;
5236 set_xlate(xlat, bpps[i] + !bpps[i]); // Let 0-wide fields be
5237 n = w * h;
5238 for (j = 0; j < n; j++ , tmp += k) *tmp = xlat[*tmp];
5239 }
5240
5241 res = 1;
5242 }
5243 else /* RLE - always bottom-up */
5244 {
5245 k = mfread(buf, 1, bl, mf);
5246 if (k < bl) goto fail3;
5247 memset(settings->img[CHN_IMAGE], 0, w * h * wbpp);
5248 skip = j = 0;
5249
5250 dest = settings->img[CHN_IMAGE] + w * i * wbpp;
5251 for (tmp = buf; tmp - buf + 1 < k; )
5252 {
5253 /* Don't fail on out-of-bounds writes */
5254 if (*tmp) /* Fill block */
5255 {
5256 dx = n = *tmp;
5257 if (j + n > w) dx = j > w ? 0 : w - j;
5258 if (bpp == 24) /* 24-bit */
5259 {
5260 copy_run(dest + j * 3, tmp + 1, dx, 3, 0, TRUE);
5261 j += n; tmp += 4;
5262 continue;
5263 }
5264 if (bpp == 8) /* 8-bit */
5265 {
5266 memset(dest + j, tmp[1], dx);
5267 j += n; tmp += 2;
5268 continue;
5269 }
5270 for (ii = 0; ii < dx; ii++) /* 4-bit */
5271 {
5272 dest[j++] = tmp[1] >> 4;
5273 if (++ii >= dx) break;
5274 dest[j++] = tmp[1] & 0xF;
5275 }
5276 j += n - dx;
5277 tmp += 2;
5278 continue;
5279 }
5280 if (tmp[1] > 2) /* Copy block */
5281 {
5282 dx = n = tmp[1];
5283 if (j + n > w) dx = j > w ? 0 : w - j;
5284 tmp += 2;
5285 if (bpp == 24)
5286 {
5287 copy_run(dest + j * 3, tmp, dx, 3, 3, TRUE);
5288 j += n; tmp += (n * 3 + 1) & ~1;
5289 continue;
5290 }
5291 if (bpp == 8) /* 8-bit */
5292 {
5293 memcpy(dest + j, tmp, dx);
5294 j += n; tmp += (n + 1) & ~1;
5295 continue;
5296 }
5297 for (ii = 0; ii < dx; ii++) /* 4-bit */
5298 {
5299 dest[j++] = *tmp >> 4;
5300 if (++ii >= dx) break;
5301 dest[j++] = *tmp++ & 0xF;
5302 }
5303 j += n - dx;
5304 tmp += (((n + 3) & ~3) - (dx & ~1)) >> 1;
5305 continue;
5306 }
5307 if (tmp[1] == 2) /* Skip block */
5308 {
5309 dx = tmp[2] + j;
5310 dy = tmp[3];
5311 if (dx > w) goto fail3;
5312 if (dy > i) dx = 0 , dy = i + 1; // To the end
5313 }
5314 else /* End-of-something block */
5315 {
5316 dx = 0;
5317 dy = tmp[1] ? i + 1 : 1;
5318 }
5319 /* Transparency detected first time? */
5320 if (!skip && ((dy != 1) || dx || (j < w)))
5321 {
5322 if ((res = allocate_image(settings, CMASK_ALPHA)))
5323 goto fail3;
5324 res = FILE_LIB_ERROR;
5325 skip = 1;
5326 if (settings->img[CHN_ALPHA]) /* Got alpha */
5327 {
5328 memset(settings->img[CHN_ALPHA], 255, w * h);
5329 skip = 2;
5330 }
5331 }
5332 /* Row skip */
5333 for (ii = 0; ii < dy; ii++ , i--)
5334 {
5335 if ((skip > 1) && (j < w))
5336 memset(settings->img[CHN_ALPHA] + w * i + j,
5337 0, w - j);
5338 j = 0;
5339 ls_progress(settings, h - i - 1, 10);
5340 }
5341 /* Column skip */
5342 if (skip > 1) memset(settings->img[CHN_ALPHA] +
5343 w * i + j, 0, dx - j);
5344 j = dx;
5345 /* No more rows left */
5346 if (i < 0)
5347 {
5348 res = 1;
5349 break;
5350 }
5351 dest = settings->img[CHN_IMAGE] + w * i * wbpp;
5352 tmp += 2 + tmp[1];
5353 }
5354 }
5355
5356 /* Delete all-zero "alpha" */
5357 if (def_alpha) delete_alpha(settings, 0);
5358
5359 fail3: if (!settings->silent) progress_end();
5360 fail2: free(buf);
5361 fail: if (fp) fclose(fp);
5362 return (res);
5363 }
5364
5365 /* Use BMP4 instead of BMP3 for images with alpha */
5366 /* #define USE_BMP4 */ /* Most programs just use 32-bit RGB BMP3 for RGBA */
5367
save_bmp(char * file_name,ls_settings * settings,memFILE * mf)5368 static int save_bmp(char *file_name, ls_settings *settings, memFILE *mf)
5369 {
5370 unsigned char *buf, *tmp;
5371 memFILE fake_mf;
5372 FILE *fp = NULL;
5373 int i, j, ll, hsz0, hsz, dsz, fsz;
5374 int w = settings->width, h = settings->height, bpp = settings->bpp;
5375
5376 i = w > BMP_MAXHSIZE / 4 ? w * 4 : BMP_MAXHSIZE;
5377 buf = malloc(i);
5378 if (!buf) return (-1);
5379 memset(buf, 0, i);
5380
5381 if (!mf)
5382 {
5383 if (!(fp = fopen(file_name, "wb")))
5384 {
5385 free(buf);
5386 return (-1);
5387 }
5388 memset(mf = &fake_mf, 0, sizeof(fake_mf));
5389 fake_mf.file = fp;
5390 }
5391
5392 /* Sizes of BMP parts */
5393 if (((settings->mode == FS_CLIPBOARD) || (bpp == 3)) &&
5394 settings->img[CHN_ALPHA]) bpp = 4;
5395 ll = (bpp * w + 3) & ~3;
5396 j = bpp == 1 ? settings->colors : 0;
5397
5398 #ifdef USE_BMP4
5399 hsz0 = bpp == 4 ? BMP4_HSIZE : BMP3_HSIZE;
5400 #else
5401 hsz0 = BMP3_HSIZE;
5402 #endif
5403 hsz = hsz0 + j * 4;
5404 dsz = ll * h;
5405 fsz = hsz + dsz;
5406
5407 /* Prepare header */
5408 buf[0] = 'B'; buf[1] = 'M';
5409 PUT32(buf + BMP_FILESIZE, fsz);
5410 PUT32(buf + BMP_DATAOFS, hsz);
5411 i = hsz0 - BMP_HDR2SIZE;
5412 PUT32(buf + BMP_HDR2SIZE, i);
5413 PUT32(buf + BMP_WIDTH, w);
5414 PUT32(buf + BMP_HEIGHT, h);
5415 PUT16(buf + BMP_PLANES, 1);
5416 PUT16(buf + BMP_BPP, bpp * 8);
5417 #ifdef USE_BMP4
5418 i = bpp == 4 ? 3 : 0; /* Bitfield "compression" / no compression */
5419 PUT32(buf + BMP_COMPRESS, i);
5420 #else
5421 PUT32(buf + BMP_COMPRESS, 0); /* No compression */
5422 #endif
5423 PUT32(buf + BMP_DATASIZE, dsz);
5424 PUT32(buf + BMP_COLORS, j);
5425 PUT32(buf + BMP_ICOLORS, j);
5426 #ifdef USE_BMP4
5427 if (bpp == 4)
5428 {
5429 memset(buf + BMP_RMASK, 0, BMP4_HSIZE - BMP_RMASK);
5430 buf[BMP_RMASK + 2] = buf[BMP_GMASK + 1] = buf[BMP_BMASK + 0] =
5431 buf[BMP_AMASK + 3] = 0xFF; /* Masks for 8-bit BGRA */
5432 buf[BMP_CSPACE] = 1; /* Device-dependent RGB */
5433 }
5434 #endif
5435 tmp = buf + hsz0;
5436 for (i = 0; i < j; i++ , tmp += 4)
5437 {
5438 tmp[0] = settings->pal[i].blue;
5439 tmp[1] = settings->pal[i].green;
5440 tmp[2] = settings->pal[i].red;
5441 }
5442 mfwrite(buf, 1, tmp - buf, mf);
5443
5444 /* Write rows */
5445 if (!settings->silent) ls_init("BMP", 1);
5446 memset(buf + ll - 4, 0, 4);
5447 for (i = h - 1; i >= 0; i--)
5448 {
5449 prepare_row(buf, settings, bpp, i);
5450 mfwrite(buf, 1, ll, mf);
5451 ls_progress(settings, h - i, 20);
5452 }
5453 if (fp) fclose(fp);
5454
5455 if (!settings->silent) progress_end();
5456
5457 free(buf);
5458 return 0;
5459 }
5460
5461 /* Partial ctype implementation for C locale;
5462 * space 1, digit 2, alpha 4, punctuation 8 */
5463 static unsigned char ctypes[256] = {
5464 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
5465 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5466 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
5467 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8,
5468 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5469 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 4,
5470 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5471 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 0,
5472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5473 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5475 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5477 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5478 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
5480 #define ISSPACE(x) (ctypes[(unsigned char)(x)] & 1)
5481 #define ISALPHA(x) (ctypes[(unsigned char)(x)] & 4)
5482 #define ISALNUM(x) (ctypes[(unsigned char)(x)] & 6)
5483 #define ISCNTRL(x) (!ctypes[(unsigned char)(x)])
5484 #define WHITESPACE "\t\n\v\f\r "
5485
5486 typedef struct {
5487 FILE *fp;
5488 char *buf, *ptr;
5489 int size, str, nl;
5490 } cctx;
5491
fsetC(cctx * ctx,FILE * fp,char * buf,int len)5492 static void fsetC(cctx *ctx, FILE *fp, char *buf, int len)
5493 {
5494 if (fp) /* Full init */
5495 {
5496 ctx->fp = fp;
5497 ctx->buf = ctx->ptr = buf;
5498 ctx->buf[0] = '\0';
5499 ctx->size = len;
5500 ctx->str = 0;
5501 ctx->nl = 1; // Not middle of line
5502 }
5503 else /* Switch buffers to a LARGER one */
5504 {
5505 int l = strlen(ctx->ptr);
5506 memmove(buf, ctx->ptr, l);
5507 buf[l] = '\0';
5508 ctx->buf = ctx->ptr = buf;
5509 ctx->size = len;
5510 }
5511 }
5512
5513 /* Reads text and cuts out C-style comments */
fgetsC(cctx * ctx)5514 static char *fgetsC(cctx *ctx)
5515 {
5516 char *buf = ctx->buf;
5517 int i, l = 0, has_chars = 0, in_comment = 0, in_string = ctx->str;
5518
5519 /* Keep unparsed tail if the line isn't yet terminated */
5520 if (!ctx->nl && ((l = strlen(ctx->ptr))))
5521 {
5522 memmove(buf, ctx->ptr, l);
5523 for (i = 0; i < l; i++) if (!ISSPACE(buf[i])) has_chars++;
5524 }
5525 ctx->ptr = buf;
5526 buf[l] = '\0';
5527
5528 while (TRUE)
5529 {
5530 /* Read a line */
5531 if (!fgets(buf + l, ctx->size - l, ctx->fp)) return (NULL);
5532
5533 /* Scan it for comments */
5534 i = l;
5535 l += strlen(buf + l);
5536 ctx->nl = l && (buf[l - 1] == '\n'); // Remember line termination
5537 for (; i < l; i++)
5538 {
5539 if (in_string)
5540 {
5541 /* Ignore backslash before quote, as libXpm does */
5542 if (buf[i] == '"') in_string = 0; /* Close a string */
5543 continue;
5544 }
5545 if (in_comment)
5546 {
5547 if ((buf[i] == '/') && i && (buf[i - 1] == '*'))
5548 {
5549 /* Replace comment by a single space */
5550 buf[in_comment - 1] = ' ';
5551 memcpy(buf + in_comment, buf + i + 1, l - i);
5552 l = in_comment + l - i - 1;
5553 i = in_comment - 1;
5554 in_comment = 0;
5555 }
5556 continue;
5557 }
5558 if (!ISSPACE(buf[i])) has_chars++;
5559 if (buf[i] == '"')
5560 in_string = 1; /* Open a string */
5561 else if ((buf[i] == '*') && i && (buf[i - 1] == '/'))
5562 {
5563 /* Open a comment */
5564 in_comment = i;
5565 has_chars -= 2;
5566 }
5567 }
5568 /* Fail unterminated strings, forbid continuations for simplicity */
5569 if (in_string && ctx->nl) return (NULL);
5570
5571 /* Whitespace ending in unclosed comment - reduce it */
5572 if ((in_comment > 1) && !has_chars)
5573 {
5574 buf[0] = '/';
5575 buf[1] = '*';
5576 in_comment = 1;
5577 }
5578
5579 /* Fail overlong lines ending in unclosed comment */
5580 if (in_comment >= ctx->size - 3) return (NULL);
5581
5582 /* Continue reading till the comment closes */
5583 if (in_comment)
5584 {
5585 l = in_comment + 1;
5586 continue;
5587 }
5588
5589 /* All line is whitespace - continue reading */
5590 if (!has_chars)
5591 {
5592 l = !l || ctx->nl ? 0 : 1; // Remember 1 leading space
5593 continue;
5594 }
5595
5596 /* Remember if last string hasn't ended */
5597 ctx->str = in_string;
5598 return (buf);
5599 }
5600 }
5601
5602 /* Gets next C string out of buffer */
fstrC(cctx * ctx)5603 static char *fstrC(cctx *ctx)
5604 {
5605 char *s, *t, *w = ctx->ptr;
5606
5607 /* String has to begin somewhere */
5608 while (!(s = strchr(w, '"')))
5609 {
5610 *(ctx->ptr = ctx->buf) = '\0';
5611 if (!(w = fgetsC(ctx))) return (NULL);
5612 }
5613 /* And to end on the same line */
5614 t = strchr(s + 1, '"');
5615 if (!t)
5616 {
5617 ctx->ptr = s;
5618 if (!(s = fgetsC(ctx))) return (NULL);
5619 t = strchr(s + 1, '"');
5620 }
5621 if (!t) return (NULL); // Overlong string
5622 /* Cut off the remainder */
5623 if (*++t)
5624 {
5625 *t++ = '\0'; // Ignoring whatever it was
5626 while (ISSPACE(*t)) t++;
5627 }
5628 /* Remember the tail */
5629 ctx->ptr = t;
5630
5631 return (s);
5632 }
5633
5634 /* Gets next C line out of buffer */
flineC(cctx * ctx)5635 static char *flineC(cctx *ctx)
5636 {
5637 /* Skip to end of this line */
5638 while (!ctx->nl)
5639 {
5640 *(ctx->ptr = ctx->buf) = '\0';
5641 if (!fgetsC(ctx)) return (NULL);
5642 }
5643 /* And read the next */
5644 return (fgetsC(ctx));
5645 }
5646
5647 /* "One at a time" hash function */
hashf(guint32 seed,char * key,int len)5648 static guint32 hashf(guint32 seed, char *key, int len)
5649 {
5650 int i;
5651
5652 for (i = 0; i < len; i++)
5653 {
5654 seed += key[i];
5655 seed += seed << 10;
5656 seed ^= seed >> 6;
5657 }
5658 seed += seed << 3;
5659 seed ^= seed >> 11;
5660 seed += seed << 15;
5661 return (seed);
5662 }
5663
5664 #define HASHSEED 0x811C9DC5
5665 #define HASH_RND(X) ((X) * 0x10450405 + 1)
5666 #define HSIZE 16384
5667 #define HMASK 0x1FFF
5668 /* For cuckoo hashing of 4096 items into 16384 slots */
5669 #define MAXLOOP 39
5670
5671 /* This is the limit from libXPM */
5672 #define XPM_MAXCOL 4096
5673
5674 /* Cuckoo hash of IDs for load or RGB triples for save */
5675 typedef struct {
5676 short hash[HSIZE];
5677 char *keys;
5678 int step, cpp, cnt;
5679 guint32 seed;
5680 } str_hash;
5681
ch_find(str_hash * cuckoo,char * str)5682 static int ch_find(str_hash *cuckoo, char *str)
5683 {
5684 guint32 key;
5685 int k, idx, step = cuckoo->step, cpp = cuckoo->cpp;
5686
5687 key = hashf(cuckoo->seed, str, cpp);
5688 k = (key & HMASK) * 2;
5689 while (TRUE)
5690 {
5691 idx = cuckoo->hash[k];
5692 if (idx && !memcmp(cuckoo->keys + (idx - 1) * step, str, cpp))
5693 return (idx);
5694 if (k & 1) return (0); /* Not found */
5695 k = ((key >> 16) & HMASK) * 2 + 1;
5696 }
5697 }
5698
ch_insert(str_hash * cuckoo,char * str)5699 static int ch_insert(str_hash *cuckoo, char *str)
5700 {
5701 char *p, *keys;
5702 guint32 key;
5703 int i, j, k, n, idx, step, cpp;
5704
5705 n = ch_find(cuckoo, str);
5706 if (n) return (n - 1);
5707
5708 keys = cuckoo->keys;
5709 step = cuckoo->step; cpp = cuckoo->cpp;
5710 if (cuckoo->cnt >= XPM_MAXCOL) return (-1);
5711 p = keys + cuckoo->cnt++ * step;
5712 memcpy(p, str, cpp); p[cpp] = 0;
5713
5714 for (n = cuckoo->cnt; n <= cuckoo->cnt; n++)
5715 {
5716 idx = n;
5717 /* Normal cuckoo process */
5718 for (i = 0; i < MAXLOOP; i++)
5719 {
5720 key = hashf(cuckoo->seed, keys + (idx - 1) * step, cpp);
5721 key >>= (i & 1) << 4;
5722 j = (key & HMASK) * 2 + (i & 1);
5723 k = cuckoo->hash[j];
5724 cuckoo->hash[j] = idx;
5725 idx = k;
5726 if (!idx) break;
5727 }
5728 if (!idx) continue;
5729 /* Failed insertion - mutate seed */
5730 cuckoo->seed = HASH_RND(cuckoo->seed);
5731 memset(cuckoo->hash, 0, sizeof(short) * HSIZE);
5732 n = 1; /* Rehash everything */
5733 }
5734 return (cuckoo->cnt - 1);
5735 }
5736
5737 #define XPM_COL_DEFS 5
5738
5739 #define BUCKET_SIZE 8
5740
5741 /* Comments are allowed where valid */
load_xpm(char * file_name,ls_settings * settings)5742 static int load_xpm(char *file_name, ls_settings *settings)
5743 {
5744 static const char *cmodes[XPM_COL_DEFS] =
5745 { "c", "g", "g4", "m", "s" };
5746 unsigned char *cbuf, *src, *dest, pal[XPM_MAXCOL * 3], *dst0 = pal;
5747 guint32 *slots;
5748 char lbuf[4096], *buf = lbuf, *bh = NULL;
5749 char ckeys[XPM_MAXCOL * 32], *cdefs[XPM_COL_DEFS], *r, *r2, *t;
5750 str_hash cuckoo;
5751 cctx ctx;
5752 FILE *fp;
5753 int uninit_(n), uninit_(nx), uninit_(nslots);
5754 int w, h, cols, cpp, hx, hy, res = -1, bpp = 1, trans = -1;
5755 int i, j, k, l, lsz = sizeof(lbuf), step = 3, pr = FALSE;
5756
5757
5758 if (!(fp = fopen(file_name, "r"))) return (-1);
5759
5760 /* Read the header - accept XPM3 and nothing else */
5761 j = 0; fscanf(fp, " /* XPM */%n", &j);
5762 if (!j) goto fail;
5763 fsetC(&ctx, fp, lbuf, sizeof(lbuf)); /* Init reader */
5764
5765 /* Skip right to the first string like libXpm does */
5766 if (!(r = fstrC(&ctx))) goto fail;
5767
5768 /* Read the values section */
5769 i = sscanf(r + 1, "%d%d%d%d%d%d", &w, &h, &cols, &cpp, &hx, &hy);
5770 if (i == 4) hx = hy = -1;
5771 else if (i != 6) goto fail;
5772 /* Extension marker is ignored, as are extensions themselves */
5773
5774 /* More than 16M colors or no colors at all aren't accepted */
5775 if ((cols < 1) || (cols > 0x1000000)) goto fail;
5776 /* Stupid chars per pixel values aren't either */
5777 if ((cpp < 1) || (cpp > 31)) goto fail;
5778 /* More than 4096 colors accepted only if 4 cpp or less */
5779 if ((cols > XPM_MAXCOL) && (cpp > 4)) goto fail;
5780
5781 /* RGB image if more than 256 colors */
5782 if (cols > 256) bpp = 3;
5783
5784 /* Store values */
5785 settings->width = w;
5786 settings->height = h;
5787 settings->bpp = bpp;
5788 if (bpp == 1) settings->colors = cols;
5789 settings->hot_x = hx;
5790 settings->hot_y = hy;
5791 settings->xpm_trans = -1;
5792
5793 /* Allocate things early, to avoid reading huge color table and THEN
5794 * failing for bad dimensions of / lack of memory for the image itself */
5795 if ((settings->mode != FS_PALETTE_LOAD) && (settings->mode != FS_PALETTE_DEF))
5796 {
5797 if ((res = allocate_image(settings, CMASK_IMAGE))) goto fail;
5798 /* Allocate row buffer */
5799 i = w * cpp + 4 + 1024;
5800 if (i > lsz) buf = malloc(lsz = i);
5801 res = FILE_MEM_ERROR;
5802 if (!buf) goto fail;
5803 fsetC(&ctx, NULL, buf, lsz); /* Switch buffers */
5804
5805 /* Init bucketed hash */
5806 if (cols > XPM_MAXCOL)
5807 {
5808 nslots = (cols + BUCKET_SIZE - 1) / BUCKET_SIZE;
5809 bh = multialloc(MA_ALIGN_DEFAULT,
5810 &slots, (nslots + 1) * sizeof(*slots),
5811 &cbuf, cols * (4 + 3), NULL);
5812 if (!bh) goto fail2;
5813
5814 dst0 = cbuf + 4;
5815 step = 4 + 3;
5816 }
5817
5818 if ((pr = !settings->silent))
5819 {
5820 ls_init("XPM", 0);
5821 progress_update(0.0);
5822 /* A color seems to cost like about 2 pixels to load */
5823 n = (cols * 2) / w;
5824 nx = n + h;
5825 }
5826 }
5827 /* Too many colors do not a palette make */
5828 else if (bpp > 1) goto fail;
5829
5830 /* Init cuckoo hash */
5831 if (!bh)
5832 {
5833 memset(&cuckoo, 0, sizeof(cuckoo));
5834 cuckoo.keys = ckeys;
5835 cuckoo.step = 32;
5836 cuckoo.cpp = cpp;
5837 cuckoo.seed = HASHSEED;
5838 }
5839
5840 /* Read colormap */
5841 res = -1;
5842 for (i = 0 , dest = dst0; i < cols; i++ , dest += step)
5843 {
5844 if (!(r = fstrC(&ctx))) goto fail3;
5845 l = strlen(r);
5846 if (l < cpp + 4) goto fail3;
5847 r[l - 1] = '\0'; // Cut off closing quote
5848
5849 /* Insert color into hash */
5850 if (bh) strncpy(dest - 4, r + 1, 4);
5851 else ch_insert(&cuckoo, r + 1);
5852
5853 /* Parse color definitions */
5854 memset(cdefs, 0, sizeof(cdefs));
5855 r += cpp + 2;
5856 k = -1; r2 = NULL;
5857 while (TRUE)
5858 {
5859 while (ISSPACE(*r)) r++;
5860 if (!*r) break;
5861 t = r++;
5862 while (*r && !ISSPACE(*r)) r++;
5863 if (*r) *r++ = '\0';
5864 if (k < 0) /* Mode */
5865 {
5866 for (j = 0; j < XPM_COL_DEFS; j++)
5867 {
5868 if (!strcmp(t, cmodes[j])) break;
5869 }
5870 if (j < XPM_COL_DEFS) /* Key */
5871 {
5872 k = j; r2 = NULL;
5873 continue;
5874 }
5875 }
5876 if (!r2) /* Color name */
5877 {
5878 if (k < 0) goto fail3;
5879 cdefs[k] = r2 = t;
5880 k = -1;
5881 }
5882 else /* Add next part of name */
5883 {
5884 l = strlen(r2);
5885 r2[l] = ' ';
5886 memmove(r2 + l + 1, t, strlen(t) + 1);
5887 }
5888 }
5889 if (!r2) goto fail3; /* Key w/o name */
5890
5891 /* Translate the best one */
5892 for (j = 0; j < XPM_COL_DEFS; j++)
5893 {
5894 int c;
5895
5896 if (!cdefs[j]) continue;
5897 if (!strcasecmp(cdefs[j], "none")) /* Transparent */
5898 {
5899 trans = i;
5900 break;
5901 }
5902 c = parse_color(cdefs[j]);
5903 if (c < 0) continue;
5904 dest[0] = INT_2_R(c);
5905 dest[1] = INT_2_G(c);
5906 dest[2] = INT_2_B(c);
5907 break;
5908 }
5909 /* Not one understandable color */
5910 if (j >= XPM_COL_DEFS) goto fail3;
5911 }
5912 /* With bucketed hashing, half the work per color is not done yet */
5913 if (pr) progress_update((float)(bh ? n / 2 : n) / nx);
5914
5915 /* Create palette */
5916 if (bpp == 1)
5917 {
5918 dest = dst0;
5919 for (i = 0; i < cols; i++ , dest += step)
5920 {
5921 settings->pal[i].red = dest[0];
5922 settings->pal[i].green = dest[1];
5923 settings->pal[i].blue = dest[2];
5924 }
5925 if (trans >= 0)
5926 {
5927 settings->xpm_trans = trans;
5928 settings->pal[trans].red = settings->pal[trans].green = 115;
5929 settings->pal[trans].blue = 0;
5930 }
5931 /* If palette is all we need */
5932 res = 1;
5933 if ((settings->mode == FS_PALETTE_LOAD) ||
5934 (settings->mode == FS_PALETTE_DEF)) goto fail3;
5935 }
5936
5937 /* Find an unused color for transparency */
5938 else if (trans >= 0)
5939 {
5940 unsigned char cmap[XPM_MAXCOL / 8], *cc = cmap;
5941 int l = XPM_MAXCOL;
5942
5943 if (bh) // Allocate color cube
5944 {
5945 l = 0x1000000;
5946 cc = malloc(l / 8);
5947 res = FILE_MEM_ERROR;
5948 if (!cc) goto fail3;
5949 }
5950 memset(cc, 0, l / 8);
5951
5952 for (i = 0 , dest = dst0; i < cols; i++ , dest += step)
5953 {
5954 if (i == trans) continue;
5955 j = MEM_2_INT(dest, 0);
5956 if (j < l) cc[j >> 3] |= 1 << (j & 7);
5957 }
5958 /* Unused color IS there, as buffer has bits per total colors;
5959 * if one is transparent, then a bit stays unset in there */
5960 dest = cc;
5961 while (*dest == 0xFF) dest++;
5962 j = (dest - cc) * 8;
5963 i = *dest;
5964 while (i & 1) j++ , i >>= 1;
5965
5966 if (bh) free(cc);
5967
5968 /* Store the result */
5969 settings->rgb_trans = j;
5970 dest = dst0 + trans * step;
5971 dest[0] = INT_2_R(j);
5972 dest[1] = INT_2_G(j);
5973 dest[2] = INT_2_B(j);
5974 }
5975
5976 if (bh) /* Sort the colors by their buckets */
5977 {
5978 unsigned char *w, *ww, tbuf[4 + 3];
5979 int ds, ins;
5980
5981 /* First, count how many goes where */
5982 for (i = 0 , dest = cbuf; i < cols; i++ , dest += 4 + 3)
5983 (slots + 1)[hashf(HASHSEED, dest, cpp) % nslots]++;
5984 /* Then, prepare buckets' offsets */
5985 for (i = 0; i < nslots; i++) slots[i + 1] += slots[i];
5986 /* Now, starting from first, move colors where they belong */
5987 for (i = 0; i < cols; )
5988 {
5989 /* Color */
5990 w = cbuf + i * (4 + 3);
5991 /* Its home */
5992 ds = hashf(HASHSEED, w, cpp) % nslots;
5993 /* Its insertion point */
5994 ins = --slots[ds + 1];
5995 /* Already in place */
5996 if (ins <= i)
5997 {
5998 slots[ds + 1] = ++i; // Adjust
5999 continue;
6000 }
6001 /* Move it */
6002 ww = cbuf + ins * (4 + 3);
6003 memcpy(tbuf, ww, 4 + 3);
6004 memcpy(ww, w, 4 + 3);
6005 memcpy(w, tbuf, 4 + 3);
6006 }
6007 if (pr) progress_update((float)n / nx);
6008 }
6009
6010 /* Now, read the image */
6011 res = FILE_LIB_ERROR;
6012 dest = settings->img[CHN_IMAGE];
6013 for (i = 0; i < h; i++)
6014 {
6015 if (!(r = fstrC(&ctx))) goto fail3;
6016 /* libXpm allows overlong strings */
6017 if (strlen(++r) < w * cpp + 1) goto fail3;
6018 for (j = 0; j < w; j++ , dest += bpp)
6019 {
6020 if (bh)
6021 {
6022 unsigned char *w;
6023 int ds, n;
6024
6025 ds = hashf(HASHSEED, r, cpp) % nslots;
6026 k = slots[ds];
6027 w = cbuf + k * (4 + 3);
6028 n = slots[ds + 1];
6029 for (; k < n; k++ , w += 4 + 3)
6030 /* Trying to avoid function call */
6031 if ((*w == *r) && !memcmp(w, r, cpp)) break;
6032 k = k >= n ? 0 : k + 1;
6033 }
6034 else k = ch_find(&cuckoo, r);
6035 if (!k) goto fail3;
6036 r += cpp;
6037 if (bpp == 1) *dest = k - 1;
6038 else
6039 {
6040 src = dst0 + (k - 1) * step;
6041 dest[0] = src[0];
6042 dest[1] = src[1];
6043 dest[2] = src[2];
6044 }
6045 }
6046 if (pr && ((n++ * 10) % nx >= nx - 10))
6047 progress_update((float)n / nx);
6048 }
6049 res = 1;
6050
6051 fail3: if (pr) progress_end();
6052 free(bh);
6053 fail2: if (buf != lbuf) free(buf);
6054 fail: fclose(fp);
6055 return (res);
6056 }
6057
6058 static const char base64[] =
6059 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
6060 "!#$%&'()*,-.:;<=>?@[]^_`{|}~",
6061 hex[] = "0123456789ABCDEF";
6062
6063 /* Extract valid C identifier from filename */
extract_ident(char * fname,int * len)6064 static char *extract_ident(char *fname, int *len)
6065 {
6066 char *tmp;
6067 int l;
6068
6069 tmp = strrchr(fname, DIR_SEP);
6070 tmp = tmp ? tmp + 1 : fname;
6071 for (; *tmp && !ISALPHA(*tmp); tmp++);
6072 for (l = 0; (l < 256) && ISALNUM(tmp[l]); l++);
6073 *len = l;
6074 return (tmp);
6075 }
6076
6077 #define CTABLE_SIZE (0x1000000 / 32)
6078 #define CINDEX_SIZE (0x1000000 / 256)
6079
6080 /* Find color index using bitmap with sparse counters */
ct_index(int rgb,guint32 * ctable)6081 static int ct_index(int rgb, guint32 *ctable)
6082 {
6083 guint32 bit = 1U << (rgb & 31), *cindex = ctable + CTABLE_SIZE;
6084 int n, d = rgb >> 5, m = d & 7;
6085
6086 if (!(ctable[d] & bit)) return (-1); // Not found
6087 n = cindex[d >> 3];
6088 while (m > 0) n += bitcount(ctable[d - m--]);
6089 return (n + bitcount(ctable[d] & (bit - 1)));
6090 }
6091
save_xpm(char * file_name,ls_settings * settings)6092 static int save_xpm(char *file_name, ls_settings *settings)
6093 {
6094 unsigned char rgbmem[XPM_MAXCOL * 4], *src;
6095 guint32 *cindex, *ctable = NULL;
6096 const char *ctb;
6097 char ws[5], tc[5] = " ";
6098 char *buf, *tmp;
6099 str_hash cuckoo;
6100 FILE *fp;
6101 int bpp = settings->bpp, w = settings->width, h = settings->height;
6102 int uninit_(ccmask);
6103 int i, j, k, l, c, cpp, cols, trans = -1;
6104
6105
6106 tmp = extract_ident(file_name, &l);
6107 if (!l) return -1;
6108
6109 /* Collect RGB colors */
6110 if (bpp == 3)
6111 {
6112 trans = settings->rgb_trans;
6113
6114 /* Init hash */
6115 memset(&cuckoo, 0, sizeof(cuckoo));
6116 cuckoo.keys = rgbmem;
6117 cuckoo.step = 4;
6118 cuckoo.cpp = 3;
6119 cuckoo.seed = HASHSEED;
6120
6121 j = w * h;
6122 src = settings->img[CHN_IMAGE];
6123 for (i = 0; i < j; i++ , src += 3)
6124 {
6125 if (ch_insert(&cuckoo, src) < 0)
6126 break; /* Too many colors for this mode */
6127 }
6128
6129 if (i < j) /* Too many colors, collect & count 'em */
6130 {
6131 ctable = calloc(CTABLE_SIZE + CINDEX_SIZE, sizeof(*ctable));
6132 if (!ctable) return (-1); // No memory
6133 src = settings->img[CHN_IMAGE];
6134 for (i = 0; i < j; i++ , src += 3)
6135 {
6136 int n = MEM_2_INT(src, 0);
6137 ctable[n >> 5] |= 1U << (n & 31);
6138 }
6139 cindex = ctable + CTABLE_SIZE;
6140 for (i = cols = 0; i < CTABLE_SIZE; i++)
6141 {
6142 if (!(i & 7)) cindex[i >> 3] = cols;
6143 cols += bitcount(ctable[i]);
6144 }
6145 /* RGB to index */
6146 if (trans > -1) trans = ct_index(trans, ctable);
6147 }
6148 else /* Sensible number of colors, cuckoo hashing works */
6149 {
6150 cols = cuckoo.cnt;
6151 /* RGB to index */
6152 if (trans > -1)
6153 {
6154 char trgb[3];
6155 trgb[0] = INT_2_R(trans);
6156 trgb[1] = INT_2_G(trans);
6157 trgb[2] = INT_2_B(trans);
6158 trans = ch_find(&cuckoo, trgb) - 1;
6159 }
6160 }
6161 }
6162
6163 /* Process indexed colors */
6164 else
6165 {
6166 cols = settings->colors;
6167 src = rgbmem;
6168 for (i = 0; i < cols; i++ , src += 4)
6169 {
6170 src[0] = settings->pal[i].red;
6171 src[1] = settings->pal[i].green;
6172 src[2] = settings->pal[i].blue;
6173 }
6174 trans = settings->xpm_trans;
6175 }
6176
6177 cpp = cols > 92 * 92 * 92 ? 4 : cols > 92 * 92 ? 3 : cols > 92 ? 2 : 1;
6178
6179 buf = malloc(w * cpp + 16); // Prepare row buffer
6180 if (!buf || !(fp = fopen(file_name, "w")))
6181 {
6182 free(buf);
6183 free(ctable);
6184 return -1;
6185 }
6186
6187 if (!settings->silent) ls_init("XPM", 1);
6188
6189 fprintf(fp, "/* XPM */\n" );
6190 fprintf(fp, "static char *%.*s_xpm[] = {\n", l, tmp);
6191
6192 if ((settings->hot_x >= 0) && (settings->hot_y >= 0))
6193 fprintf(fp, "\"%d %d %d %d %d %d\",\n", w, h, cols, cpp,
6194 settings->hot_x, settings->hot_y);
6195 else fprintf(fp, "\"%d %d %d %d\",\n", w, h, cols, cpp);
6196
6197 /* Create colortable */
6198 ctb = cols > 16 ? base64 : hex;
6199 tc[cpp] = '\0';
6200 if (ctable) // From bitmap
6201 {
6202 for (i = c = 0; i < CTABLE_SIZE; i++)
6203 {
6204 guint32 n = ctable[i];
6205 for (k = 0; n; k++ , n >>= 1)
6206 {
6207 if (!(n & 1)) continue;
6208 l = i * 32 + k; // Color
6209
6210 /* Color ID */
6211 ws[0] = ctb[c % 92];
6212 ws[1] = ctb[(c / 92) % 92];
6213 ws[2] = ctb[(c / (92 * 92)) % 92];
6214 ws[3] = ctb[c / (92 * 92 * 92)];
6215 ws[cpp] = '\0';
6216
6217 if (c == trans) // Transparency
6218 fprintf(fp, "\"%s\tc None\",\n", tc);
6219 else fprintf(fp, "\"%s\tc #%02X%02X%02X\",\n", ws,
6220 INT_2_R(l), INT_2_G(l), INT_2_B(l));
6221
6222 c++;
6223 }
6224 }
6225 }
6226 else // From cuckoo's keys
6227 {
6228 ccmask = 255 >> cpp; // 63 for 2 cpp, 127 for 1
6229 for (i = 0; i < cols; i++)
6230 {
6231 if (i == trans)
6232 {
6233 fprintf(fp, "\"%s\tc None\",\n", tc);
6234 continue;
6235 }
6236 ws[0] = ctb[i & ccmask];
6237 ws[1] = ctb[i >> 6];
6238 ws[cpp] = '\0';
6239 src = rgbmem + i * 4;
6240 fprintf(fp, "\"%s\tc #%02X%02X%02X\",\n", ws,
6241 src[0], src[1], src[2]);
6242 }
6243 }
6244
6245 w *= bpp;
6246 for (i = 0; i < h; i++)
6247 {
6248 src = settings->img[CHN_IMAGE] + i * w;
6249 tmp = buf;
6250 *tmp++ = '"';
6251 for (j = 0; j < w; j += bpp, tmp += cpp)
6252 {
6253 if (bpp == 1) k = src[j];
6254 else if (!ctable) k = ch_find(&cuckoo, src + j) - 1;
6255 else k = ct_index(MEM_2_INT(src, j), ctable);
6256 if (k == trans)
6257 tmp[0] = tmp[1] = tmp[2] = tmp[3] = ' ';
6258 else if (ctable)
6259 {
6260 tmp[0] = ctb[k % 92];
6261 tmp[1] = ctb[(k / 92) % 92];
6262 tmp[2] = ctb[(k / (92 * 92)) % 92];
6263 tmp[3] = ctb[k / (92 * 92 * 92)];
6264 }
6265 else // Backward compatible mapping
6266 {
6267 tmp[0] = ctb[k & ccmask];
6268 tmp[1] = ctb[k >> 6];
6269 }
6270 }
6271 strcpy(tmp, i < h - 1 ? "\",\n" : "\"\n};\n");
6272 fputs(buf, fp);
6273 ls_progress(settings, i, 10);
6274 }
6275 fclose(fp);
6276
6277 if (!settings->silent) progress_end();
6278
6279 free(buf);
6280 free(ctable);
6281 return 0;
6282 }
6283
load_xbm(char * file_name,ls_settings * settings)6284 static int load_xbm(char *file_name, ls_settings *settings)
6285 {
6286 static const char XPMtext[] = "0123456789ABCDEFabcdef,} \t\n",
6287 XPMval[] = {
6288 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
6289 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16 };
6290 unsigned char ctb[256], *dest;
6291 char lbuf[4096], *r;
6292 cctx ctx;
6293 FILE *fp;
6294 int w , h, hx = -1, hy = -1, bpn = 16, res = -1;
6295 int i, j, k, c, v = 0;
6296
6297
6298 if (!(fp = fopen(file_name, "r"))) return (-1);
6299
6300 /* Read & parse what serves as header to XBM */
6301 fsetC(&ctx, fp, lbuf, sizeof(lbuf)); /* Init reader */
6302 /* Width and height - required part in fixed order */
6303 if (!(r = flineC(&ctx))) goto fail;
6304 if (!sscanf(r, "#define %*s%n %d", &i, &w)) goto fail;
6305 if (strncmp(r + i - 5, "width", 5)) goto fail;
6306 if (!(r = flineC(&ctx))) goto fail;
6307 if (!sscanf(r, "#define %*s%n %d", &i, &h)) goto fail;
6308 if (strncmp(r + i - 6, "height", 6)) goto fail;
6309 /* Hotspot X and Y - optional part in fixed order */
6310 if (!(r = flineC(&ctx))) goto fail;
6311 if (sscanf(r, "#define %*s%n %d", &i, &hx))
6312 {
6313 if (strncmp(r + i - 5, "x_hot", 5)) goto fail;
6314 if (!(r = flineC(&ctx))) goto fail;
6315 if (!sscanf(r, "#define %*s%n %d", &i, &hy)) goto fail;
6316 if (strncmp(r + i - 5, "y_hot", 5)) goto fail;
6317 if (!(r = flineC(&ctx))) goto fail;
6318 }
6319 /* "Intro" string */
6320 j = 0; sscanf(r, " static short %*[^[]%n[] = {%n", &i, &j);
6321 if (!j)
6322 {
6323 bpn = 8; /* X11 format - 8-bit data */
6324 j = 0; sscanf(r, " static unsigned char %*[^[]%n[] = {%n", &i, &j);
6325 if (!j) sscanf(r, " static char %*[^[]%n[] = {%n", &i, &j);
6326 if (!j) goto fail;
6327 }
6328 if (strncmp(r + i - 4, "bits", 4)) goto fail;
6329 // !!! For now, newline is required between "intro" and data
6330
6331 /* Store values */
6332 settings->width = w;
6333 settings->height = h;
6334 settings->bpp = 1;
6335 settings->hot_x = hx;
6336 settings->hot_y = hy;
6337 /* Palette is white and black */
6338 set_bw(settings);
6339
6340 /* Allocate image */
6341 if ((res = allocate_image(settings, CMASK_IMAGE))) goto fail;
6342
6343 /* Prepare to read data */
6344 memset(ctb, 17, sizeof(ctb));
6345 for (i = 0; XPMtext[i]; i++)
6346 {
6347 ctb[(unsigned char)XPMtext[i]] = XPMval[i];
6348 }
6349
6350 /* Now, read the image */
6351 if (!settings->silent) ls_init("XBM", 0);
6352 res = FILE_LIB_ERROR;
6353 dest = settings->img[CHN_IMAGE];
6354 for (i = 0; i < h; i++)
6355 {
6356 for (j = k = 0; j < w; j++ , k--)
6357 {
6358 if (!k) /* Get next value, the way X itself does */
6359 {
6360 v = 0;
6361 while (TRUE)
6362 {
6363 if ((c = getc(fp)) == EOF) goto fail2;
6364 c = ctb[c & 255];
6365 if (c < 16) /* Accept hex digits */
6366 {
6367 v = (v << 4) + c;
6368 k++;
6369 }
6370 /* Silently ignore out-of-place chars */
6371 else if (c > 16) continue;
6372 /* Stop on delimiters after digits */
6373 else if (k) break;
6374 }
6375 k = bpn;
6376 }
6377 *dest++ = v & 1;
6378 v >>= 1;
6379 }
6380 ls_progress(settings, i, 10);
6381 }
6382 res = 1;
6383
6384 fail2: if (!settings->silent) progress_end();
6385 fail: fclose(fp);
6386 return (res);
6387 }
6388
6389 #define BPL 12 /* Bytes per line */
6390 #define CPB 6 /* Chars per byte */
save_xbm(char * file_name,ls_settings * settings)6391 static int save_xbm(char *file_name, ls_settings *settings)
6392 {
6393 unsigned char bw, *src;
6394 unsigned char row[MAX_WIDTH / 8];
6395 char buf[CPB * BPL + 16], *tmp;
6396 FILE *fp;
6397 int i, j, k, l, w = settings->width, h = settings->height;
6398
6399 if ((settings->bpp != 1) || (settings->colors > 2)) return WRONG_FORMAT;
6400
6401 /* Extract valid C identifier from name */
6402 tmp = extract_ident(file_name, &i);
6403 if (!i) return -1;
6404
6405 if (!(fp = fopen(file_name, "w"))) return -1;
6406
6407 fprintf(fp, "#define %.*s_width %i\n", i, tmp, w);
6408 fprintf(fp, "#define %.*s_height %i\n", i, tmp, h);
6409 if ((settings->hot_x >= 0) && (settings->hot_y >= 0))
6410 {
6411 fprintf(fp, "#define %.*s_x_hot %i\n", i, tmp, settings->hot_x);
6412 fprintf(fp, "#define %.*s_y_hot %i\n", i, tmp, settings->hot_y);
6413 }
6414 fprintf(fp, "static unsigned char %.*s_bits[] = {\n", i, tmp);
6415
6416 if (!settings->silent) ls_init("XBM", 1);
6417
6418 bw = get_bw(settings);
6419 j = k = (w + 7) >> 3; i = l = 0;
6420 while (TRUE)
6421 {
6422 if (j >= k)
6423 {
6424 if (i >= h) break;
6425 src = settings->img[CHN_IMAGE] + i * w;
6426 memset(row, 0, k);
6427 for (j = 0; j < w; j++)
6428 {
6429 if (src[j] == bw) row[j >> 3] |= 1 << (j & 7);
6430 }
6431 j = 0;
6432 ls_progress(settings, i, 10);
6433 i++;
6434 }
6435 for (; (l < BPL) && (j < k); l++ , j++)
6436 {
6437 tmp = buf + l * CPB;
6438 tmp[0] = ' '; tmp[1] = '0'; tmp[2] = 'x';
6439 tmp[3] = hex[row[j] >> 4]; tmp[4] = hex[row[j] & 0xF];
6440 tmp[5] = ',';
6441 }
6442 if ((l == BPL) && (j < k))
6443 {
6444 buf[BPL * CPB] = '\n'; buf[BPL * CPB + 1] = '\0';
6445 fputs(buf, fp);
6446 l = 0;
6447 }
6448 }
6449 strcpy(buf + l * CPB - 1, " };\n");
6450 fputs(buf, fp);
6451 fclose(fp);
6452
6453 if (!settings->silent) progress_end();
6454
6455 return 0;
6456 }
6457
6458 /*
6459 * Those who don't understand PCX are condemned to reinvent it, poorly. :-)
6460 */
6461
6462 #define LSS_WIDTH 4 /* 16b */
6463 #define LSS_HEIGHT 6 /* 16b */
6464 #define LSS_PALETTE 8 /* 16 * 3 * 8b */
6465 #define LSS_HSIZE 56
6466
load_lss(char * file_name,ls_settings * settings)6467 static int load_lss(char *file_name, ls_settings *settings)
6468 {
6469 unsigned char hdr[LSS_HSIZE], *dest, *tmp, *buf = NULL;
6470 FILE *fp;
6471 f_long l;
6472 int i, j, k, w, h, bl, idx, last, cnt, res = -1;
6473
6474
6475 if (!(fp = fopen(file_name, "rb"))) return (-1);
6476
6477 /* Read the header */
6478 k = fread(hdr, 1, LSS_HSIZE, fp);
6479
6480 /* Check general validity */
6481 if (k < LSS_HSIZE) goto fail; /* Least supported header size */
6482 if (strncmp(hdr, "\x3D\xF3\x13\x14", 4)) goto fail; /* Signature */
6483
6484 w = GET16(hdr + LSS_WIDTH);
6485 h = GET16(hdr + LSS_HEIGHT);
6486 settings->width = w;
6487 settings->height = h;
6488 settings->bpp = 1;
6489 settings->colors = 16;
6490
6491 /* Read palette */
6492 tmp = hdr + LSS_PALETTE;
6493 for (i = 0; i < 16; i++)
6494 {
6495 settings->pal[i].red = tmp[0] << 2 | tmp[0] >> 4;
6496 settings->pal[i].green = tmp[1] << 2 | tmp[1] >> 4;
6497 settings->pal[i].blue = tmp[2] << 2 | tmp[2] >> 4;
6498 tmp += 3;
6499 }
6500 /* If palette is all we need */
6501 res = 1;
6502 if ((settings->mode == FS_PALETTE_LOAD) ||
6503 (settings->mode == FS_PALETTE_DEF)) goto fail;
6504
6505 /* Load all image at once */
6506 fseek(fp, 0, SEEK_END);
6507 l = ftell(fp);
6508 if (l <= LSS_HSIZE) goto fail; /* Too large or too small */
6509 l -= LSS_HSIZE;
6510 fseek(fp, LSS_HSIZE, SEEK_SET);
6511 bl = (w * h * 3) >> 1; /* Cannot possibly be longer */
6512 if (bl > l) bl = l;
6513 buf = malloc(bl);
6514 res = FILE_MEM_ERROR;
6515 if (!buf) goto fail2;
6516 if ((res = allocate_image(settings, CMASK_IMAGE))) goto fail2;
6517
6518 if (!settings->silent) ls_init("LSS16", 0);
6519
6520 res = FILE_LIB_ERROR;
6521 j = fread(buf, 1, bl, fp);
6522 if (j < bl) goto fail3;
6523
6524 dest = settings->img[CHN_IMAGE];
6525 idx = 0; bl += bl;
6526 for (i = 0; i < h; i++)
6527 {
6528 last = 0; idx = (idx + 1) & ~1;
6529 for (j = 0; j < w; )
6530 {
6531 if (idx >= bl) goto fail3;
6532 k = (buf[idx >> 1] >> ((idx & 1) << 2)) & 0xF; ++idx;
6533 if (k != last)
6534 {
6535 dest[j++] = last = k;
6536 continue;
6537 }
6538 if (idx >= bl) goto fail3;
6539 cnt = (buf[idx >> 1] >> ((idx & 1) << 2)) & 0xF; ++idx;
6540 if (!cnt)
6541 {
6542 if (idx >= bl) goto fail3;
6543 cnt = (buf[idx >> 1] >> ((idx & 1) << 2)) & 0xF; ++idx;
6544 if (idx >= bl) goto fail3;
6545 k = (buf[idx >> 1] >> ((idx & 1) << 2)) & 0xF; ++idx;
6546 cnt = (k << 4) + cnt + 16;
6547 }
6548 if (cnt > w - j) cnt = w - j;
6549 memset(dest + j, last, cnt);
6550 j += cnt;
6551 }
6552 dest += w;
6553 }
6554 res = 1;
6555
6556 fail3: if (!settings->silent) progress_end();
6557 fail2: free(buf);
6558 fail: fclose(fp);
6559 return (res);
6560 }
6561
save_lss(char * file_name,ls_settings * settings)6562 static int save_lss(char *file_name, ls_settings *settings)
6563 {
6564 unsigned char *buf, *tmp, *src;
6565 FILE *fp;
6566 int i, j, uninit_(k), last, cnt, idx;
6567 int w = settings->width, h = settings->height;
6568
6569
6570 if ((settings->bpp != 1) || (settings->colors > 16)) return WRONG_FORMAT;
6571
6572 i = w > LSS_HSIZE ? w : LSS_HSIZE;
6573 buf = malloc(i);
6574 if (!buf) return -1;
6575 memset(buf, 0, i);
6576
6577 if (!(fp = fopen(file_name, "wb")))
6578 {
6579 free(buf);
6580 return -1;
6581 }
6582
6583 /* Prepare header */
6584 buf[0] = 0x3D; buf[1] = 0xF3; buf[2] = 0x13; buf[3] = 0x14;
6585 PUT16(buf + LSS_WIDTH, w);
6586 PUT16(buf + LSS_HEIGHT, h);
6587 j = settings->colors > 16 ? 16 : settings->colors;
6588 tmp = buf + LSS_PALETTE;
6589 for (i = 0; i < j; i++)
6590 {
6591 tmp[0] = settings->pal[i].red >> 2;
6592 tmp[1] = settings->pal[i].green >> 2;
6593 tmp[2] = settings->pal[i].blue >> 2;
6594 tmp += 3;
6595 }
6596 fwrite(buf, 1, LSS_HSIZE, fp);
6597
6598 /* Write rows */
6599 if (!settings->silent) ls_init("LSS16", 1);
6600 src = settings->img[CHN_IMAGE];
6601 for (i = 0; i < h; i++)
6602 {
6603 memset(buf, 0, w);
6604 last = cnt = idx = 0;
6605 for (j = 0; j < w; )
6606 {
6607 for (; j < w; j++)
6608 {
6609 k = *src++ & 0xF;
6610 if ((k != last) || (++cnt >= 255 + 16)) break;
6611 }
6612 if (cnt)
6613 {
6614 buf[idx >> 1] |= last << ((idx & 1) << 2); ++idx;
6615 if (cnt >= 16)
6616 {
6617 ++idx; /* Insert zero */
6618 cnt -= 16;
6619 buf[idx >> 1] |= (cnt & 0xF) <<
6620 ((idx & 1) << 2); ++idx;
6621 cnt >>= 4;
6622 }
6623 buf[idx >> 1] |= cnt << ((idx & 1) << 2); ++idx;
6624 }
6625 if (j++ >= w) break; /* Final repeat */
6626 cnt = 0;
6627 if (k == last) continue; /* Chain of repeats */
6628 buf[idx >> 1] |= k << ((idx & 1) << 2); ++idx;
6629 last = k;
6630 }
6631 idx = (idx + 1) & ~1;
6632 fwrite(buf, 1, idx >> 1, fp);
6633 ls_progress(settings, i, 10);
6634 }
6635 fclose(fp);
6636
6637 if (!settings->silent) progress_end();
6638
6639 free(buf);
6640 return 0;
6641 }
6642
6643 /* *** PREFACE ***
6644 * No other format has suffered so much at the hands of inept coders. With TGA,
6645 * exceptions are the rule, and files perfectly following the specification are
6646 * impossible to find. While I did my best to handle the format's perversions
6647 * that I'm aware of, there surely exist other kinds of weird TGAs that will
6648 * load wrong, or not at all. If you encounter one such, send a bugreport with
6649 * the file attached to it. */
6650
6651 /* TGA header */
6652 #define TGA_IDLEN 0 /* 8b */
6653 #define TGA_PALTYPE 1 /* 8b */
6654 #define TGA_IMGTYPE 2 /* 8b */
6655 #define TGA_PALSTART 3 /* 16b */
6656 #define TGA_PALCOUNT 5 /* 16b */
6657 #define TGA_PALBITS 7 /* 8b */
6658 #define TGA_X0 8 /* 16b */
6659 #define TGA_Y0 10 /* 16b */
6660 #define TGA_WIDTH 12 /* 16b */
6661 #define TGA_HEIGHT 14 /* 16b */
6662 #define TGA_BPP 16 /* 8b */
6663 #define TGA_DESC 17 /* 8b */
6664 #define TGA_HSIZE 18
6665
6666 /* Image descriptor bits */
6667 #define TGA_ALPHA 0x0F
6668 #define TGA_R2L 0x10
6669 #define TGA_T2B 0x20
6670 #define TGA_IL 0xC0 /* Interleave mode - obsoleted in TGA 2.0 */
6671
6672 /* TGA footer */
6673 #define TGA_EXTOFS 0 /* 32b */
6674 #define TGA_DEVOFS 4 /* 32b */
6675 #define TGA_SIGN 8
6676 #define TGA_FSIZE 26
6677
6678 /* TGA extension area */
6679 #define TGA_EXTLEN 0 /* 16b */
6680 #define TGA_SOFTID 426 /* 41 bytes */
6681 #define TGA_SOFTV 467 /* 16b */
6682 #define TGA_ATYPE 494 /* 8b */
6683 #define TGA_EXTSIZE 495
6684
extend_bytes(unsigned char * dest,int len,int maxval)6685 static void extend_bytes(unsigned char *dest, int len, int maxval)
6686 {
6687 unsigned char tb[256];
6688
6689 memset(tb, 255, 256);
6690 set_xlate_n(tb, maxval);
6691 do_xlate(tb, dest, len);
6692 }
6693
load_tga(char * file_name,ls_settings * settings)6694 static int load_tga(char *file_name, ls_settings *settings)
6695 {
6696 unsigned char hdr[TGA_HSIZE], ftr[TGA_FSIZE], ext[TGA_EXTSIZE];
6697 unsigned char pal[256 * 4], xlat5[32], xlat6[64], trans[256];
6698 unsigned char *buf = NULL, *dest, *dsta, *src = NULL, *srca = NULL;
6699 unsigned char *bstart, *bstop;
6700 FILE *fp;
6701 f_long fl;
6702 unsigned fofs;
6703 int i, k, w, h, bpp, ftype, ptype, ibpp, rbits, abits, itrans = FALSE;
6704 int rle, real_alpha = FALSE, assoc_alpha = FALSE, wmode = 0, res = -1;
6705 int iofs, buflen;
6706 int ix, ishift, imask, ax, ashift, amask;
6707 int start, xstep, xstepb, ystep, ccnt, rcnt, strl, y;
6708
6709
6710 if (!(fp = fopen(file_name, "rb"))) return (-1);
6711
6712 /* Read the header */
6713 k = fread(hdr, 1, TGA_HSIZE, fp);
6714 if (k < TGA_HSIZE) goto fail;
6715
6716 /* TGA has no signature as such - so check fields one by one */
6717 ftype = hdr[TGA_IMGTYPE];
6718 if (!(ftype & 3) || (ftype & 0xF4)) goto fail; /* Invalid type */
6719 /* Fail on interleave, because of lack of example files */
6720 if (hdr[TGA_DESC] & TGA_IL) goto fail;
6721 rle = ftype & 8;
6722
6723 iofs = TGA_HSIZE + hdr[TGA_IDLEN];
6724
6725 rbits = hdr[TGA_BPP];
6726 if (!rbits) goto fail; /* Zero bpp */
6727 abits = hdr[TGA_DESC] & TGA_ALPHA;
6728 if (abits > rbits) goto fail; /* Weird alpha */
6729 /* Workaround for a rather frequent bug */
6730 if (abits == rbits) abits = 0;
6731 ibpp = (rbits + 7) >> 3;
6732 rbits -= abits;
6733
6734 set_xlate(xlat5, 5);
6735 ptype = hdr[TGA_PALTYPE];
6736 switch (ftype & 3)
6737 {
6738 case 1: /* Paletted */
6739 {
6740 int pbpp, i, j, k, l;
6741 png_color *pptr;
6742
6743 if (ptype != 1) goto fail; /* Invalid palette */
6744 /* Don't want to bother with overlong palette without even
6745 * having one example where such a thing exists - WJ */
6746 if (rbits > 8) goto fail;
6747
6748 k = GET16(hdr + TGA_PALSTART);
6749 if (k >= 1 << rbits) goto fail; /* Weird palette start */
6750 j = GET16(hdr + TGA_PALCOUNT);
6751 if (!j || (k + j > 1 << rbits)) goto fail; /* Weird size */
6752 ptype = hdr[TGA_PALBITS];
6753 /* The options are quite limited here in practice */
6754 if (!ptype || (ptype > 32) || ((ptype & 7) && (ptype != 15)))
6755 goto fail;
6756 pbpp = (ptype + 7) >> 3;
6757 l = j * pbpp;
6758
6759 /* Read the palette */
6760 fseek(fp, iofs, SEEK_SET);
6761 if (fread(pal + k * pbpp, 1, l, fp) != l) goto fail;
6762 iofs += l;
6763
6764 /* Store the palette */
6765 settings->colors = j + k;
6766 memset(settings->pal, 0, 256 * 3);
6767 pptr = settings->pal + k;
6768 for (i = 0; i < l; i += pbpp , pptr++)
6769 {
6770 switch (pbpp)
6771 {
6772 case 1: /* 8-bit greyscale */
6773 pptr->red = pptr->green = pptr->blue = pal[i];
6774 break;
6775 case 2: /* 5:5:5 BGR */
6776 pptr->blue = xlat5[pal[i] & 0x1F];
6777 pptr->green = xlat5[(((pal[i + 1] << 8) +
6778 pal[i]) >> 5) & 0x1F];
6779 pptr->red = xlat5[(pal[i + 1] >> 2) & 0x1F];
6780 break;
6781 case 3: case 4: /* 8:8:8 BGR */
6782 pptr->blue = pal[i + 0];
6783 pptr->green = pal[i + 1];
6784 pptr->red = pal[i + 2];
6785 break;
6786 }
6787 }
6788 /* If palette is all we need */
6789 res = 1;
6790 if ((settings->mode == FS_PALETTE_LOAD) ||
6791 (settings->mode == FS_PALETTE_DEF)) goto fail;
6792
6793 /* Assemble transparency table */
6794 memset(trans, 255, 256);
6795 if (ptype == 15)
6796 {
6797 int i, n, tr;
6798
6799 for (i = n = 0; i < j; i++) n += pal[i + i + 1] & 0x80;
6800 /* Assume the less frequent value is transparent */
6801 tr = n >> 6 < j ? 0x80 : 0;
6802 for (i = 0; i < j; i++)
6803 {
6804 if ((pal[i + i + 1] & 0x80) == tr) trans[i + k] = 0;
6805 }
6806 }
6807 else if (ptype == 32)
6808 {
6809 for (i = 0; i < j; i++) trans[i + k] = pal[i * 4 + 3];
6810 }
6811 else break; /* Cannot have transparent color at all */
6812
6813 /* If all alphas are identical, ignore them */
6814 itrans = !is_filled(trans + k, trans[k], j);
6815 break;
6816 }
6817 case 2: /* RGB */
6818 /* Options are very limited - and bugs abound. Presence or
6819 * absence of attribute bits can't be relied upon. */
6820 switch (rbits)
6821 {
6822 case 16: /* 5:5:5 BGR or 5:6:5 BGR or 5:5:5:1 BGRA */
6823 if (abits) goto fail;
6824 if (tga_565)
6825 {
6826 set_xlate(xlat6, 6);
6827 wmode = 4;
6828 break;
6829 }
6830 rbits = 15;
6831 /* Fallthrough */
6832 case 15: /* 5:5:5 BGR or 5:5:5:1 BGRA */
6833 if (abits > 1) goto fail;
6834 abits = 1; /* Here it's unreliable to uselessness */
6835 wmode = 2;
6836 break;
6837 case 32: /* 8:8:8 BGR or 8:8:8:8 BGRA */
6838 if (abits) goto fail;
6839 rbits = 24; abits = 8;
6840 wmode = 6;
6841 break;
6842 case 24: /* 8:8:8 BGR or 8:8:8:8 BGRA */
6843 if (abits && (abits != 8)) goto fail;
6844 wmode = 6;
6845 break;
6846 default: goto fail;
6847 }
6848 break;
6849 case 3: /* Greyscale */
6850 /* Not enough examples - easier to handle all possibilities */
6851 /* Create palette */
6852 settings->colors = rbits > 8 ? 256 : 1 << rbits;
6853 mem_bw_pal(settings->pal, 0, settings->colors - 1);
6854 break;
6855 }
6856 /* Prepare for reading bitfields */
6857 i = abits > 8 ? abits - 8 : 0;
6858 abits -= i; i += rbits;
6859 ax = i >> 3;
6860 ashift = i & 7;
6861 amask = (1 << abits) - 1;
6862 i = rbits > 8 ? rbits - 8 : 0;
6863 rbits -= i;
6864 ix = i >> 3;
6865 ishift = i & 7;
6866 imask = (1 << rbits) - 1;
6867
6868 /* Now read the footer if one is available */
6869 fseek(fp, 0, SEEK_END);
6870 fl = ftell(fp);
6871 while (fl >= iofs + TGA_FSIZE)
6872 {
6873 fseek(fp, fl - TGA_FSIZE, SEEK_SET);
6874 k = fread(ftr, 1, TGA_FSIZE, fp);
6875 if (k < TGA_FSIZE) break;
6876 if (strcmp(ftr + TGA_SIGN, "TRUEVISION-XFILE.")) break;
6877 fofs = GET32(ftr + TGA_EXTOFS);
6878 if ((fofs > F_LONG_MAX - TGA_EXTSIZE - TGA_FSIZE) ||
6879 (fofs < iofs) || (fofs + TGA_EXTSIZE + TGA_FSIZE > fl))
6880 break; /* Invalid location */
6881 fseek(fp, fofs, SEEK_SET);
6882 k = fread(ext, 1, TGA_EXTSIZE, fp);
6883 if ((k < TGA_EXTSIZE) ||
6884 /* !!! 3D Studio writes 494 into this field */
6885 (GET16(ext + TGA_EXTLEN) < TGA_EXTSIZE - 1))
6886 break; /* Invalid size */
6887 if ((ftype & 3) != 1) /* Premultiplied alpha? */
6888 assoc_alpha = ext[TGA_ATYPE] == 4;
6889 /* Can believe alpha bits contain alpha if this field says so */
6890 real_alpha |= assoc_alpha | (ext[TGA_ATYPE] == 3);
6891 break;
6892 }
6893
6894 /* Allocate buffer and image */
6895 settings->width = w = GET16(hdr + TGA_WIDTH);
6896 settings->height = h = GET16(hdr + TGA_HEIGHT);
6897 settings->bpp = bpp = (ftype & 3) == 2 ? 3 : 1;
6898 buflen = ibpp * w;
6899 if (rle && (w < 129)) buflen = ibpp * 129;
6900 buf = malloc(buflen + 1); /* One extra byte for bitparser */
6901 res = FILE_MEM_ERROR;
6902 if (!buf) goto fail;
6903 if ((res = allocate_image(settings, abits ? CMASK_RGBA : CMASK_IMAGE)))
6904 goto fail2;
6905 /* Don't even try reading alpha if nowhere to store it */
6906 if (abits && settings->img[CHN_ALPHA]) wmode |= 1;
6907 res = -1;
6908
6909 if (!settings->silent) ls_init("TGA", 0);
6910
6911 fseek(fp, iofs, SEEK_SET); /* Seek to data */
6912 /* Prepare loops */
6913 start = 0; xstep = 1; ystep = 0;
6914 if (hdr[TGA_DESC] & TGA_R2L)
6915 {
6916 /* Right-to-left */
6917 start = w - 1;
6918 xstep = -1;
6919 ystep = 2 * w;
6920 }
6921 if (!(hdr[TGA_DESC] & TGA_T2B))
6922 {
6923 /* Bottom-to-top */
6924 start += (h - 1) * w;
6925 ystep -= 2 * w;
6926 }
6927 xstepb = xstep * bpp;
6928 res = FILE_LIB_ERROR;
6929
6930 dest = settings->img[CHN_IMAGE] + start * bpp;
6931 dsta = settings->img[CHN_ALPHA] + start;
6932 y = ccnt = rcnt = 0;
6933 bstart = bstop = buf + buflen;
6934 strl = w;
6935 while (TRUE)
6936 {
6937 int j;
6938
6939 j = bstop - bstart;
6940 if (j < ibpp)
6941 {
6942 if (bstop - buf < buflen) goto fail3; /* Truncated file */
6943 memcpy(buf, bstart, j);
6944 j += fread(buf + j, 1, buflen - j, fp);
6945 bstop = (bstart = buf) + j;
6946 if (!rle) /* Uncompressed */
6947 {
6948 if (j < buflen) goto fail3; /* Truncated file */
6949 rcnt = w; /* "Copy block" a row long */
6950 }
6951 }
6952 while (TRUE)
6953 {
6954 /* Read pixels */
6955 if (rcnt)
6956 {
6957 int l, n;
6958
6959 l = rcnt < strl ? rcnt : strl;
6960 if (j < ibpp * l) l = j / ibpp;
6961 rcnt -= l; strl -= l;
6962 while (l--)
6963 {
6964 switch (wmode)
6965 {
6966 case 1: /* Generic alpha */
6967 *dsta = (((bstart[ax + 1] << 8) +
6968 bstart[ax]) >> ashift) & amask;
6969 case 0: /* Generic single channel */
6970 *dest = (((bstart[ix + 1] << 8) +
6971 bstart[ix]) >> ishift) & imask;
6972 break;
6973 case 3: /* One-bit alpha for 16 bpp */
6974 *dsta = bstart[1] >> 7;
6975 case 2: /* 5:5:5 BGR */
6976 n = (bstart[1] << 8) + bstart[0];
6977 dest[0] = xlat5[(n >> 10) & 0x1F];
6978 dest[1] = xlat5[(n >> 5) & 0x1F];
6979 dest[2] = xlat5[n & 0x1F];
6980 break;
6981 case 5: /* Cannot happen */
6982 case 4: /* 5:6:5 BGR */
6983 n = (bstart[1] << 8) + bstart[0];
6984 dest[0] = xlat5[n >> 11];
6985 dest[1] = xlat6[(n >> 5) & 0x3F];
6986 dest[2] = xlat5[n & 0x1F];
6987 break;
6988 case 7: /* One-byte alpha for 32 bpp */
6989 *dsta = bstart[3];
6990 case 6: /* 8:8:8 BGR */
6991 dest[0] = bstart[2];
6992 dest[1] = bstart[1];
6993 dest[2] = bstart[0];
6994 break;
6995 }
6996 dest += xstepb;
6997 dsta += xstep;
6998 bstart += ibpp;
6999 }
7000 if (!strl || rcnt) break; /* Row end or buffer end */
7001 }
7002 /* Copy pixels */
7003 if (ccnt)
7004 {
7005 int i, l;
7006
7007 l = ccnt < strl ? ccnt : strl;
7008 ccnt -= l; strl -= l;
7009 for (i = 0; i < l; i++ , dest += xstepb)
7010 {
7011 dest[0] = src[0];
7012 if (bpp == 1) continue;
7013 dest[1] = src[1];
7014 dest[2] = src[2];
7015 }
7016 if (wmode & 1) memset(xstep < 0 ?
7017 dsta - l + 1 : dsta, *srca, l);
7018 dsta += xstep * l;
7019 if (!strl || ccnt) break; /* Row end or buffer end */
7020 }
7021 /* Read block header */
7022 j = bstop - bstart - 1;
7023 if (j < 0) break; /* Nothing in buffer */
7024 rcnt = *bstart++;
7025 if (rcnt > 0x7F) /* Repeat block - one read + some copies */
7026 {
7027 ccnt = rcnt & 0x7F;
7028 rcnt = 1;
7029 src = dest;
7030 srca = dsta;
7031 }
7032 else ++rcnt; /* Copy block - several reads */
7033 }
7034 if (strl) continue; /* It was buffer end */
7035 ls_progress(settings, y, 10);
7036 if (++y >= h) break; /* All done */
7037 dest += ystep * bpp;
7038 if (dsta) dsta += ystep;
7039 strl = w;
7040 }
7041
7042 /* Check if alpha channel is valid */
7043 if (!real_alpha && settings->img[CHN_ALPHA])
7044 delete_alpha(settings, settings->img[CHN_ALPHA][0]);
7045
7046 /* Check if alpha in 16-bpp BGRA is inverse */
7047 if (settings->img[CHN_ALPHA] && (wmode == 3) && !assoc_alpha)
7048 {
7049 unsigned char *timg, *talpha;
7050 int i, j = w * h, k = 0, l;
7051
7052 timg = settings->img[CHN_IMAGE];
7053 talpha = settings->img[CHN_ALPHA];
7054 for (i = 0; i < j; i++)
7055 {
7056 l = 5;
7057 if (!(timg[0] | timg[1] | timg[2])) l = 1;
7058 else if ((timg[0] & timg[1] & timg[2]) == 255) l = 4;
7059 k |= l << talpha[i];
7060 if (k == 0xF) break; /* Colors independent of alpha */
7061 timg += 3;
7062 }
7063 /* If 0-covered parts more colorful than 1-covered, invert alpha */
7064 if ((k & 5) > ((k >> 1) & 5))
7065 {
7066 for (i = 0; i < j; i++) talpha[i] ^= 1;
7067 }
7068 }
7069
7070 /* Rescale alpha */
7071 if (settings->img[CHN_ALPHA] && (abits < 8))
7072 extend_bytes(settings->img[CHN_ALPHA], w * h, (1 << abits) - 1);
7073
7074 /* Unassociate alpha */
7075 if (settings->img[CHN_ALPHA] && assoc_alpha && (abits > 1))
7076 {
7077 mem_demultiply(settings->img[CHN_IMAGE],
7078 settings->img[CHN_ALPHA], w * h, bpp);
7079 }
7080 res = 0;
7081
7082 /* Apply palette transparency */
7083 if (itrans) res = palette_trans(settings, trans);
7084
7085 if (!res) res = 1;
7086 fail3: if (!settings->silent) progress_end();
7087 fail2: free(buf);
7088 fail: fclose(fp);
7089 return (res);
7090 }
7091
save_tga(char * file_name,ls_settings * settings)7092 static int save_tga(char *file_name, ls_settings *settings)
7093 {
7094 unsigned char hdr[TGA_HSIZE], ftr[TGA_FSIZE], pal[256 * 4];
7095 unsigned char *buf, *src, *srca, *dest;
7096 FILE *fp;
7097 int i, j, y0, y1, vstep, pcn, pbpp = 3;
7098 int w = settings->width, h = settings->height, bpp = settings->bpp;
7099 int rle = settings->tga_RLE;
7100
7101 /* Indexed images not supposed to have alpha in TGA standard */
7102 if ((bpp == 3) && settings->img[CHN_ALPHA]) bpp = 4;
7103 i = w * bpp;
7104 if (rle) i += i + (w >> 7) + 3;
7105 buf = malloc(i);
7106 if (!buf) return -1;
7107
7108 if (!(fp = fopen(file_name, "wb")))
7109 {
7110 free(buf);
7111 return -1;
7112 }
7113
7114 /* Prepare header */
7115 memset(hdr, 0, TGA_HSIZE);
7116 switch (bpp)
7117 {
7118 case 1: /* Indexed */
7119 hdr[TGA_PALTYPE] = 1;
7120 hdr[TGA_IMGTYPE] = 1;
7121 PUT16(hdr + TGA_PALCOUNT, settings->colors);
7122 if ((settings->xpm_trans >= 0) &&
7123 (settings->xpm_trans < settings->colors)) pbpp = 4;
7124 hdr[TGA_PALBITS] = pbpp * 8;
7125 break;
7126 case 4: /* RGBA */
7127 hdr[TGA_DESC] = 8;
7128 case 3: /* RGB */
7129 hdr[TGA_IMGTYPE] = 2;
7130 break;
7131 }
7132 hdr[TGA_BPP] = bpp * 8;
7133 PUT16(hdr + TGA_WIDTH, w);
7134 PUT16(hdr + TGA_HEIGHT, h);
7135 if (rle) hdr[TGA_IMGTYPE] |= 8;
7136 if (!tga_defdir) hdr[TGA_DESC] |= TGA_T2B;
7137 fwrite(hdr, 1, TGA_HSIZE, fp);
7138
7139 /* Write palette */
7140 if (bpp == 1)
7141 {
7142 dest = pal;
7143 for (i = 0; i < settings->colors; i++ , dest += pbpp)
7144 {
7145 dest[0] = settings->pal[i].blue;
7146 dest[1] = settings->pal[i].green;
7147 dest[2] = settings->pal[i].red;
7148 if (pbpp > 3) dest[3] = 255;
7149 }
7150 /* Mark transparent color */
7151 if (pbpp > 3) pal[settings->xpm_trans * 4 + 3] = 0;
7152 fwrite(pal, 1, dest - pal, fp);
7153 }
7154
7155 /* Write rows */
7156 if (!settings->silent) ls_init("TGA", 1);
7157 if (tga_defdir)
7158 {
7159 y0 = h - 1; y1 = -1; vstep = -1;
7160 }
7161 else
7162 {
7163 y0 = 0; y1 = h; vstep = 1;
7164 }
7165 for (i = y0 , pcn = 0; i != y1; i += vstep , pcn++)
7166 {
7167 prepare_row(buf, settings, bpp, i); /* Fill uncompressed row */
7168 src = buf;
7169 dest = buf + w * bpp;
7170 if (rle) /* Compress */
7171 {
7172 unsigned char *tmp;
7173 int k, l;
7174
7175 for (j = 1; j <= w; j++)
7176 {
7177 tmp = srca = src;
7178 src += bpp;
7179 /* Scan row for repeats */
7180 for (; j < w; j++ , src += bpp)
7181 {
7182 switch (bpp)
7183 {
7184 case 4: if (src[3] != srca[3]) break;
7185 case 3: if (src[2] != srca[2]) break;
7186 case 2: if (src[1] != srca[1]) break;
7187 case 1: if (src[0] != srca[0]) break;
7188 default: continue;
7189 }
7190 /* Useful repeat? */
7191 if (src - srca > bpp + 2) break;
7192 srca = src;
7193 }
7194 /* Avoid too-short repeats at row ends */
7195 if (src - srca <= bpp + 2) srca = src;
7196 /* Create copy blocks */
7197 for (k = (srca - tmp) / bpp; k > 0; k -= 128)
7198 {
7199 l = k > 128 ? 128 : k;
7200 *dest++ = l - 1;
7201 memcpy(dest, tmp, l *= bpp);
7202 dest += l; tmp += l;
7203 }
7204 /* Create repeat blocks */
7205 for (k = (src - srca) / bpp; k > 0; k -= 128)
7206 {
7207 l = k > 128 ? 128 : k;
7208 *dest++ = l + 127;
7209 memcpy(dest, srca, bpp);
7210 dest += bpp;
7211 }
7212 }
7213 }
7214 fwrite(src, 1, dest - src, fp);
7215 ls_progress(settings, pcn, 20);
7216 }
7217
7218 /* Write footer */
7219 memcpy(ftr + TGA_SIGN, "TRUEVISION-XFILE.", TGA_FSIZE - TGA_SIGN);
7220 memset(ftr, 0, TGA_SIGN);
7221 fwrite(ftr, 1, TGA_FSIZE, fp);
7222
7223 fclose(fp);
7224
7225 if (!settings->silent) progress_end();
7226
7227 free(buf);
7228 return 0;
7229 }
7230
7231 /* PCX header */
7232 #define PCX_ID 0 /* 8b */
7233 #define PCX_VER 1 /* 8b */
7234 #define PCX_ENC 2 /* 8b */
7235 #define PCX_BPP 3 /* 8b */
7236 #define PCX_X0 4 /* 16b */
7237 #define PCX_Y0 6 /* 16b */
7238 #define PCX_X1 8 /* 16b */
7239 #define PCX_Y1 10 /* 16b */
7240 #define PCX_HDPI 12 /* 16b */
7241 #define PCX_VDPI 14 /* 16b */
7242 #define PCX_PAL 16 /* 8b*3*16 */
7243 #define PCX_NPLANES 65 /* 8b */
7244 #define PCX_LINELEN 66 /* 16b */
7245 #define PCX_PALTYPE 68 /* 16b */
7246 #define PCX_HRES 70 /* 16b */
7247 #define PCX_VRES 72 /* 16b */
7248 #define PCX_HSIZE 128
7249
7250 #define PCX_BUFSIZE 16384 /* Bytes read at a time */
7251
7252 /* Default EGA/VGA palette */
7253 static const png_color def_pal[16] = {
7254 {0x00, 0x00, 0x00}, {0x00, 0x00, 0xAA}, {0x00, 0xAA, 0x00}, {0x00, 0xAA, 0xAA},
7255 {0xAA, 0x00, 0x00}, {0xAA, 0x00, 0xAA}, {0xAA, 0x55, 0x00}, {0xAA, 0xAA, 0xAA},
7256 {0x55, 0x55, 0x55}, {0x55, 0x55, 0xFF}, {0x55, 0xFF, 0x55}, {0x55, 0xFF, 0xFF},
7257 {0xFF, 0x55, 0x55}, {0xFF, 0x55, 0xFF}, {0xFF, 0xFF, 0x55}, {0xFF, 0xFF, 0xFF},
7258 };
7259
load_pcx(char * file_name,ls_settings * settings)7260 static int load_pcx(char *file_name, ls_settings *settings)
7261 {
7262 static const unsigned char planarconfig[9] = {
7263 0x11, /* BW */ 0x12, /* 4c */ 0x21, /* 4c */ 0x31, /* 8c */
7264 0x41, /* 16c */ 0x14, /* 16c */ 0x18, /* 256c */
7265 0x38, /* RGB */ 0x48 /* RGBA */ };
7266 unsigned char hdr[PCX_HSIZE], pbuf[769];
7267 unsigned char *buf, *row, *dest, *tmp;
7268 FILE *fp;
7269 int ver, bits, planes, ftype;
7270 int y, ccnt, bstart, bstop, strl, plane, cf;
7271 int w, h, cols, buflen, bpp = 3, res = -1;
7272
7273
7274 if (!(fp = fopen(file_name, "rb"))) return (-1);
7275
7276 /* Read the header */
7277 if (fread(hdr, 1, PCX_HSIZE, fp) < PCX_HSIZE) goto fail;
7278
7279 /* PCX has no real signature - so check fields one by one */
7280 if ((hdr[PCX_ID] != 10) || (hdr[PCX_ENC] > 1)) goto fail;
7281 ver = hdr[PCX_VER];
7282 if (ver > 5) goto fail;
7283
7284 bits = hdr[PCX_BPP];
7285 planes = hdr[PCX_NPLANES];
7286 if ((bits == 24) && (planes == 1)) ftype = 7; /* Single-plane RGB */
7287 else if ((bits | planes) > 15) goto fail;
7288 else if ((tmp = memchr(planarconfig, (planes << 4) | bits, 9)))
7289 ftype = tmp - planarconfig;
7290 else goto fail;
7291
7292 /* Prepare palette */
7293 if (ftype < 7)
7294 {
7295 bpp = 1;
7296 settings->colors = cols = 1 << (bits * planes);
7297 /* BW (0 is black) */
7298 if (cols == 2)
7299 {
7300 settings->pal[0] = def_pal[0];
7301 settings->pal[1] = def_pal[15];
7302 }
7303 /* Default 256-color palette - assumed greyscale */
7304 else if ((ver == 3) && (cols == 256)) set_gray(settings);
7305 /* Default 16-color palette */
7306 else if ((ver == 3) && (cols == 16))
7307 memcpy(settings->pal, def_pal, sizeof(def_pal));
7308 /* !!! CGA palette is evil: what the PCX spec describes is the way it
7309 * was handled by PC Paintbrush 3.0, while 4.0 was using an entirely
7310 * different, undocumented encoding for palette selection.
7311 * The only seemingly sane way to differentiate the two is to look at
7312 * paletteinfo field: zeroed in 3.0, set in 4.0+ - WJ */
7313 else if (cols == 4)
7314 {
7315 /* Bits 2:1:0 in index: color burst:palette:intensity */
7316 static const unsigned char cga_pals[8 * 3] = {
7317 2, 4, 6, 10, 12, 14,
7318 3, 5, 7, 11, 13, 15,
7319 3, 4, 7, 11, 12, 15,
7320 3, 4, 7, 11, 12, 15 };
7321 int i, idx = hdr[PCX_PAL + 3] >> 5; // PB 3.0
7322
7323 if (GET16(hdr + PCX_PALTYPE)) // PB 4.0
7324 {
7325 /* Pick green palette if G>B in slot 1 */
7326 i = hdr[PCX_PAL + 5] >= hdr[PCX_PAL + 4];
7327 /* Pick bright palette if max(G,B) > 200 */
7328 idx = i * 2 + (hdr[PCX_PAL + 4 + i] > 200);
7329 }
7330
7331 settings->pal[0] = def_pal[hdr[PCX_PAL] >> 4];
7332 for (i = 1 , idx *= 3; i < 4; i++)
7333 settings->pal[i] = def_pal[cga_pals[idx++]];
7334 }
7335 /* VGA palette - read from file */
7336 else if (cols == 256)
7337 {
7338 if ((fseek(fp, -769, SEEK_END) < 0) ||
7339 (fread(pbuf, 1, 769, fp) < 769) ||
7340 (pbuf[0] != 0x0C)) goto fail;
7341 rgb2pal(settings->pal, pbuf + 1, 256);
7342 }
7343 /* 8 or 16 colors - read from header */
7344 else rgb2pal(settings->pal, hdr + PCX_PAL, cols);
7345
7346 /* If palette is all we need */
7347 res = 1;
7348 if ((settings->mode == FS_PALETTE_LOAD) ||
7349 (settings->mode == FS_PALETTE_DEF)) goto fail;
7350 }
7351
7352 /* Allocate buffer and image */
7353 settings->width = w = GET16(hdr + PCX_X1) - GET16(hdr + PCX_X0) + 1;
7354 settings->height = h = GET16(hdr + PCX_Y1) - GET16(hdr + PCX_Y0) + 1;
7355 settings->bpp = bpp;
7356 buflen = GET16(hdr + PCX_LINELEN);
7357 res = -1;
7358 if (buflen < ((w * bits + 7) >> 3)) goto fail;
7359 /* To accommodate bitparser's extra step */
7360 buf = malloc(PCX_BUFSIZE + buflen + 1);
7361 res = FILE_MEM_ERROR;
7362 if (!buf) goto fail;
7363 row = buf + PCX_BUFSIZE;
7364 if ((res = allocate_image(settings, ftype > 7 ? CMASK_RGBA : CMASK_IMAGE)))
7365 goto fail2;
7366
7367 /* Read and decode the file */
7368 if (!settings->silent) ls_init("PCX", 0);
7369 res = FILE_LIB_ERROR;
7370 fseek(fp, PCX_HSIZE, SEEK_SET);
7371 dest = settings->img[CHN_IMAGE];
7372 if (bits == 1) memset(dest, 0, w * h); // Write will be by OR
7373 y = plane = ccnt = 0;
7374 bstart = bstop = PCX_BUFSIZE;
7375 strl = buflen;
7376 cf = hdr[PCX_ENC] ? 0xC0 : 0x100; // Compressed, or not
7377 while (TRUE)
7378 {
7379 unsigned char v;
7380
7381 /* Keep the buffer filled */
7382 if (bstart >= bstop)
7383 {
7384 bstart -= bstop;
7385 bstop = fread(buf, 1, PCX_BUFSIZE, fp);
7386 if (bstop <= bstart) goto fail3; /* Truncated file */
7387 }
7388
7389 /* Decode data */
7390 v = buf[bstart];
7391 if (ccnt) /* Middle of a run */
7392 {
7393 int l = strl < ccnt ? strl : ccnt;
7394 memset(row + buflen - strl, v, l);
7395 strl -= l; ccnt -= l;
7396 }
7397 else if (v >= cf) /* Start of a run */
7398 {
7399 ccnt = v & 0x3F;
7400 bstart++;
7401 }
7402 else row[buflen - strl--] = v;
7403 bstart += !ccnt;
7404 if (strl) continue;
7405
7406 /* Store a line */
7407 if (bits == 1) // N planes of 1-bit data (MSB first)
7408 {
7409 unsigned char uninit_(v), *tmp = row;
7410 int i, n = 7 - plane;
7411
7412 for (i = 0; i < w; i++ , v += v)
7413 {
7414 if (!(i & 7)) v = *tmp++;
7415 dest[i] |= (v & 0x80) >> n;
7416 }
7417 }
7418 else if (bits == 24) // 1 plane of RGB
7419 memcpy(dest, row, w * 3);
7420 else if (plane < 3) // BPP planes of 2/4/8-bit data (MSB first)
7421 stream_MSB(row, dest + plane, w, bits, 0, bits, bpp);
7422 else if (settings->img[CHN_ALPHA]) // 8-bit alpha plane
7423 memcpy(settings->img[CHN_ALPHA] + y * w, row, w);
7424
7425 if (++plane >= planes)
7426 {
7427 ls_progress(settings, y, 10);
7428 if (++y >= h) break;
7429 dest += w * bpp;
7430 plane = 0;
7431 }
7432 strl = buflen;
7433 }
7434 res = 1;
7435
7436 fail3: if (!settings->silent) progress_end();
7437 fail2: free(buf);
7438 fail: fclose(fp);
7439 return (res);
7440 }
7441
save_pcx(char * file_name,ls_settings * settings)7442 static int save_pcx(char *file_name, ls_settings *settings)
7443 {
7444 unsigned char *buf, *src, *dest;
7445 FILE *fp;
7446 int w = settings->width, h = settings->height, bpp = settings->bpp;
7447 int i, l, plane, cnt;
7448
7449
7450 /* Allocate buffer */
7451 i = w * 2; // Buffer one plane, with worst-case RLE expansion factor 2
7452 if (i < PCX_HSIZE) i = PCX_HSIZE;
7453 if (i < 769) i = 769; // For palette
7454 buf = calloc(1, i); // Zeroing out is for header
7455 if (!buf) return (-1);
7456
7457 if (!(fp = fopen(file_name, "wb")))
7458 {
7459 free(buf);
7460 return (-1);
7461 }
7462
7463 /* Prepare header */
7464 memcpy(buf, "\x0A\x05\x01\x08", 4); // Version 5 PCX, 8 bits/plane
7465 PUT16(buf + PCX_X1, w - 1);
7466 PUT16(buf + PCX_Y1, h - 1);
7467 PUT16(buf + PCX_HDPI, 300); // GIMP sets DPI to this value
7468 PUT16(buf + PCX_VDPI, 300);
7469 buf[PCX_NPLANES] = bpp;
7470 PUT16(buf + PCX_LINELEN, w);
7471 buf[PCX_PALTYPE] = 1;
7472 fwrite(buf, 1, PCX_HSIZE, fp);
7473
7474 /* Compress & write pixel rows */
7475 if (!settings->silent) ls_init("PCX", 1);
7476 src = settings->img[CHN_IMAGE];
7477 for (i = 0; i < h; i++ , src += w * bpp)
7478 {
7479 for (plane = 0; plane < bpp; plane++)
7480 {
7481 unsigned char v, *tmp = src + plane;
7482
7483 dest = buf; cnt = 0; l = w;
7484 while (l > 0)
7485 {
7486 v = *tmp; tmp += bpp; cnt++;
7487 if ((--l <= 0) || (cnt == 0x3F) || (v != *tmp))
7488 {
7489 if ((cnt > 1) || (v >= 0xC0))
7490 *dest++ = cnt | 0xC0;
7491 *dest++ = v; cnt = 0;
7492 }
7493 }
7494 fwrite(buf, 1, dest - buf, fp);
7495 }
7496 ls_progress(settings, i, 20);
7497 }
7498
7499 /* Write palette */
7500 if (bpp == 1)
7501 {
7502 buf[0] = 0x0C;
7503 pal2rgb(buf + 1, settings->pal, settings->colors, 256);
7504 fwrite(buf, 1, 769, fp);
7505 }
7506
7507 fclose(fp);
7508
7509 if (!settings->silent) progress_end();
7510
7511 free(buf);
7512 return (0);
7513 }
7514
7515 /* *** PREFACE ***
7516 * LBM format has no one definitive documentation source, nor a good testsuite,
7517 * and while I found enough examples of some types, other ones I never observed
7518 * in the wild remain unsupported. If you encounter some such curiosity failing
7519 * to load or loading wrong, send a bugreport with the file attached to it. */
7520
7521 /* Macros for IFF tags; big-endian too */
7522 #define TAG4B_FORM TAG4B('F', 'O', 'R', 'M')
7523 #define TAG4B_ILBM TAG4B('I', 'L', 'B', 'M')
7524 #define TAG4B_PBM TAG4B('P', 'B', 'M', ' ')
7525 #define TAG4B_BMHD TAG4B('B', 'M', 'H', 'D')
7526 #define TAG4B_CMAP TAG4B('C', 'M', 'A', 'P')
7527 #define TAG4B_GRAB TAG4B('G', 'R', 'A', 'B')
7528 #define TAG4B_DEST TAG4B('D', 'E', 'S', 'T')
7529 #define TAG4B_CAMG TAG4B('C', 'A', 'M', 'G')
7530 #define TAG4B_BODY TAG4B('B', 'O', 'D', 'Y')
7531 /* Multipalette tags */
7532 #define TAG4B_SHAM TAG4B('S', 'H', 'A', 'M')
7533 #define TAG4B_CTBL TAG4B('C', 'T', 'B', 'L')
7534 #define TAG4B_PCHG TAG4B('P', 'C', 'H', 'G')
7535
7536 /* LBM header block (BMHD tag) */
7537 #define BMHD_W 0 /* 16b */
7538 #define BMHD_H 2 /* 16b */
7539 #define BMHD_X0 4 /* 16b */
7540 #define BMHD_Y0 6 /* 16b */
7541 #define BMHD_BPP 8 /* 8b */
7542 #define BMHD_MASK 9 /* 8b */
7543 #define BMHD_COMP 10 /* 8b */
7544 #define BMHD_PAD 11 /* 8b */
7545 #define BMHD_TRAN 12 /* 16b */
7546 #define BMHD_ASPX 14 /* 8b */
7547 #define BMHD_ASPY 15 /* 8b */
7548 #define BMHD_SCW 16 /* 16b */
7549 #define BMHD_SCH 18 /* 16b */
7550 #define BMHD_SIZE 20
7551
7552 /* LBM DEST block */
7553 #define DEST_DEPTH 0 /* 8b */
7554 #define DEST_PAD 1 /* 8b */
7555 #define DEST_PICK 2 /* 16b */
7556 #define DEST_ONOFF 4 /* 16b */
7557 #define DEST_MASK 6 /* 16b */
7558 #define DEST_SIZE 8
7559
7560 /* PCHG block header */
7561 #define PCHG_COMPR 0 /* 16b */
7562 #define PCHG_FLAGS 2 /* 16b */
7563 #define PCHG_START 4 /* 16b */
7564 #define PCHG_COUNT 6 /* 16b */
7565 #define PCHG_CHLIN 8 /* 16b */
7566 #define PCHG_MINR 10 /* 16b */
7567 #define PCHG_MAXR 12 /* 16b */
7568 #define PCHG_MAXCH 14 /* 16b */
7569 #define PCHG_TOTCH 16 /* 32b */
7570 #define PCHG_HSIZE 20
7571
7572 #define HAVE_BMHD 1
7573 #define HAVE_CMAP 2
7574 #define HAVE_GRAB 4
7575 #define HAVE_DEST 8
7576
load_lbm(char * file_name,ls_settings * settings)7577 static int load_lbm(char *file_name, ls_settings *settings)
7578 {
7579 static const unsigned char bitdepths[] =
7580 { 1, 2, 3, 4, 5, 6, 7, 8, 21, 24, 32 };
7581 unsigned char hdr[BMHD_SIZE], dbuf[DEST_SIZE], pchdr[PCHG_HSIZE];
7582 unsigned char pbuf[768], wbuf[256];
7583 unsigned char *buf, *row, *dest, *mpp, *pr = NULL;
7584 FILE *fp;
7585 int y, ccnt, bstart, bstop, strl, np, ap, mp;
7586 f_long ctbl = 0, pchg = 0;
7587 unsigned tag, tl;
7588 int pstart = 0, ctbll = 0, pchgl = 0, pcnt = 0, sh2 = 0;
7589 int w, h, bpp, bits, mask, tbits, buflen, plen, half = 0, ham = 0;
7590 int pbm, palsize = 0, blocks = 0, hx = 0, hy = 0, res = -1;
7591 int i, j, l, p, pad, want_pal;
7592
7593
7594 if (!(fp = fopen(file_name, "rb"))) return (-1);
7595
7596 /* Read the IFF header & check signature */
7597 if (fread(wbuf, 1, 12, fp) < 12) goto fail;
7598 if (GET32B(wbuf) != TAG4B_FORM) goto fail;
7599 tag = GET32B(wbuf + 8);
7600 if (!(pbm = tag == TAG4B_PBM) && !(tag == TAG4B_ILBM)) goto fail;
7601
7602 /* Read block headers & see what we get */
7603 want_pal = (settings->mode == FS_PALETTE_LOAD) ||
7604 (settings->mode == FS_PALETTE_DEF);
7605 while (fread(wbuf, 1, 8, fp) == 8)
7606 {
7607 tag = GET32B(wbuf);
7608 tl = GET32B(wbuf + 4);
7609 if (tl >= INT_MAX) break; // Sanity check
7610 pad = tl & 1;
7611 if (tag == TAG4B_BMHD)
7612 {
7613 if (tl != BMHD_SIZE) break;
7614 if (fread(hdr, 1, BMHD_SIZE, fp) != BMHD_SIZE) break;
7615 blocks |= HAVE_BMHD;
7616 continue;
7617 }
7618 else if (tag == TAG4B_CMAP)
7619 {
7620 /* Allow palette being too long */
7621 palsize = tl > 768 ? 768 : tl;
7622 if (fread(pbuf, 1, palsize, fp) != palsize) break;
7623 blocks |= HAVE_CMAP;
7624 tl -= palsize;
7625 /* If palette is all we need; hope there's only one */
7626 if (want_pal)
7627 {
7628 res = 1;
7629 break;
7630 }
7631 // Fallthrough
7632 }
7633 else if (tag == TAG4B_GRAB)
7634 {
7635 if ((tl != 4) || (fread(wbuf, 1, 4, fp) != 4)) break;
7636 blocks |= HAVE_GRAB;
7637 hx = GET16B(wbuf);
7638 hy = GET16B(wbuf + 2);
7639 continue;
7640 }
7641 else if (tag == TAG4B_DEST)
7642 {
7643 if (tl != DEST_SIZE) break;
7644 if (fread(dbuf, 1, DEST_SIZE, fp) != DEST_SIZE) break;
7645 blocks |= HAVE_DEST;
7646 continue;
7647 }
7648 else if (tag == TAG4B_CAMG)
7649 {
7650 if ((tl != 4) || (fread(wbuf, 1, 4, fp) != 4)) break;
7651 tag = GET32B(wbuf);
7652 half = tag & 0x80;
7653 ham = tag & 0x800;
7654 continue;
7655 }
7656 else if ((tag == TAG4B_SHAM) || (tag == TAG4B_CTBL))
7657 {
7658 ctbl = ftell(fp);
7659 ctbll = tl;
7660 // SHAM has "version" word at the beginning
7661 if (tag == TAG4B_SHAM)
7662 {
7663 if (tl < 2) break;
7664 ctbl += 2 , ctbll -= 2;
7665 }
7666 }
7667 else if (tag == TAG4B_PCHG)
7668 {
7669 if ((tl < PCHG_HSIZE) ||
7670 (fread(pchdr, 1, PCHG_HSIZE, fp) != PCHG_HSIZE)) break;
7671 pchg = ftell(fp);
7672 pchgl = tl -= PCHG_HSIZE;
7673 }
7674 else if (tag == TAG4B_BODY)
7675 {
7676 /* Palette & header must be before body */
7677 if (!want_pal && (blocks & HAVE_BMHD)) res = 0;
7678 break;
7679 }
7680 /* Default: skip (the rest of) tag data */
7681 tl += pad;
7682 if (tl && fseek(fp, tl, SEEK_CUR)) break;
7683 }
7684 if (res < 0) goto fail;
7685
7686 /* Parse bitplanes */
7687 tbits = !(blocks & HAVE_BMHD) ? 0 : // Palette may happen before header
7688 blocks & HAVE_DEST ? dbuf[DEST_DEPTH] : hdr[BMHD_BPP];
7689
7690 /* Prepare palette */
7691 if (blocks & HAVE_CMAP)
7692 {
7693 /* Corrective multipliers to counteract dumb shift */
7694 static const unsigned char mult[8] =
7695 { 128, 128, 130, 132, 136, 146, 170, 255 };
7696
7697 /* Limit palette to actual bitplanes */
7698 l = palsize / 3;
7699 if (tbits && (tbits < 9))
7700 {
7701 i = tbits;
7702 if (ham) i = i > 6 ? 6 : 4;
7703 else if (half && (i > 5)) i = 5;
7704 i = 1 << i;
7705 if (l > i) l = i;
7706 }
7707 /* Detect and correct palettes where 6..1-bit color was shifted
7708 * left by 2..7 without replicating high bits into low */
7709 l *= 3;
7710 for (i = 0 , j = 0x80; i < l; i++) j |= pbuf[i];
7711 for (i = 0; !(j & 1); i++) j >>= 1;
7712 for (j = mult[i] , i = 0; i < l; i++)
7713 pbuf[i] = (pbuf[i] * j) >> 7;
7714 /* Apply half-brite mode */
7715 if (half && (l <= 32 * 3))
7716 {
7717 memset(pbuf + l, 0, 32 * 3 - l);
7718 for (i = 0; i < l; i++)
7719 pbuf[i + 32 * 3] = pbuf[i] >> 1;
7720 l += 32 * 3;
7721 }
7722 /* Store the result */
7723 rgb2pal(settings->pal, pbuf, settings->colors = l / 3);
7724 }
7725 if (want_pal) goto fail;
7726
7727 /* Check sanity */
7728 res = -1;
7729 if (hdr[BMHD_COMP] > 1) goto fail; // Unknown compression type
7730 bits = hdr[BMHD_BPP];
7731 if (!memchr(bitdepths, bits, sizeof(bitdepths))) goto fail;
7732 if (ham)
7733 {
7734 if ((bits < 5) || (bits > 8)) goto fail;
7735 // No reason for grayscale HAM to exist
7736 if (!(blocks & HAVE_CMAP)) goto fail;
7737 ham = bits > 6 ? 6 : 4; // Shift value
7738 }
7739 if (ctbl)
7740 {
7741 h = GET16B(hdr + BMHD_H);
7742 sh2 = ctbll == (h >> 1) * 32;
7743 if (!sh2 && (ctbll != h * 32)) goto fail; // Size must match
7744 pchg = pchgl = 0; // If both present, simpler is better
7745 if (bits > (ham ? 6 : 4)) goto fail;
7746 }
7747 if (pchg)
7748 {
7749 /* No examples of anything but uncompressed 12-bit PCHG blocks,
7750 * so no reason to waste code supporting anything else */
7751 if (GET16B(pchdr + PCHG_COMPR)) goto fail;
7752 if (GET16B(pchdr + PCHG_FLAGS) != 1) goto fail;
7753 if (bits > (half || ham ? 6 : 5)) goto fail;
7754 pstart = GET16B(pchdr + PCHG_START);
7755 pcnt = GET16B(pchdr + PCHG_COUNT);
7756
7757 }
7758 mask = hdr[BMHD_MASK] == 1;
7759 if (pbm && (mask || ham || ctbl || pchg || (bits != 8)))
7760 goto fail; // Not compatible
7761
7762 /* DEST block if any */
7763 if (blocks & HAVE_DEST)
7764 {
7765 unsigned skip, setv, v;
7766
7767 /* For simplicity, as no one ever saw files w/DEST anyway */
7768 if ((tbits < bits) || (tbits > 8) || ham) goto fail;
7769 /* Make a lookup table for remapping bits after the fact;
7770 * ignore planeMask in hope it masks only planeOnOff */
7771 skip = ((1 << tbits) - 1) & ~GET16B(dbuf + DEST_PICK); // Skipmask
7772 setv = skip & GET16B(dbuf + DEST_ONOFF); // Setmask
7773 for (v = i = 0; !(i >> bits); i++)
7774 {
7775 wbuf[i] = v | setv;
7776 v = (v + skip + 1) & ~skip; // Increment across gaps
7777 }
7778 }
7779 /* 21-bit RGB */
7780 else if (bits == 21)
7781 {
7782 set_xlate(wbuf, 7);
7783 blocks |= HAVE_DEST; // !!! Let same xlate do either thing
7784 }
7785
7786 /* Make greyscale palette if needed */
7787 if ((tbits <= 8) && !(blocks & HAVE_CMAP))
7788 mem_bw_pal(settings->pal, 0, (settings->colors = 1 << tbits) - 1);
7789
7790 /* Transparent color - nearly always a glitch, rarely a real thing */
7791 if (!lbm_untrans && (hdr[BMHD_MASK] > 1))
7792 {
7793 j = GET16B(hdr + BMHD_TRAN);
7794 if (j < settings->colors) settings->xpm_trans = j;
7795 }
7796
7797 if (blocks & HAVE_GRAB) settings->hot_x = hx , settings->hot_y = hy;
7798
7799 /* Allocate buffer and image */
7800 settings->width = w = GET16B(hdr + BMHD_W);
7801 settings->height = h = GET16B(hdr + BMHD_H);
7802 plen = ctbll + pchgl;
7803 settings->bpp = bpp = ham || plen || (bits > 8) ? 3 : 1;
7804 buflen = pbm ? w + (w & 1) : ((w + 15) >> 4) * 2 * (bits + mask);
7805 buf = multialloc(MA_ALIGN_DEFAULT, &buf, PCX_BUFSIZE, &row, buflen,
7806 &mpp, plen, NULL);
7807 res = FILE_MEM_ERROR;
7808 if (!buf) goto fail;
7809 i = bits == 32 ? CMASK_RGBA : CMASK_IMAGE;
7810 if (mask) i |= CMASK_FOR(lbm_mask);
7811 if ((res = allocate_image(settings, i))) goto fail2;
7812 if (!pbm) // Prepare for writes by OR
7813 {
7814 memset(settings->img[CHN_IMAGE], 0, w * h * bpp);
7815 if (settings->img[CHN_ALPHA])
7816 memset(settings->img[CHN_ALPHA], 0, w * h);
7817 if ((i & ~CMASK_RGBA) && settings->img[lbm_mask])
7818 memset(settings->img[lbm_mask], 0, w * h);
7819 }
7820
7821 /* Load color change table if any */
7822 if (plen)
7823 {
7824 f_long b = ftell(fp);
7825 if (fseek(fp, ctbl + pchg, SEEK_SET) ||
7826 (fread(mpp, 1, plen, fp) != plen)) goto fail2;
7827 fseek(fp, b, SEEK_SET);
7828 if (!ham) ham = 8; // Use same decoding loop in mode 0
7829 pr = mpp + ((pcnt + 31) >> 5) * 4;
7830 }
7831
7832 /* Read and decode the file */
7833 if (!settings->silent) ls_init("LBM", 0);
7834 res = FILE_LIB_ERROR;
7835 ap = bits > 24 ? 24 : -1; // First alpha plane
7836 if (!settings->img[CHN_ALPHA]) ap = -1; // No alpha
7837 mp = bits; // Mask plane
7838 if (!mask || !lbm_mask || !settings->img[lbm_mask] ||
7839 ((lbm_mask == CHN_ALPHA) && (ap > 0))) mp = -1;
7840 np = mp > 0 ? bits + 1 : (ap > 0) || (bits < 24) ? bits : 24; // Planes to read
7841 y = ccnt = 0;
7842 if (!hdr[BMHD_COMP]) ccnt = buflen * h; // Uncompressed is file-sized copy run
7843 bstart = bstop = PCX_BUFSIZE;
7844 strl = buflen;
7845 while (TRUE)
7846 {
7847 /* Keep the buffer filled */
7848 if (bstart >= bstop)
7849 {
7850 bstart -= bstop;
7851 bstop = fread(buf, 1, PCX_BUFSIZE, fp);
7852 if (bstop <= bstart) goto fail3; /* Truncated file */
7853 }
7854
7855 /* Decode data */
7856 if (ccnt < 0) /* Middle of a repeat run */
7857 {
7858 int l = strl + ccnt < 0 ? strl : -ccnt;
7859 memset(row + buflen - strl, buf[bstart], l);
7860 strl -= l; bstart += !(ccnt += l);
7861 }
7862 else if (ccnt > 0) /* Middle of a copy run */
7863 {
7864 int l = strl < ccnt ? strl : ccnt;
7865 if (l > bstop - bstart) l = bstop - bstart;
7866 memcpy(row + buflen - strl, buf + bstart, l);
7867 strl -= l; ccnt -= l; bstart += l;
7868 }
7869 else /* Start of a run */
7870 {
7871 ccnt = buf[bstart];
7872 ccnt += ccnt < 128 ? 1 : -257;
7873 bstart++;
7874 }
7875 if (strl) continue;
7876
7877 /* Store a line */
7878 p = y * w;
7879 dest = settings->img[CHN_IMAGE] + p * bpp;
7880 if (pbm) memcpy(dest, row, w);
7881 while (!pbm)
7882 {
7883 unsigned char *dsta = NULL, *dstm = NULL;
7884 unsigned char uninit_(v), *tmp, *dp;
7885 int i, n, plane, step = bpp;
7886
7887 if (ap > 0) dsta = settings->img[CHN_ALPHA] + p;
7888 if (mp > 0) dstm = settings->img[lbm_mask] + p;
7889 for (plane = 0; plane < np; plane++)
7890 {
7891 tmp = row + ((w + 15) >> 4) * 2 * plane;
7892 if (bits == 21)
7893 dp = dest + plane % 3 , n = 1 + plane / 3;
7894 else dp = dest + (plane >> 3) , n = 7 - (plane & 7);
7895 if (plane == mp) dp = dstm , step = 1; // Mask
7896 else if (plane >= 24) dp = dsta , step = 1; // Alpha
7897 if (!dp) continue; // Skipping alpha till mask
7898 for (i = 0; i < w; i++ , v += v , dp += step)
7899 {
7900 if (!(i & 7)) v = *tmp++;
7901 *dp |= (v & 0x80) >> n;
7902 }
7903 }
7904
7905 if (!ham) break;
7906
7907 /* Multipalette, simpler kind */
7908 if (ctbl && !(y & sh2))
7909 {
7910 unsigned char *dest = pbuf;
7911 for (i = 0; i < 16; i++ , pr += 2 , dest += 3)
7912 {
7913 int v = GET16B(pr);
7914 dest[0] = ((v >> 8) & 0xF) * 0x11;
7915 dest[1] = ((v >> 4) & 0xF) * 0x11;
7916 dest[2] = (v & 0xF) * 0x11;
7917 }
7918 }
7919 /* Multipalette, complex kind */
7920 while (pchg && (y >= pstart) && (y < pstart + pcnt))
7921 {
7922 unsigned char *dest;
7923 int n, n16, v, i, j;
7924 i = y - pstart;
7925 j = (i >> 5) * 4;
7926 if (!((GET32B(mpp + j) >> (~i & 0x1F)) & 1))
7927 break; // Nothing to do for this line
7928 n16 = pr[1]; // Colors 16-31 for this many
7929 n = pr[0] + n16; // Total indices
7930 pr += 2;
7931 while (n-- > 0)
7932 {
7933 v = GET16B(pr);
7934 pr += 2;
7935 dest = pbuf + (n < n16) * 16 * 3 + (v >> 12) * 3;
7936 dest[0] = ((v >> 8) & 0xF) * 0x11;
7937 dest[1] = ((v >> 4) & 0xF) * 0x11;
7938 dest[2] = (v & 0xF) * 0x11;
7939 }
7940 if (half) for (i = 0; i < 32 * 3; i++)
7941 pbuf[i + 32 * 3] = pbuf[i] >> 1;
7942 break;
7943 }
7944
7945 /* Recode the row */
7946 /* !!! Start with palette color 0 as amigaos.net says and
7947 * GrafX2 does, not RGB 0 as ilbmtopnm does */
7948 tmp = pbuf;
7949 dp = dest;
7950 for (i = 0; i < w; i++ , dp += 3)
7951 {
7952 n = (v = *dp) >> ham;
7953 if (!n) tmp = pbuf + v * 3; // Palette color
7954 dp[0] = tmp[0];
7955 dp[1] = tmp[1];
7956 dp[2] = tmp[2];
7957 tmp = dp;
7958 if (!n) continue;
7959 v ^= n << ham;
7960 n ^= (n >> 1) ^ 3; // 0BRG -> RGB
7961 /* !!! In HAM8, preserve low 2 bits as Amiga docs
7962 * say and ilbmtopnm does; but in HAM6, put value
7963 * into lower & upper bits like GrafX2 and unlike
7964 * ilbmtopnm: those old Amigas did not HAVE any
7965 * color bits beyond the 4 */
7966 dp[n] = ham == 4 ? v + (v << 4) :
7967 (v << 2) + (dp[n] & 3);
7968 }
7969 break;
7970 }
7971 ls_progress(settings, y, 10);
7972 if (++y >= h) break;
7973 strl = buflen;
7974 }
7975 res = 1;
7976
7977 /* Finalize DEST or 21-bit */
7978 if (blocks & HAVE_DEST) do_xlate(wbuf, settings->img[CHN_IMAGE], w * h * bpp);
7979 /* Finalize mask */
7980 if (mp < 0); // No mask
7981 else if (is_filled(settings->img[lbm_mask], settings->img[lbm_mask][0], w * h))
7982 deallocate_image(settings, CMASK_FOR(lbm_mask)); // Useless mask
7983 else
7984 {
7985 memset(wbuf + 1, 255, 255); // Nonzero means fully opaque
7986 wbuf[0] = 0;
7987 do_xlate(wbuf, settings->img[lbm_mask], w * h);
7988 }
7989
7990 fail3: if (!settings->silent) progress_end();
7991 fail2: free(buf);
7992 fail: fclose(fp);
7993 return (res);
7994 }
7995
save_lbm(char * file_name,ls_settings * settings)7996 static int save_lbm(char *file_name, ls_settings *settings)
7997 {
7998 unsigned char *buf, *wb, *src, *dest;
7999 FILE *fp;
8000 f_long bstart, fend;
8001 unsigned l;
8002 int w = settings->width, h = settings->height, bpp = settings->bpp;
8003 int pbm = settings->lbm_pbm && (bpp == 1), comp = !!settings->lbm_pack;
8004 int i, j, np1, rl, plane, st, cnt, np = 0, mask = 0;
8005
8006 /* Count bitplanes */
8007 if (!pbm)
8008 {
8009 mask = settings->img[lbm_mask] ? lbm_mask : 0;
8010 if (bpp == 1) // Planes to hold indexed color
8011 {
8012 i = settings->colors - 1;
8013 if (i > 15) np = 4 , i >>= 4;
8014 if (i > 3) np += 2 , i >>= 2;
8015 if (i > 1) np++ , i >>= 1;
8016 np += i;
8017 }
8018 else np = settings->img[CHN_ALPHA] ? 32 : 24; // RGBA/RGB
8019 if ((np == 32) && (mask == CHN_ALPHA)) mask = 0; // No need
8020 }
8021
8022 /* Allocate buffer */
8023 rl = pbm ? w + (w & 1) : ((w + 15) >> 4) * 2; // One plane
8024 i = rl + (rl + 127) / 128; // Worst-case RLE expansion
8025 if (!pbm) i *= np + !!mask; // Buffer all planes
8026 i += comp * rl; // Uncompressed source
8027 if (i < 8 + 768) i = 8 + 768; // For CMAP & header
8028 buf = calloc(1, i); // Zeroing out is for header
8029 if (!buf) return (-1);
8030 wb = buf + comp * rl; // Compressed data go here
8031
8032 if (!(fp = fopen(file_name, "wb")))
8033 {
8034 free(buf);
8035 return (-1);
8036 }
8037
8038 /* Prepare header */
8039 memcpy(buf, "FORM\0\0\0\0", 8);
8040 memcpy(buf + 8, pbm ? "PBM " : "ILBM", 4);
8041 memcpy(buf + 12, "BMHD", 4);
8042 PUT32B(buf + 16, BMHD_SIZE);
8043 PUT16B(buf + 20 + BMHD_W, w);
8044 PUT16B(buf + 20 + BMHD_H, h);
8045 buf[20 + BMHD_BPP] = pbm ? 8 : np;
8046 buf[20 + BMHD_MASK] = mask ? 1 : 0;
8047 buf[20 + BMHD_COMP] = comp;
8048 if (!mask && (settings->xpm_trans >= 0))
8049 {
8050 buf[20 + BMHD_MASK] = 2;
8051 PUT16B(buf + 20 + BMHD_TRAN, settings->xpm_trans);
8052 }
8053 buf[20 + BMHD_ASPX] = buf[20 + BMHD_ASPY] = 1;
8054 /* Leave page size unset */
8055 // PUT16B(buf + 20 + BMHD_W, w);
8056 // PUT16B(buf + 20 + BMHD_H, h);
8057 fwrite(buf, 1, 20 + BMHD_SIZE, fp);
8058
8059 /* Palette (none for RGB/RGBA, to avoid confusing readers) */
8060 if (bpp == 1)
8061 {
8062 memcpy(buf, "CMAP", 4);
8063 i = settings->colors * 3;
8064 i += i & 1; // Align the size itself, as in every example observed
8065 PUT32B(buf + 4, i);
8066 pal2rgb(buf + 8, settings->pal, settings->colors, 256);
8067 fwrite(buf, 1, 8 + i, fp);
8068 }
8069
8070 /* Anchor point */
8071 if ((settings->hot_x >= 0) && (settings->hot_y >= 0))
8072 {
8073 memcpy(buf, "GRAB", 4);
8074 PUT32B(buf + 4, 4);
8075 PUT16B(buf + 8, settings->hot_x);
8076 PUT16B(buf + 10, settings->hot_y);
8077 fwrite(buf, 1, 8 + 4, fp);
8078 }
8079
8080 /* Compress & write pixel rows */
8081 if (!settings->silent) ls_init("LBM", 1);
8082 fwrite("BODY\0\0\0\0", 1, 8, fp);
8083 bstart = ftell(fp);
8084 np1 = np + (pbm || mask); // Total planes
8085 for (i = 0; i < h; i++)
8086 {
8087 src = settings->img[CHN_IMAGE] + w * bpp * i;
8088 dest = wb;
8089 for (plane = 0; plane < np1; plane++)
8090 {
8091 unsigned char v, *d, *s = src + (plane >> 3);
8092 int n = plane & 7, step = bpp;
8093
8094 d = comp ? buf : dest;
8095 if (pbm)
8096 {
8097 /* Copy indexed row */
8098 memcpy(d, src, w);
8099 d += w;
8100 }
8101 else
8102 {
8103 /* Extract a bitplane */
8104 if (plane >= 24) // Alpha
8105 s = settings->img[CHN_ALPHA] + w * i , step = 1;
8106 if (plane == np) // Mask - threshold at 128
8107 s = settings->img[mask] + w * i , step = 1 , n = 7;
8108 for (j = v = 0; j < w; j++ , s += step)
8109 {
8110 v |= ((*s >> n) & 1) << (~j & 7);
8111 if (~j & 7) continue;
8112 *d++ = v;
8113 v = 0;
8114 }
8115 if (w & 7) *d++ = v;
8116 }
8117 if ((d - buf) & 1) *d++ = 0; // Align
8118
8119 if (!comp)
8120 {
8121 dest = d;
8122 continue;
8123 }
8124
8125 /* Compress a bitplane */
8126 #define FILL 1
8127 #define EMIT 2
8128 #define STOP 4
8129 #define NFIL 8
8130 s = buf;
8131 st = cnt = 0;
8132 while (TRUE)
8133 {
8134 if (d - s <= 0) st |= EMIT + STOP;
8135 else if (cnt == 128) st |= EMIT;
8136 else if (st & FILL)
8137 {
8138 if (s[0] != *(s - 1)) st = EMIT + FILL;
8139 }
8140 else if ((d - s > 1) && (s[0] == s[1]))
8141 {
8142 /* Code pairs as repeats only when NOT following
8143 * a copy block; code triples as repeats always */
8144 if (!cnt || ((d - s > 2) && (s[0] == s[2])))
8145 st = EMIT + NFIL;
8146 }
8147 if (!(st & EMIT))
8148 {
8149 s++ , cnt++;
8150 continue;
8151 }
8152 if (st & FILL)
8153 {
8154 *dest++ = 257 - cnt;
8155 *dest++ = *(s - 1);
8156 }
8157 else if (cnt)
8158 {
8159 *dest++ = cnt - 1;
8160 memcpy(dest, s - cnt, cnt);
8161 dest += cnt;
8162 }
8163 if (st & STOP) break;
8164 if (st & NFIL)
8165 {
8166 s += cnt = 2;
8167 st = FILL;
8168 }
8169 else st = cnt = 0;
8170 }
8171 #undef FILL
8172 #undef EMIT
8173 #undef STOP
8174 #undef NFIL
8175 }
8176 fwrite(wb, 1, dest - wb, fp);
8177 ls_progress(settings, i, 20);
8178 }
8179
8180 /* Align last block & write sizes */
8181 fend = ftell(fp);
8182 l = fend - bstart;
8183 if (l & 1) fwrite("", 1, 1, fp); // Padding
8184 PUT32B(buf, l);
8185 fseek(fp, bstart - 4, SEEK_SET);
8186 fwrite(buf, 1, 4, fp);
8187 l = fend - 8;
8188 l += l & 1; // Aligned
8189 PUT32B(buf, l);
8190 fseek(fp, 4, SEEK_SET);
8191 fwrite(buf, 1, 4, fp);
8192 fclose(fp);
8193
8194 if (!settings->silent) progress_end();
8195
8196 free(buf);
8197 return (0);
8198 }
8199
8200 typedef void (*cvt_func)(unsigned char *dest, unsigned char *src, int len,
8201 int bpp, int step, int maxval);
8202
convert_16b(unsigned char * dest,unsigned char * src,int len,int bpp,int step,int maxval)8203 static void convert_16b(unsigned char *dest, unsigned char *src, int len,
8204 int bpp, int step, int maxval)
8205 {
8206 int i, v, m = maxval * 2;
8207
8208 if (!(step -= bpp)) bpp *= len , len = 1;
8209 step *= 2;
8210 while (len-- > 0)
8211 {
8212 i = bpp;
8213 while (i--)
8214 {
8215 v = (src[0] << 8) + src[1];
8216 src += 2;
8217 *dest++ = (v * (255 * 2) + maxval) / m;
8218 }
8219 src += step;
8220 }
8221 }
8222
copy_bytes(unsigned char * dest,unsigned char * src,int len,int bpp,int step)8223 static void copy_bytes(unsigned char *dest, unsigned char *src, int len,
8224 int bpp, int step)
8225 {
8226 int i, dd = 0;
8227
8228 if (!(step -= bpp)) bpp *= len , len = 1;
8229 else if (step < 0) bpp -= dd = -step , step = 0;
8230 while (len-- > 0)
8231 {
8232 i = bpp;
8233 while (i--) *dest++ = *src++;
8234 src += step; dest += dd;
8235 }
8236 }
8237
check_next_pnm(FILE * fp,char id)8238 static int check_next_pnm(FILE *fp, char id)
8239 {
8240 char buf[2];
8241
8242 if (fread(buf, 2, 1, fp))
8243 {
8244 fseek(fp, -2, SEEK_CUR);
8245 if ((buf[0] == 'P') && (buf[1] == id)) return (FILE_HAS_FRAMES);
8246 }
8247 return (1);
8248 }
8249
8250 /* Parse PAM header */
pam_behead(memFILE * mf,int whdm[4])8251 static char *pam_behead(memFILE *mf, int whdm[4])
8252 {
8253 char wbuf[2048];
8254 char *t1, *t2, *tail, *res = NULL;
8255 int i, n, l, flag = 0;
8256
8257 /* Read header, check for basic PAM */
8258 if (!mfgets(wbuf, sizeof(wbuf), mf) || strncmp(wbuf, "P7", 2))
8259 return (NULL);
8260 while (TRUE)
8261 {
8262 if (!mfgets(wbuf, sizeof(wbuf), mf)) break;
8263 if (!wbuf[0] || (wbuf[0] == '#')) continue; // Empty line or comment
8264 t1 = wbuf + strspn(wbuf, WHITESPACE);
8265 l = strcspn(t1, WHITESPACE);
8266 t2 = t1 + l + strspn(t1 + l, WHITESPACE);
8267 t1[l] = '\0';
8268 if (!strcmp(t1, "ENDHDR"))
8269 {
8270 if (flag < 0x0F) break; // Incomplete header
8271 return (res ? res : strdup("")); // TUPLTYPE is optional
8272 }
8273 if (!*t2) break; // There must be something but whitespace
8274 tail = t2 + strcspn(t2, WHITESPACE);
8275 if (!strcmp(t1, "TUPLTYPE"))
8276 {
8277 if (res) continue; // Only first value matters
8278 while (TRUE)
8279 {
8280 t1 = tail + strspn(tail, WHITESPACE);
8281 if (!*t1) break;
8282 tail = t1 + strcspn(t1, WHITESPACE);
8283 }
8284 // Preserve value for caller
8285 *tail = '\0';
8286 res = strdup(t2);
8287 continue;
8288 }
8289 // Other fields are numeric
8290 *tail = '\0';
8291 i = strtol(t2, &tail, 10);
8292 if (*tail) break;
8293 if (i < 1) break; // Must be at least 1
8294
8295 if (!strcmp(t1, "WIDTH")) n = 0;
8296 else if (!strcmp(t1, "HEIGHT")) n = 1;
8297 else if (!strcmp(t1, "DEPTH")) n = 2;
8298 else if (!strcmp(t1, "MAXVAL")) n = 3;
8299 else break; // Unknown IDs not allowed
8300
8301 whdm[n] = i;
8302 n = 1 << n;
8303 if (flag & n) break; // No duplicate entries
8304 flag |= n;
8305 }
8306 free(res);
8307 return (NULL);
8308 }
8309
8310 /* PAM loader does not support nonstandard types "GRAYSCALEFP" and "RGBFP",
8311 * because handling format variations which aren't found in the wild
8312 * is a waste of code - WJ */
8313
load_pam_frame(FILE * fp,ls_settings * settings)8314 static int load_pam_frame(FILE *fp, ls_settings *settings)
8315 {
8316 static const char *typenames[] = {
8317 "BLACKANDWHITE", "BLACKANDWHITE_ALPHA",
8318 "GRAYSCALE", "GRAYSCALE_ALPHA",
8319 "RGB", "RGB_ALPHA",
8320 "CMYK", "CMYK_ALPHA", NULL };
8321 static const char depths[] = { 1, 2, 1, 2, 3, 4, 4, 5 };
8322 memFILE fake_mf;
8323 cvt_func cvt_stream;
8324 char *t1;
8325 unsigned char *dest, *buf = NULL;
8326 int maxval, w, h, depth, ftype = -1;
8327 int i, j, ll, bpp, trans, vl, res, whdm[4];
8328
8329
8330 /* Read header */
8331 memset(&fake_mf, 0, sizeof(fake_mf));
8332 fake_mf.file = fp;
8333 if (!(t1 = pam_behead(&fake_mf, whdm))) return (-1);
8334 /* Compare TUPLTYPE to list of known ones */
8335 if (*t1) for (i = 0; typenames[i]; i++)
8336 {
8337 if (strcmp(t1, typenames[i])) continue;
8338 ftype = i;
8339 break;
8340 }
8341 free(t1); // No use anymore
8342 w = whdm[0]; h = whdm[1]; depth = whdm[2]; maxval = whdm[3];
8343 /* Interpret unknown content as RGB or grayscale */
8344 if (ftype < 0) ftype = depth >= 3 ? 4 : 2;
8345
8346 /* Validate */
8347 if ((depth < depths[ftype]) || (depth > 16) || (maxval > 65535))
8348 return (-1);
8349 bpp = ftype < 4 ? 1 : 3;
8350 trans = ftype & 1;
8351 vl = maxval < 256 ? 1 : 2;
8352 ll = w * depth * vl;
8353 /* !!! ImageMagick writes BLACKANDWHITE as GRAYSCALE */
8354 if ((ftype < 2) && (maxval > 1)) ftype += 2;
8355 if (ftype < 2) set_bw(settings); // BW
8356 else if (bpp == 1) set_gray(settings); // Grayscale
8357
8358 /* Allocate row buffer if cannot read directly into image */
8359 if (trans || (vl > 1) || (bpp != depth))
8360 {
8361 buf = malloc(ll);
8362 if (!buf) return (FILE_MEM_ERROR);
8363 }
8364
8365 /* Allocate image */
8366 settings->width = w;
8367 settings->height = h;
8368 settings->bpp = bpp;
8369 res = allocate_image(settings, trans ? CMASK_RGBA : CMASK_IMAGE);
8370 if (res) goto fail;
8371
8372 /* Read the image */
8373 if (!settings->silent) ls_init("PAM", 0);
8374 res = FILE_LIB_ERROR;
8375 cvt_stream = vl > 1 ? convert_16b : (cvt_func)copy_bytes;
8376 for (i = 0; i < h; i++)
8377 {
8378 dest = buf ? buf : settings->img[CHN_IMAGE] + ll * i;
8379 j = fread(dest, 1, ll, fp);
8380 if (j < ll) goto fail2;
8381 ls_progress(settings, i, 10);
8382
8383 if (!buf) continue; // Nothing else to do here
8384 if (settings->img[CHN_ALPHA]) // Have alpha - parse it
8385 {
8386 cvt_stream(settings->img[CHN_ALPHA] + w * i,
8387 buf + depths[ftype] * vl - vl, w, 1, depth, maxval);
8388 }
8389 dest = settings->img[CHN_IMAGE] + w * bpp * i;
8390 if (ftype >= 6) // CMYK
8391 {
8392 cvt_stream(buf, buf, w, 4, depth, maxval);
8393 if (maxval < 255) extend_bytes(buf, w * 4, maxval);
8394 cmyk2rgb(dest, buf, w, FALSE, settings);
8395 }
8396 else cvt_stream(dest, buf, w, bpp, depth, maxval);
8397 }
8398
8399 /* Check for next frame */
8400 res = check_next_pnm(fp, '7');
8401
8402 fail2: if (maxval < 255) // Extend what we've read
8403 {
8404 j = w * h;
8405 if (settings->img[CHN_ALPHA])
8406 extend_bytes(settings->img[CHN_ALPHA], j, maxval);
8407 j *= bpp;
8408 dest = settings->img[CHN_IMAGE];
8409 if (ftype >= 6); // CMYK is done already
8410 else if (ftype > 1) extend_bytes(dest, j, maxval);
8411 else // Convert BW from 1-is-white to 1-is-black
8412 {
8413 for (i = 0; i < j; i++ , dest++) *dest = !*dest;
8414 }
8415 }
8416 if (!settings->silent) progress_end();
8417
8418 fail: free(buf);
8419 return (res);
8420 }
8421
8422 #define PNM_BUFSIZE 4096
8423 typedef struct {
8424 FILE *f;
8425 int ptr, end, eof, comment;
8426 char buf[PNM_BUFSIZE + 2];
8427 } pnmbuf;
8428
8429 /* What PBM documentation says is NOT what Netpbm actually does; skipping a
8430 * comment in file header, it does not consume the newline after it - WJ */
pnm_skip_comment(pnmbuf * pnm)8431 static void pnm_skip_comment(pnmbuf *pnm)
8432 {
8433 pnm->comment = !pnm->buf[pnm->ptr += strcspn(pnm->buf + pnm->ptr, "\r\n")];
8434 }
8435
pnm_gets(pnmbuf * pnm,int data)8436 static char *pnm_gets(pnmbuf *pnm, int data)
8437 {
8438 int k, l;
8439
8440 while (TRUE)
8441 {
8442 while (pnm->ptr < pnm->end)
8443 {
8444 l = pnm->ptr + strspn(pnm->buf + pnm->ptr, WHITESPACE);
8445 if (pnm->buf[l] == '#')
8446 {
8447 if (data) return (NULL);
8448 pnm->ptr = l;
8449 pnm_skip_comment(pnm);
8450 continue;
8451 }
8452 k = l + strcspn(pnm->buf + l, WHITESPACE "#");
8453 if (pnm->buf[k] || pnm->eof)
8454 {
8455 pnm->ptr = k + 1;
8456 if (pnm->buf[k] == '#')
8457 {
8458 if (data) return (NULL);
8459 pnm_skip_comment(pnm);
8460 }
8461 pnm->buf[k] = '\0';
8462 return (pnm->buf + l);
8463 }
8464 memmove(pnm->buf, pnm->buf + l, pnm->end -= l);
8465 pnm->ptr = 0;
8466 break;
8467 }
8468 if (pnm->eof) return (NULL);
8469 if (pnm->ptr >= pnm->end) pnm->ptr = pnm->end = 0;
8470 l = PNM_BUFSIZE - pnm->end;
8471 if (l <= 0) return (NULL); // A "token" of 4096 chars means failure
8472 pnm->end += k = fread(pnm->buf + pnm->end, 1, l, pnm->f);
8473 pnm->eof = k < l;
8474 if (pnm->comment) pnm_skip_comment(pnm);
8475 }
8476 }
8477
pnm_endhdr(pnmbuf * pnm,int plain)8478 static int pnm_endhdr(pnmbuf *pnm, int plain)
8479 {
8480 while (pnm->comment)
8481 {
8482 pnm_skip_comment(pnm);
8483 if (!pnm->comment) break;
8484 if (pnm->eof) return (FALSE);
8485 pnm->end = fread(pnm->buf, 1, PNM_BUFSIZE, pnm->f);
8486 pnm->eof = pnm->end < PNM_BUFSIZE;
8487 }
8488 /* Last whitespace in header already got consumed while parsing */
8489
8490 /* Buffer will remain in use in plain mode */
8491 if (!plain && (pnm->ptr < pnm->end))
8492 fseek(pnm->f, pnm->ptr - pnm->end, SEEK_CUR);
8493 return (TRUE);
8494 }
8495
load_pnm_frame(FILE * fp,ls_settings * settings)8496 static int load_pnm_frame(FILE *fp, ls_settings *settings)
8497 {
8498 pnmbuf pnm;
8499 char *s, *tail;
8500 unsigned char *dest;
8501 int i, l, m, w, h, bpp, maxval, plain, mode, fid, res;
8502
8503
8504 /* Identify*/
8505 memset(&pnm, 0, sizeof(pnm));
8506 pnm.f = fp;
8507 fid = settings->ftype == FT_PBM ? 0 : settings->ftype == FT_PGM ? 1 : 2;
8508 if (!(s = pnm_gets(&pnm, FALSE))) return (-1);
8509 if ((s[0] != 'P') || ((s[1] != fid + '1') && (s[1] != fid + '4')))
8510 return (-1);
8511 plain = s[1] < '4';
8512
8513 /* Read header */
8514 if (!(s = pnm_gets(&pnm, FALSE))) return (-1);
8515 w = strtol(s, &tail, 10);
8516 if (*tail) return (-1);
8517 if (!(s = pnm_gets(&pnm, FALSE))) return (-1);
8518 h = strtol(s, &tail, 10);
8519 if (*tail) return (-1);
8520 bpp = maxval = 1;
8521 if (settings->ftype == FT_PBM) set_bw(settings);
8522 else
8523 {
8524 if (!(s = pnm_gets(&pnm, FALSE))) return (-1);
8525 maxval = strtol(s, &tail, 10);
8526 if (*tail) return (-1);
8527 if ((maxval <= 0) || (maxval > 65535)) return (-1);
8528 if (settings->ftype == FT_PGM) set_gray(settings);
8529 else bpp = 3;
8530 }
8531 if (!pnm_endhdr(&pnm, plain)) return (-1);
8532
8533 /* Store values */
8534 settings->width = w;
8535 settings->height = h;
8536 settings->bpp = bpp;
8537
8538 /* Allocate image */
8539 if ((res = allocate_image(settings, CMASK_IMAGE))) return (res);
8540
8541 /* Now, read the image */
8542 mode = settings->ftype == FT_PBM ? plain /* 0 and 1 */ :
8543 plain ? 2 : maxval < 255 ? 3 : maxval > 255 ? 4 : 5;
8544 s = "";
8545 if (!settings->silent) ls_init("PNM", 0);
8546 res = FILE_LIB_ERROR;
8547 l = w * bpp;
8548 m = maxval * 2;
8549 for (i = 0; i < h; i++)
8550 {
8551 dest = settings->img[CHN_IMAGE] + l * i;
8552 switch (mode)
8553 {
8554 case 0: /* Raw packed bits */
8555 {
8556 #if PNM_BUFSIZE * 8 < MAX_WIDTH
8557 #error "Buffer too small to read PBM row all at once"
8558 #endif
8559 int i, j, k;
8560 unsigned char *tp = pnm.buf;
8561
8562 k = (w + 7) >> 3;
8563 j = fread(tp, 1, k, fp);
8564 for (i = 0; i < w; i++)
8565 *dest++ = (tp[i >> 3] >> (~i & 7)) & 1;
8566 if (j < k) goto fail2;
8567 break;
8568 }
8569 case 3: /* Raw byte values - extend later */
8570 case 5: /* Raw 0..255 values - trivial */
8571 if (fread(dest, 1, l, fp) < l) goto fail2;
8572 break;
8573 case 1: /* Chars "0" and "1" */
8574 {
8575 int i;
8576 unsigned char ch;
8577
8578 for (i = 0; i < l; i++)
8579 {
8580 if (!s[0] && !(s = pnm_gets(&pnm, TRUE)))
8581 goto fail2;
8582 ch = *s++ - '0';
8583 if (ch > 1) goto fail2;
8584 *dest++ = ch;
8585 }
8586 break;
8587 }
8588 case 2: /* Integers in ASCII */
8589 {
8590 int i, n;
8591
8592 for (i = 0; i < l; i++)
8593 {
8594 if (!(s = pnm_gets(&pnm, TRUE))) goto fail2;
8595 n = strtol(s, &tail, 10);
8596 if (*tail) goto fail2;
8597 if ((n < 0) || (n > maxval)) goto fail2;
8598 n = (n * (255 * 2) + maxval) / m;
8599 *dest++ = n;
8600 }
8601 break;
8602 }
8603 case 4: /* Raw ushorts in MSB order */
8604 {
8605 int i, j, k, ll;
8606
8607 for (ll = l * 2; ll > 0; ll -= k)
8608 {
8609 k = PNM_BUFSIZE < ll ? PNM_BUFSIZE : ll;
8610 j = fread(pnm.buf, 1, k, fp);
8611 i = j >> 1;
8612 convert_16b(dest, pnm.buf, i, 1, 1, maxval);
8613 dest += i;
8614 if (j < k) goto fail2;
8615 }
8616 break;
8617 }
8618 }
8619 ls_progress(settings, i, 10);
8620 }
8621 res = 1;
8622
8623 /* Check for next frame */
8624 if (!plain) res = check_next_pnm(fp, fid + '4');
8625
8626 fail2: if (mode == 3) // Extend what we've read
8627 extend_bytes(settings->img[CHN_IMAGE], l * h, maxval);
8628 if (!settings->silent) progress_end();
8629
8630 return (res);
8631 }
8632
load_pnm_frames(char * file_name,ani_settings * ani)8633 static int load_pnm_frames(char *file_name, ani_settings *ani)
8634 {
8635 FILE *fp;
8636 ls_settings w_set;
8637 int res, is_pam = ani->settings.ftype == FT_PAM, next = TRUE;
8638
8639
8640 if (!(fp = fopen(file_name, "rb"))) return (-1);
8641 while (next)
8642 {
8643 res = FILE_TOO_LONG;
8644 if (!check_next_frame(&ani->fset, ani->settings.mode, FALSE))
8645 goto fail;
8646 w_set = ani->settings;
8647 w_set.gif_delay = -1; // Multipage
8648 res = (is_pam ? load_pam_frame : load_pnm_frame)(fp, &w_set);
8649 next = res == FILE_HAS_FRAMES;
8650 if ((res != 1) && !next) goto fail;
8651 res = process_page_frame(file_name, ani, &w_set);
8652 if (res) goto fail;
8653 }
8654 res = 1;
8655 fail: fclose(fp);
8656 return (res);
8657 }
8658
load_pnm(char * file_name,ls_settings * settings)8659 static int load_pnm(char *file_name, ls_settings *settings)
8660 {
8661 FILE *fp;
8662 int res;
8663
8664 if (!(fp = fopen(file_name, "rb"))) return (-1);
8665 res = (settings->ftype == FT_PAM ? load_pam_frame :
8666 load_pnm_frame)(fp, settings);
8667 fclose(fp);
8668 return (res);
8669 }
8670
save_pbm(char * file_name,ls_settings * settings)8671 static int save_pbm(char *file_name, ls_settings *settings)
8672 {
8673 unsigned char buf[MAX_WIDTH / 8], bw, *src;
8674 FILE *fp;
8675 int i, l, w = settings->width, h = settings->height;
8676
8677
8678 if ((settings->bpp != 1) || (settings->colors > 2)) return WRONG_FORMAT;
8679
8680 if (!(fp = fopen(file_name, "wb"))) return (-1);
8681
8682 if (!settings->silent) ls_init("PBM", 1);
8683 fprintf(fp, "P4\n%d %d\n", w, h);
8684
8685 bw = get_bw(settings);
8686
8687 /* Write rows */
8688 src = settings->img[CHN_IMAGE];
8689 l = (w + 7) >> 3;
8690 for (i = 0; i < h; i++)
8691 {
8692 pack_MSB(buf, src, w, bw);
8693 src += w;
8694 fwrite(buf, l, 1, fp);
8695 ls_progress(settings, i, 20);
8696 }
8697 fclose(fp);
8698
8699 if (!settings->silent) progress_end();
8700
8701 return (0);
8702 }
8703
save_ppm(char * file_name,ls_settings * settings)8704 static int save_ppm(char *file_name, ls_settings *settings)
8705 {
8706 FILE *fp;
8707 int i, l, m, w = settings->width, h = settings->height;
8708
8709
8710 if (settings->bpp != 3) return WRONG_FORMAT;
8711
8712 if (!(fp = fopen(file_name, "wb"))) return (-1);
8713
8714 if (!settings->silent) ls_init("PPM", 1);
8715 fprintf(fp, "P6\n%d %d\n255\n", w, h);
8716
8717 /* Write rows */
8718 m = (l = w * 3) * h;
8719 // Write entire file at once if no progressbar
8720 if (settings->silent) l = m;
8721 for (i = 0; m > 0; m -= l , i++)
8722 {
8723 fwrite(settings->img[CHN_IMAGE] + l * i, l, 1, fp);
8724 ls_progress(settings, i, 20);
8725 }
8726 fclose(fp);
8727
8728 if (!settings->silent) progress_end();
8729
8730 return (0);
8731 }
8732
save_pam(char * file_name,ls_settings * settings)8733 static int save_pam(char *file_name, ls_settings *settings)
8734 {
8735 unsigned char xv, xa, *dest, *src, *srca, *buf = NULL;
8736 FILE *fp;
8737 int ibpp = settings->bpp, w = settings->width, h = settings->height;
8738 int i, j, bpp;
8739
8740
8741 if ((ibpp != 3) && (settings->colors > 2)) return WRONG_FORMAT;
8742
8743 bpp = ibpp + !!settings->img[CHN_ALPHA];
8744 /* For BW: image XOR 1 if white is 0, alpha AND 1 */
8745 xv = 0; xa = 255;
8746 if (ibpp == 1) xv = get_bw(settings) , xa = 1;
8747 if (bpp != 3) // BW needs inversion, and alpha, interlacing
8748 {
8749 buf = malloc(w * bpp);
8750 if (!buf) return (-1);
8751 }
8752
8753 if (!(fp = fopen(file_name, "wb")))
8754 {
8755 free(buf);
8756 return (-1);
8757 }
8758
8759 if (!settings->silent) ls_init("PAM", 1);
8760 fprintf(fp, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\n"
8761 "TUPLTYPE %s%s\nENDHDR\n", w, h, bpp, ibpp == 1 ? 1 : 255,
8762 ibpp == 1 ? "BLACKANDWHITE" : "RGB", bpp > ibpp ? "_ALPHA" : "");
8763
8764 for (i = 0; i < h; i++)
8765 {
8766 src = settings->img[CHN_IMAGE] + i * w * ibpp;
8767 if ((dest = buf))
8768 {
8769 srca = NULL;
8770 if (settings->img[CHN_ALPHA])
8771 srca = settings->img[CHN_ALPHA] + i * w;
8772 for (j = 0; j < w; j++)
8773 {
8774 *dest++ = *src++ ^ xv;
8775 if (ibpp > 1)
8776 {
8777 *dest++ = *src++;
8778 *dest++ = *src++;
8779 }
8780 if (srca) *dest++ = *srca++ & xa;
8781 }
8782 src = buf;
8783 }
8784 fwrite(src, 1, w * bpp, fp);
8785 ls_progress(settings, i, 20);
8786 }
8787 fclose(fp);
8788
8789 if (!settings->silent) progress_end();
8790 free(buf);
8791
8792 return (0);
8793 }
8794
8795 /* *** PREFACE ***
8796 * PMM is mtPaint's own format, extending the PAM format in a compatible way;
8797 * PAM tools from Netpbm can easily split a PMM file into regular PAM files, or
8798 * build it back from these. Some extra values are stored inside the "TUPLTYPE"
8799 * fields, because Netpbm tools do NOT preserve comments but don't much care
8800 * about TUPLTYPE. Other things, like palette, are stored as separate
8801 * pseudo-images preceding the bitmap, with their own TUPLTYPE and extra values.
8802 * When building a PMM file out of PAMs by hand, just write out the PMM_ID1
8803 * string, below, before the first PAM file - WJ */
8804
8805 # define PMM_ID1 "P7\n#MTPAINT#"
8806
8807 typedef struct {
8808 char *next; // the rest of string
8809 char *tag; // last found tag
8810 int val; // its value if any
8811 } tagline;
8812
8813 /* Parse a tag out of string */
nexttag(tagline * iter,int split_under)8814 static int nexttag(tagline *iter, int split_under)
8815 {
8816 char *s, *tail, *str = iter->next;
8817 int l, n, res = 1;
8818
8819 iter->tag = str;
8820 if (!str || !*str) return (0); // Empty
8821 l = strcspn(str, "_=" WHITESPACE + !split_under);
8822 if (!l) return (0); // No tag here - format violation
8823 s = str + l;
8824 if (*s == '=') /* NAME=VALUE */
8825 {
8826 n = strtol(++s, &tail, 10);
8827 if ((tail == s) || (*tail && !strchr(WHITESPACE, *tail)))
8828 return (0); // Unparsable or no value - format violation
8829 iter->val = n;
8830 s = tail;
8831 res = 2; // Have value
8832 }
8833 else s += (*s == '_'); /* NAME_ */
8834
8835 iter->next = s + strspn(s, WHITESPACE);
8836 str[l] = '\0';
8837
8838 return (res); // Parsed another tag
8839 }
8840
8841 /* Interpret known value tags, ignore unknown ones */
readtags(tagline * tl,ls_settings * settings,int bpp)8842 static void readtags(tagline *tl, ls_settings *settings, int bpp)
8843 {
8844 static const char *tags[] = { "TRANS", "DELAY", "X", "Y", NULL };
8845 int j, i = 2;
8846
8847 // Skip channel tags if no extra channels
8848 if (!bpp) while ((i = nexttag(tl, FALSE)) == 1);
8849
8850 while (i == 2)
8851 {
8852 for (j = 0; tags[j] && strcmp(tl->tag, tags[j]); j++);
8853 i = tl->val;
8854
8855 switch (j)
8856 {
8857 case 0: // Transparent color
8858 /* Invalid value - ignore */
8859 if (i < -1) break;
8860 /* No transparency - disable */
8861 if (i == -1) settings->xpm_trans =
8862 settings->rgb_trans = -1;
8863 /* Indexed transparency */
8864 else if (bpp < 3)
8865 {
8866 if (i < settings->colors) settings->xpm_trans = i;
8867 }
8868 /* RGB transparency */
8869 else if (i <= 0xFFFFFF)
8870 {
8871 int j = settings->xpm_trans;
8872 png_color *p = settings->pal + j;
8873 // Only if differs from indexed
8874 if ((j < 0) || (PNG_2_INT(*p) != i))
8875 settings->rgb_trans = i;
8876 }
8877 break;
8878 case 1: // Anim delay, in 0.01 sec
8879 if (i >= 0) settings->gif_delay = i;
8880 break;
8881 case 2: // X offset
8882 settings->x = i;
8883 break;
8884 case 3: // Y offset
8885 settings->y = i;
8886 break;
8887 // !!! No other parameters yet
8888 }
8889 i = nexttag(tl, FALSE);
8890 }
8891 }
8892
load_pmm_frame(memFILE * mf,ls_settings * settings)8893 static int load_pmm_frame(memFILE *mf, ls_settings *settings)
8894 {
8895 /* !!! INDEXED is at index 1, RGB at index 3 to use index as BPP */
8896 static const char *blocks[] = { "TAGS", "INDEXED", "PALETTE", "RGB", NULL };
8897 tagline tl;
8898 unsigned char *dest, *buf = NULL;
8899 char *ttype = NULL;
8900 int w, h, depth, rgbpp, cmask = CMASK_IMAGE;
8901 int i, j, l, res, whdm[4], slots[NUM_CHANNELS];
8902
8903 while (TRUE)
8904 {
8905 res = -1;
8906 free(ttype);
8907 if (!(tl.next = ttype = pam_behead(mf, whdm))) break;
8908 if (whdm[3] > 255) break; // 16-bit values not allowed
8909 depth = whdm[2];
8910 if (depth > 16) break; // Depth limited to sane values
8911 w = whdm[0]; h = whdm[1];
8912
8913 /* Parse out type tag */
8914 j = -1;
8915 if (nexttag(&tl, TRUE) == 1)
8916 {
8917 for (j = 0; blocks[j] && strcmp(blocks[j], tl.tag); j++);
8918 if (!blocks[j]) j = -1;
8919 }
8920
8921 if (!j) readtags(&tl, settings, 0); /* TAGS */
8922
8923 if (j <= 0) /* !!! IGNORE anything unrecognized & skip "TAGS" */
8924 {
8925 mfseek(mf, w * h * depth, SEEK_CUR);
8926 continue;
8927 }
8928
8929 if (j == 2) /* PALETTE */
8930 {
8931 unsigned char pbuf[256 * 16], *tp = pbuf;
8932
8933 /* Validate */
8934 if ((depth < 3) || (w < 2) || (w > 256) || (h != 1)) break;
8935 settings->colors = w;
8936 settings->xpm_trans = settings->rgb_trans = -1; // Default
8937
8938 /* Skip channel tags, interpret value tags */
8939 readtags(&tl, settings, 0);
8940
8941 if (mfread(pbuf, depth, w, mf) != w) break; // Failed
8942 /* Store palette */
8943 extend_bytes(tp, w * depth, whdm[3]);
8944 for (i = 0; i < w; i++)
8945 {
8946 settings->pal[i].red = tp[0];
8947 settings->pal[i].green = tp[1];
8948 settings->pal[i].blue = tp[2];
8949 tp += depth;
8950 }
8951 /* If palette is all we need */
8952 res = EXPLODE_FAILED;
8953 if ((settings->mode == FS_PALETTE_LOAD) ||
8954 (settings->mode == FS_PALETTE_DEF)) break;
8955 continue;
8956 }
8957
8958 /* Got an image bitmap */
8959 // !!! Only slots 1 & 3 fall through to here
8960 rgbpp = j;
8961 /* Add up extra channels */
8962 memset(slots, 0, sizeof(slots));
8963 while ((i = nexttag(&tl, FALSE)) == 1)
8964 {
8965 if (!strcmp(tl.tag, "ALPHA")) i = CHN_ALPHA;
8966 else if (!strcmp(tl.tag, "SELECTION")) i = CHN_SEL;
8967 else if (!strcmp(tl.tag, "MASK")) i = CHN_MASK;
8968 else // Unknown channel - skip
8969 {
8970 j++;
8971 continue;
8972 }
8973 slots[i] = j++;
8974 cmask |= CMASK_FOR(i);
8975 }
8976 if (j > depth) break; // Cannot be
8977
8978 /* Interpret value tags */
8979 if (i == 2) readtags(&tl, settings, rgbpp);
8980
8981 l = w * depth;
8982 /* Allocate row buffer if cannot read directly into image */
8983 if (rgbpp != depth)
8984 {
8985 res = FILE_MEM_ERROR;
8986 if (!(buf = malloc(l))) break;
8987 }
8988 /* Allocate image */
8989 settings->width = w;
8990 settings->height = h;
8991 settings->bpp = rgbpp;
8992 if ((res = allocate_image(settings, cmask))) break;
8993
8994 /* Read the image */
8995 if (!settings->silent) ls_init("* PMM *", 0);
8996 res = FILE_LIB_ERROR;
8997 for (i = 0; i < h; i++)
8998 {
8999 dest = settings->img[CHN_IMAGE] + w * rgbpp * i;
9000 if (!mfread(buf ? buf : dest, l, 1, mf)) goto fail;
9001 ls_progress(settings, i, 10);
9002 if (!buf) continue; // Nothing else to do here
9003
9004 copy_bytes(dest, buf, w, rgbpp, depth);
9005 for (j = CHN_ALPHA; j < NUM_CHANNELS; j++)
9006 if (settings->img[j]) copy_bytes(
9007 settings->img[j] + w * i,
9008 buf + slots[j], w, 1, depth);
9009 }
9010
9011 /* Extend what we've read */
9012 if (whdm[3] < 255)
9013 {
9014 i = w * h * rgbpp;
9015 for (j = CHN_IMAGE; j < NUM_CHANNELS; j++)
9016 {
9017 if (settings->img[j]) extend_bytes(
9018 settings->img[j], i, whdm[3]);
9019 i = w * h;
9020 }
9021 }
9022
9023 /* Check for next frame */
9024 res = 1;
9025 if (mfread(ttype, 2, 1, mf)) // it was no shorter than "RGB"
9026 {
9027 mfseek(mf, -2, SEEK_CUR);
9028 if (!strncmp(ttype, "P7", 2)) res = FILE_HAS_FRAMES;
9029 }
9030
9031 fail: if (!settings->silent) progress_end();
9032 break;
9033 }
9034 free(buf);
9035 free(ttype);
9036 return (res);
9037 }
9038
load_pmm_frames(char * file_name,ani_settings * ani,memFILE * mf)9039 static int load_pmm_frames(char *file_name, ani_settings *ani, memFILE *mf)
9040 {
9041 memFILE fake_mf;
9042 FILE *fp = NULL;
9043 ls_settings w_set, init_set;
9044 int res, next;
9045
9046
9047 if (!mf)
9048 {
9049 if (!(fp = fopen(file_name, "rb"))) return (-1);
9050 memset(mf = &fake_mf, 0, sizeof(fake_mf));
9051 fake_mf.file = fp;
9052 }
9053 init_set = ani->settings;
9054 init_set.gif_delay = -1; // Multipage by default
9055 while (TRUE)
9056 {
9057 w_set = init_set;
9058 res = load_pmm_frame(mf, &w_set);
9059 next = res == FILE_HAS_FRAMES;
9060 if ((res != 1) && !next) break;
9061 /* !!! RGB transparency may modify the palette */
9062 map_rgb_trans(&w_set);
9063 if ((res = process_page_frame(file_name, ani, &w_set))) break;
9064 res = 1;
9065 if (!next) break;
9066 res = FILE_TOO_LONG;
9067 if (!check_next_frame(&ani->fset, ani->settings.mode,
9068 w_set.gif_delay >= 0)) break;
9069 /* Update initial values */
9070 init_set.colors = w_set.colors; // Palettes are inheritable
9071 init_set.xpm_trans = w_set.xpm_trans;
9072 init_set.rgb_trans = w_set.rgb_trans;
9073 init_set.gif_delay = w_set.gif_delay;
9074 }
9075 fclose(fp);
9076 return (res);
9077 }
9078
load_pmm(char * file_name,ls_settings * settings,memFILE * mf)9079 static int load_pmm(char *file_name, ls_settings *settings, memFILE *mf)
9080 {
9081 memFILE fake_mf;
9082 FILE *fp = NULL;
9083 int res;
9084
9085 if (!mf)
9086 {
9087 if (!(fp = fopen(file_name, "rb"))) return (-1);
9088 memset(mf = &fake_mf, 0, sizeof(fake_mf));
9089 fake_mf.file = fp;
9090 }
9091 res = load_pmm_frame(mf, settings);
9092 if (fp) fclose(fp);
9093 return (res);
9094 }
9095
save_pmm(char * file_name,ls_settings * settings,memFILE * mf)9096 static int save_pmm(char *file_name, ls_settings *settings, memFILE *mf)
9097 {
9098 unsigned char *dest, *src, *buf = NULL;
9099 unsigned char sbuf[768];
9100 memFILE fake_mf;
9101 FILE *fp = NULL;
9102 int rgbpp = settings->bpp, w = settings->width, h = settings->height;
9103 int i, k, bpp;
9104
9105
9106 for (i = bpp = 0; i < NUM_CHANNELS; i++) bpp += !!settings->img[i];
9107 bpp += rgbpp - 1;
9108 /* Allocate row buffer if needed */
9109 if ((bpp != rgbpp) && (settings->mode != FS_PALETTE_SAVE))
9110 {
9111 buf = malloc(w * bpp);
9112 if (!buf) return (-1);
9113 }
9114
9115 if (!mf)
9116 {
9117 if (!(fp = fopen(file_name, "wb")))
9118 {
9119 free(buf);
9120 return (-1);
9121 }
9122 memset(mf = &fake_mf, 0, sizeof(fake_mf));
9123 fake_mf.file = fp;
9124 }
9125
9126 if (!settings->silent) ls_init("* PMM *", 1);
9127
9128 /* First, write palette */
9129 if (settings->pal)
9130 {
9131 mfputs(PMM_ID1 "\n", mf);
9132 snprintf(sbuf, sizeof(sbuf), "WIDTH %d\n", settings->colors);
9133 mfputs(sbuf, mf);
9134 // Extra data for palette: transparent index if any
9135 sbuf[0] = '\0';
9136 if (settings->xpm_trans >= 0) snprintf(sbuf, sizeof(sbuf),
9137 " TRANS=%d", settings->xpm_trans);
9138 mfputss(mf, "HEIGHT 1\nDEPTH 3\nMAXVAL 255\nTUPLTYPE PALETTE",
9139 sbuf, "\nENDHDR\n", NULL);
9140 pal2rgb(sbuf, settings->pal, settings->colors, 0);
9141 mfwrite(sbuf, 1, settings->colors * 3, mf);
9142 }
9143 /* All done if only writing palette */
9144 if (settings->mode == FS_PALETTE_SAVE) goto done;
9145
9146 /* Now, write image bitmap */
9147 mfputs(PMM_ID1 "\n", mf);
9148 snprintf(sbuf, sizeof(sbuf), "WIDTH %d\nHEIGHT %d\nDEPTH %d\n",
9149 w, h, bpp);
9150 mfputss(mf, sbuf, "MAXVAL 255\nTUPLTYPE ",
9151 rgbpp > 1 ? "RGB" : "INDEXED",
9152 settings->img[CHN_ALPHA] ? "_ALPHA" : "",
9153 settings->img[CHN_SEL] ? " SELECTION" : "",
9154 settings->img[CHN_MASK] ? " MASK" : "",
9155 "\nENDHDR\n", NULL);
9156
9157 for (i = 0; i < h; i++)
9158 {
9159 src = settings->img[CHN_IMAGE] + i * w * rgbpp;
9160 if ((dest = buf))
9161 {
9162 copy_bytes(dest, src, w, bpp, rgbpp);
9163 dest += rgbpp;
9164 for (k = CHN_ALPHA; k < NUM_CHANNELS; k++)
9165 if (settings->img[k]) copy_bytes(dest++,
9166 settings->img[k] + i * w, w, bpp, 1);
9167 src = buf;
9168 }
9169 mfwrite(src, 1, w * bpp, mf);
9170 ls_progress(settings, i, 20);
9171 }
9172 done: if (fp) fclose(fp);
9173
9174 if (!settings->silent) progress_end();
9175
9176 free(buf);
9177 return 0;
9178 }
9179
9180 /* Put screenshots and X pixmaps on an equal footing with regular files */
9181
9182 #ifdef HAVE_PIXMAPS
9183
save_pixmap(ls_settings * settings,memFILE * mf)9184 static int save_pixmap(ls_settings *settings, memFILE *mf)
9185 {
9186 pixmap_info p;
9187 unsigned char *src, *dest, *sel, *buf = NULL;
9188 int i, j, l, w = settings->width, h = settings->height;
9189
9190 /* !!! Pixmap export used only for FS_CLIPBOARD, where the case of
9191 * selection without alpha is already prevented */
9192 if ((settings->bpp == 1) || settings->img[CHN_ALPHA])
9193 {
9194 buf = malloc(w * 3);
9195 if (!buf) return (-1);
9196 }
9197
9198 if (!export_pixmap(&p, w, h))
9199 {
9200 free(buf);
9201 return (-1);
9202 }
9203
9204 /* Plain RGB - copy it whole */
9205 if (!buf) pixmap_put_rows(&p, settings->img[CHN_IMAGE], 0, h);
9206
9207 /* Something else - render & copy row by row */
9208 else
9209 {
9210 l = w * settings->bpp;
9211 for (i = 0; i < h; i++)
9212 {
9213 src = settings->img[CHN_IMAGE] + l * i;
9214 if (settings->bpp == 3) memcpy(buf, src, l);
9215 else do_convert_rgb(0, 1, w, buf, src, settings->pal);
9216 /* There is no way to send alpha to XPaint, so I use
9217 * alpha (and selection if any) to blend image with
9218 * white and send the result - WJ */
9219 if (settings->img[CHN_ALPHA])
9220 {
9221 src = settings->img[CHN_ALPHA] + w * i;
9222 sel = settings->img[CHN_SEL] ?
9223 settings->img[CHN_SEL] + w * i : NULL;
9224 dest = buf;
9225 for (j = 0; j < w; j++)
9226 {
9227 int ii, jj, k = *src++;
9228
9229 if (sel)
9230 {
9231 k *= *sel++;
9232 k = (k + (k >> 8) + 1) >> 8;
9233 }
9234 for (ii = 0; ii < 3; ii++)
9235 {
9236 jj = 255 * 255 + (*dest - 255) * k;
9237 *dest++ = (jj + (jj >> 8) + 1) >> 8;
9238 }
9239 }
9240 }
9241 pixmap_put_rows(&p, buf, i, 1);
9242 }
9243 free(buf);
9244 }
9245
9246 *(XID_type *)mf->m.buf = p.xid;
9247 mf->top = sizeof(XID_type);
9248 return (0);
9249 }
9250
9251 #else /* Pixmap export fails by definition in absence of X */
9252 #define save_pixmap(A,B) (-1)
9253 #endif
9254
load_pixmap(ls_settings * settings,memFILE * mf)9255 static int load_pixmap(ls_settings *settings, memFILE *mf)
9256 {
9257 pixmap_info p;
9258 int res = -1;
9259
9260 if (import_pixmap(&p, mf ? (void *)mf->m.buf : NULL)) // !mf == screenshot
9261 {
9262 settings->width = p.w;
9263 settings->height = p.h;
9264 settings->bpp = 3;
9265 res = allocate_image(settings, CMASK_IMAGE);
9266 if (!res) res = pixmap_get_rows(&p,
9267 settings->img[CHN_IMAGE], 0, p.h) ? 1 : -1;
9268 drop_pixmap(&p);
9269 }
9270 return (res);
9271 }
9272
9273 /* Handle SVG import using gdk-pixbuf */
9274
9275 #if (GDK_PIXBUF_MAJOR > 2) || ((GDK_PIXBUF_MAJOR == 2) && (GDK_PIXBUF_MINOR >= 4))
9276
9277 #define MAY_HANDLE_SVG
9278
9279 static int svg_check = -1;
9280
svg_supported()9281 static int svg_supported()
9282 {
9283 GSList *tmp, *ff;
9284 int i, res = FALSE;
9285
9286 ff = gdk_pixbuf_get_formats();
9287 for (tmp = ff; tmp; tmp = tmp->next)
9288 {
9289 gchar **mime = gdk_pixbuf_format_get_mime_types(tmp->data);
9290
9291 for (i = 0; mime[i]; i++)
9292 {
9293 res |= strstr(mime[i], "image/svg") == mime[i];
9294 }
9295 g_strfreev(mime);
9296 if (res) break;
9297 }
9298 g_slist_free(ff);
9299 return (res);
9300 }
9301
load_svg(char * file_name,ls_settings * settings)9302 static int load_svg(char *file_name, ls_settings *settings)
9303 {
9304 GdkPixbuf *pbuf;
9305 GError *err = NULL;
9306 guchar *src;
9307 unsigned char *dest, *dsta;
9308 int i, j, w, h, bpp, cmask, skip, res = -1;
9309
9310
9311 #if (GDK_PIXBUF_MAJOR == 2) && (GDK_PIXBUF_MINOR < 8)
9312 /* 2.4 can constrain size only while preserving aspect ratio;
9313 * 2.6 can constrain size fully, but not partially */
9314 if (settings->req_w && settings->req_h)
9315 pbuf = gdk_pixbuf_new_from_file_at_scale(file_name,
9316 settings->req_w, settings->req_h, FALSE, &err);
9317 else pbuf = gdk_pixbuf_new_from_file(file_name, &err);
9318 #else
9319 /* 2.8+ is full-featured */
9320 pbuf = gdk_pixbuf_new_from_file_at_scale(file_name,
9321 settings->req_w ? settings->req_w : -1,
9322 settings->req_h ? settings->req_h : -1,
9323 !(settings->req_w && settings->req_h), &err);
9324 #endif
9325 if (!pbuf)
9326 {
9327 if ((err->domain == GDK_PIXBUF_ERROR) &&
9328 (err->code == GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY))
9329 res = FILE_MEM_ERROR;
9330 g_error_free(err);
9331 return (res);
9332 }
9333 /* Prevent images loading wrong in case gdk-pixbuf ever starts using
9334 * something other than 8-bit RGB/RGBA without me noticing - WJ */
9335 if (gdk_pixbuf_get_bits_per_sample(pbuf) != 8) goto fail;
9336
9337 bpp = gdk_pixbuf_get_n_channels(pbuf);
9338 if (bpp == 4) cmask = CMASK_RGBA;
9339 else if (bpp == 3) cmask = CMASK_IMAGE;
9340 else goto fail;
9341 settings->width = w = gdk_pixbuf_get_width(pbuf);
9342 settings->height = h = gdk_pixbuf_get_height(pbuf);
9343 settings->bpp = 3;
9344 if ((res = allocate_image(settings, cmask))) goto fail;
9345
9346 skip = gdk_pixbuf_get_rowstride(pbuf) - w * bpp;
9347 src = gdk_pixbuf_get_pixels(pbuf);
9348 dest = settings->img[CHN_IMAGE];
9349 dsta = settings->img[CHN_ALPHA];
9350 for (i = 0; i < h; i++ , src += skip)
9351 for (j = 0; j < w; j++ , src += bpp , dest += 3)
9352 {
9353 dest[0] = src[0];
9354 dest[1] = src[1];
9355 dest[2] = src[2];
9356 if (dsta) *dsta++ = src[3];
9357 }
9358 res = 1;
9359
9360 /* Delete all-set "alpha" */
9361 delete_alpha(settings, 255);
9362
9363 fail: g_object_unref(pbuf);
9364 return (res);
9365 }
9366
9367 #endif
9368
9369 /* Handle SVG import using rsvg-convert */
9370
import_svg(char * file_name,ls_settings * settings)9371 static int import_svg(char *file_name, ls_settings *settings)
9372 {
9373 da_settings ds;
9374 char buf[PATHBUF];
9375 int res = -1;
9376
9377 if (!get_tempname(buf, file_name, FT_PNG)) return (-1);
9378 memset(&ds, 0, sizeof(ds));
9379 ds.sname = file_name;
9380 ds.dname = buf;
9381 ds.width = settings->req_w;
9382 ds.height = settings->req_h;
9383 if (!run_def_action_x(DA_SVG_CONVERT, &ds))
9384 res = load_png(buf, settings, NULL, FALSE);
9385 unlink(buf);
9386
9387 /* Delete all-set "alpha" */
9388 if (res == 1) delete_alpha(settings, 255);
9389
9390 return (res);
9391 }
9392
9393 /* Handle textual palette file formats - GIMP's GPL and mtPaint's own TXT */
9394
to_pal(png_color * c,int * rgb)9395 static void to_pal(png_color *c, int *rgb)
9396 {
9397 c->red = rgb[0] < 0 ? 0 : rgb[0] > 255 ? 255 : rgb[0];
9398 c->green = rgb[1] < 0 ? 0 : rgb[1] > 255 ? 255 : rgb[1];
9399 c->blue = rgb[2] < 0 ? 0 : rgb[2] > 255 ? 255 : rgb[2];
9400 }
9401
load_txtpal(char * file_name,ls_settings * settings)9402 static int load_txtpal(char *file_name, ls_settings *settings)
9403 {
9404 char lbuf[4096];
9405 FILE *fp;
9406 png_color *c = settings->pal;
9407 int i, rgb[3], n = 0, res = -1;
9408
9409
9410 if (!(fp = fopen(file_name, "r"))) return (-1);
9411 if (!fgets(lbuf, 4096, fp)) goto fail;
9412 if (settings->ftype == FT_GPL)
9413 {
9414 if (strstr(lbuf, "GIMP Palette") != lbuf) goto fail;
9415 while (fgets(lbuf, 4096, fp) && (n < 256))
9416 {
9417 /* Just ignore invalid/unknown lines */
9418 if (sscanf(lbuf, "%d %d %d", rgb + 0, rgb + 1, rgb + 2) != 3)
9419 continue;
9420 to_pal(c++, rgb);
9421 n++;
9422 }
9423 }
9424 else
9425 {
9426 if (sscanf(lbuf, "%i", &n) != 1) goto fail;
9427 /* No further validation of anything at all */
9428 n = n < 2 ? 2 : n > 256 ? 256 : n;
9429 for (i = 0; i < n; i++)
9430 {
9431 fscanf(fp, "%i,%i,%i\n", rgb + 0, rgb + 1, rgb + 2);
9432 to_pal(c++, rgb);
9433 }
9434 }
9435 settings->colors = n;
9436 if (n > 0) res = 1;
9437
9438 fail: fclose(fp);
9439 return (res);
9440 }
9441
save_txtpal(char * file_name,ls_settings * settings)9442 static int save_txtpal(char *file_name, ls_settings *settings)
9443 {
9444 FILE *fp;
9445 char *tpl;
9446 png_color *cp;
9447 int i, l, n = settings->colors;
9448
9449 if ((fp = fopen(file_name, "w")) == NULL) return (-1);
9450
9451 if (settings->ftype == FT_GPL) // .gpl file
9452 {
9453 tpl = extract_ident(file_name, &l);
9454 if (!l) tpl = "mtPaint" , l = strlen("mtPaint");
9455 fprintf(fp, "GIMP Palette\nName: %.*s\nColumns: 16\n#\n", l, tpl);
9456 tpl = "%3i %3i %3i\tUntitled\n";
9457 }
9458 else // .txt file
9459 {
9460 fprintf(fp, "%i\n", n);
9461 tpl = "%i,%i,%i\n";
9462 }
9463
9464 cp = settings->pal;
9465 for (i = 0; i < n; i++ , cp++)
9466 fprintf(fp, tpl, cp->red, cp->green, cp->blue);
9467
9468 fclose(fp);
9469 return (0);
9470 }
9471
9472 /* Handle raw palette file formats - 6-bit PAL and 8-bit ACT */
9473
load_rawpal(char * file_name,ls_settings * settings)9474 static int load_rawpal(char *file_name, ls_settings *settings)
9475 {
9476 unsigned char buf[769], xlat[256], *tp;
9477 FILE *fp;
9478 char *stop;
9479 int i, l, ftype;
9480
9481
9482 memset(buf, 0, sizeof(buf));
9483 if (!(fp = fopen(file_name, "rb"))) return (-1);
9484 l = fread(buf, 1, 769, fp);
9485 fclose(fp);
9486 if (!l || (l > 768) || (l % 3)) return (-1); // Wrong size
9487 l /= 3;
9488
9489 /* !!! Filetype in ls_settings is ignored */
9490 ftype = FT_NONE;
9491 if ((stop = strrchr(file_name, '.')))
9492 {
9493 if (!strcasecmp(stop + 1, "act"))
9494 {
9495 if (l != 256) return (-1);
9496 ftype = FT_ACT;
9497 }
9498 else if (!strcasecmp(stop + 1, "pal"))
9499 ftype = FT_PAL;
9500 }
9501 if (l < 256) ftype = FT_PAL;
9502
9503 if (ftype != FT_ACT) // Default to 6-bit
9504 {
9505 set_xlate(xlat, 6);
9506 for (i = 64; i < 255; i++) xlat[i] = xlat[i - 64];
9507 }
9508 else set_xlate(xlat, 8); // 1:1
9509
9510 for (i = 0 , tp = buf; i < l; i++)
9511 {
9512 settings->pal[i].red = xlat[tp[0]];
9513 settings->pal[i].green = xlat[tp[1]];
9514 settings->pal[i].blue = xlat[tp[2]];
9515 tp += 3;
9516 }
9517 settings->colors = l;
9518
9519 return (1);
9520 }
9521
save_rawpal(char * file_name,ls_settings * settings)9522 static int save_rawpal(char *file_name, ls_settings *settings)
9523 {
9524 FILE *fp;
9525 unsigned char buf[768], xlat[256], *tp;
9526 png_color *cp;
9527 int i, n = settings->colors;
9528
9529 if (!(fp = fopen(file_name, "wb"))) return (-1);
9530
9531 memset(buf, 0, 768);
9532 if (settings->ftype == FT_PAL) // 6-bit
9533 for (i = 0; i < 256; i++)
9534 xlat[i] = (63 * 2 * i + 255) / (255 * 2);
9535 else for (i = 0; i < 256; i++) xlat[i] = i; // 8-bit ACT
9536
9537 cp = settings->pal;
9538 for (i = 0 , tp = buf; i < n; i++ , cp++)
9539 {
9540 tp[0] = xlat[cp->red];
9541 tp[1] = xlat[cp->green];
9542 tp[2] = xlat[cp->blue];
9543 tp += 3;
9544 }
9545 if (settings->ftype != FT_PAL) n = 256;
9546 i = fwrite(buf, n * 3, 1, fp);
9547 fclose(fp);
9548
9549 return (i ? 0 : -1);
9550 }
9551
save_image_x(char * file_name,ls_settings * settings,memFILE * mf)9552 static int save_image_x(char *file_name, ls_settings *settings, memFILE *mf)
9553 {
9554 ls_settings setw = *settings; // Make a copy to safely modify
9555 png_color greypal[256];
9556 int res;
9557
9558 /* Prepare to handle clipboard export */
9559 if (setw.mode != FS_CLIPBOARD); // not export
9560 else if (setw.ftype & FTM_EXTEND) setw.mode = FS_CLIP_FILE; // to mtPaint
9561 else if (setw.img[CHN_SEL] && !setw.img[CHN_ALPHA])
9562 {
9563 /* Pass clipboard mask as alpha if there is no alpha already */
9564 setw.img[CHN_ALPHA] = setw.img[CHN_SEL];
9565 setw.img[CHN_SEL] = NULL;
9566 }
9567 setw.ftype &= FTM_FTYPE;
9568
9569 /* Be silent if only writing palette */
9570 if (setw.mode == FS_PALETTE_SAVE) setw.silent = TRUE;
9571
9572 /* Provide a grayscale palette if needed */
9573 if ((setw.bpp == 1) && !setw.pal)
9574 mem_bw_pal(setw.pal = greypal, 0, 255);
9575
9576 /* Validate transparent color (for now, forbid out-of-palette RGB
9577 * transparency altogether) */
9578 if (setw.colors && (setw.xpm_trans >= setw.colors))
9579 setw.xpm_trans = setw.rgb_trans = -1;
9580
9581 switch (setw.ftype)
9582 {
9583 default:
9584 case FT_PNG: res = save_png(file_name, &setw, mf); break;
9585 case FT_GIF: res = save_gif(file_name, &setw); break;
9586 #ifdef U_JPEG
9587 case FT_JPEG: res = save_jpeg(file_name, &setw); break;
9588 #endif
9589 #ifdef HANDLE_JP2
9590 case FT_JP2:
9591 case FT_J2K: res = save_jpeg2000(file_name, &setw); break;
9592 #endif
9593 #ifdef U_TIFF
9594 case FT_TIFF: res = save_tiff(file_name, &setw, mf); break;
9595 #endif
9596 #ifdef U_WEBP
9597 case FT_WEBP: res = save_webp(file_name, &setw); break;
9598 #endif
9599 case FT_BMP: res = save_bmp(file_name, &setw, mf); break;
9600 case FT_XPM: res = save_xpm(file_name, &setw); break;
9601 case FT_XBM: res = save_xbm(file_name, &setw); break;
9602 case FT_LSS: res = save_lss(file_name, &setw); break;
9603 case FT_TGA: res = save_tga(file_name, &setw); break;
9604 case FT_PCX: res = save_pcx(file_name, &setw); break;
9605 case FT_LBM: res = save_lbm(file_name, &setw); break;
9606 case FT_PBM: res = save_pbm(file_name, &setw); break;
9607 case FT_PPM: res = save_ppm(file_name, &setw); break;
9608 case FT_PAM: res = save_pam(file_name, &setw); break;
9609 case FT_PMM: res = save_pmm(file_name, &setw, mf); break;
9610 case FT_PIXMAP: res = save_pixmap(&setw, mf); break;
9611 /* Palette files */
9612 case FT_GPL:
9613 case FT_TXT: res = save_txtpal(file_name, &setw); break;
9614 case FT_PAL:
9615 case FT_ACT: res = save_rawpal(file_name, &setw); break;
9616 }
9617
9618 return (res);
9619 }
9620
save_image(char * file_name,ls_settings * settings)9621 int save_image(char *file_name, ls_settings *settings)
9622 {
9623 return (save_image_x(file_name, settings, NULL));
9624 }
9625
save_mem_image(unsigned char ** buf,int * len,ls_settings * settings)9626 int save_mem_image(unsigned char **buf, int *len, ls_settings *settings)
9627 {
9628 memFILE mf;
9629 int res;
9630
9631 memset(&mf, 0, sizeof(mf));
9632 if ((settings->ftype & FTM_FTYPE) == FT_PIXMAP)
9633 mf.m.buf = malloc(sizeof(XID_type)); // Expect to know type here
9634 else if (!(file_formats[settings->ftype & FTM_FTYPE].flags & FF_WMEM))
9635 return (-1);
9636 else mf.m.buf = malloc(mf.m.size = 0x4000 - 64);
9637 /* Be silent when saving to memory */
9638 settings->silent = TRUE;
9639 res = save_image_x(NULL, settings, &mf);
9640 if (res) free(mf.m.buf);
9641 else *buf = mf.m.buf , *len = mf.top;
9642 return (res);
9643 }
9644
store_image_extras(image_info * image,image_state * state,ls_settings * settings)9645 static void store_image_extras(image_info *image, image_state *state,
9646 ls_settings *settings)
9647 {
9648 #if U_LCMS
9649 /* Apply ICC profile */
9650 while (settings->icc_size > 0)
9651 {
9652 cmsHPROFILE from, to;
9653 cmsHTRANSFORM how = NULL;
9654 int l = settings->icc_size - sizeof(icHeader);
9655 unsigned char *iccdata = settings->icc + sizeof(icHeader);
9656
9657 /* Do nothing if the profile seems to be the default sRGB one */
9658 if ((l == 3016) && (hashf(HASHSEED, iccdata, l) == 0xBA0A8E52UL) &&
9659 (hashf(HASH_RND(HASHSEED), iccdata, l) == 0x94C42C77UL)) break;
9660
9661 from = cmsOpenProfileFromMem((void *)settings->icc,
9662 settings->icc_size);
9663 to = cmsCreate_sRGBProfile();
9664 if (from && (cmsGetColorSpace(from) == icSigRgbData))
9665 how = cmsCreateTransform(from, TYPE_RGB_8,
9666 to, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
9667 if (how && (settings->bpp == 1)) /* For GIF: apply to palette */
9668 {
9669 unsigned char tm[256 * 3];
9670 int l = settings->colors;
9671
9672 pal2rgb(tm, settings->pal, l, 0);
9673 cmsDoTransform(how, tm, tm, l);
9674 rgb2pal(settings->pal, tm, l);
9675
9676 cmsDeleteTransform(how);
9677 }
9678 else if (how)
9679 {
9680 unsigned char *img = settings->img[CHN_IMAGE];
9681 size_t l = settings->width, sz = l * settings->height;
9682 int i, j;
9683
9684 if (!settings->silent)
9685 progress_init(_("Applying colour profile"), 1);
9686 else if (sz < UINT_MAX) l = sz;
9687 j = sz / l;
9688 for (i = 0; i < j; i++ , img += l * 3)
9689 {
9690 if (!settings->silent && ((i * 20) % j >= j - 20))
9691 if (progress_update((float)i / j)) break;
9692 cmsDoTransform(how, img, img, l);
9693 }
9694 progress_end();
9695 cmsDeleteTransform(how);
9696 }
9697 if (from) cmsCloseProfile(from);
9698 cmsCloseProfile(to);
9699 break;
9700 }
9701 #endif
9702 // !!! Changing any values is frequently harmful in this mode, so don't do it
9703 if (settings->mode == FS_CHANNEL_LOAD) return;
9704
9705 /* Stuff RGB transparency into color 255 */
9706 map_rgb_trans(settings);
9707
9708 /* Accept vars which make sense */
9709 state->xbm_hot_x = settings->hot_x;
9710 state->xbm_hot_y = settings->hot_y;
9711 if (settings->gif_delay > 0) preserved_gif_delay = settings->gif_delay;
9712
9713 /* Accept palette */
9714 image->trans = settings->xpm_trans;
9715 mem_pal_copy(image->pal, settings->pal);
9716 image->cols = settings->colors;
9717 }
9718
load_image_x(char * file_name,memFILE * mf,int mode,int ftype,int rw,int rh)9719 static int load_image_x(char *file_name, memFILE *mf, int mode, int ftype,
9720 int rw, int rh)
9721 {
9722 layer_image *lim = NULL;
9723 png_color pal[256];
9724 ls_settings settings;
9725 int i, tr, res, res0, undo = ftype & FTM_UNDO;
9726
9727
9728 /* Clipboard import - from mtPaint, or from something other? */
9729 if ((mode == FS_CLIPBOARD) && (ftype & FTM_EXTEND)) mode = FS_CLIP_FILE;
9730 ftype &= FTM_FTYPE;
9731
9732 /* Prepare layer slot */
9733 if (mode == FS_LAYER_LOAD)
9734 {
9735 lim = layer_table[layers_total].image;
9736 if (!lim) lim = layer_table[layers_total].image =
9737 alloc_layer(0, 0, 1, 0, NULL);
9738 else if (layers_total) mem_free_image(&lim->image_, FREE_IMAGE);
9739 if (!lim) return (FILE_MEM_ERROR);
9740 }
9741
9742 /* Fit scalable image into channel */
9743 if (mode == FS_CHANNEL_LOAD) rw = mem_width , rh = mem_height;
9744
9745 init_ls_settings(&settings, NULL);
9746 settings.req_w = rw;
9747 settings.req_h = rh;
9748 /* Preset delay to -1, to detect animations by its changing */
9749 settings.gif_delay = -1;
9750 #ifdef U_LCMS
9751 /* Set size to -1 when we don't want color profile */
9752 if (!apply_icc || ((mode == FS_CHANNEL_LOAD) ? (MEM_BPP != 3) :
9753 (mode != FS_PNG_LOAD) && (mode != FS_LAYER_LOAD)))
9754 settings.icc_size = -1;
9755 #endif
9756 /* 0th layer load is just an image load */
9757 if ((mode == FS_LAYER_LOAD) && !layers_total) mode = FS_PNG_LOAD;
9758 settings.mode = mode;
9759 settings.ftype = ftype;
9760 settings.pal = pal;
9761 /* Clear hotspot & transparency */
9762 settings.hot_x = settings.hot_y = -1;
9763 settings.xpm_trans = settings.rgb_trans = -1;
9764 /* Be silent if working from memory */
9765 if (mf) settings.silent = TRUE;
9766
9767 /* !!! Use default palette - for now */
9768 mem_pal_copy(pal, mem_pal_def);
9769 settings.colors = mem_pal_def_i;
9770
9771 switch (ftype)
9772 {
9773 default:
9774 case FT_PNG: res0 = load_png(file_name, &settings, mf, FALSE); break;
9775 case FT_GIF: res0 = load_gif(file_name, &settings); break;
9776 #ifdef U_JPEG
9777 case FT_JPEG: res0 = load_jpeg(file_name, &settings); break;
9778 #endif
9779 #ifdef HANDLE_JP2
9780 case FT_JP2:
9781 case FT_J2K: res0 = load_jpeg2000(file_name, &settings); break;
9782 #endif
9783 #ifdef U_TIFF
9784 case FT_TIFF: res0 = load_tiff(file_name, &settings, mf); break;
9785 #endif
9786 #ifdef U_WEBP
9787 case FT_WEBP: res0 = load_webp(file_name, &settings); break;
9788 #endif
9789 case FT_BMP: res0 = load_bmp(file_name, &settings, mf); break;
9790 case FT_XPM: res0 = load_xpm(file_name, &settings); break;
9791 case FT_XBM: res0 = load_xbm(file_name, &settings); break;
9792 case FT_LSS: res0 = load_lss(file_name, &settings); break;
9793 case FT_TGA: res0 = load_tga(file_name, &settings); break;
9794 case FT_PCX: res0 = load_pcx(file_name, &settings); break;
9795 case FT_LBM: res0 = load_lbm(file_name, &settings); break;
9796 case FT_PBM:
9797 case FT_PGM:
9798 case FT_PPM:
9799 case FT_PAM: res0 = load_pnm(file_name, &settings); break;
9800 case FT_PMM: res0 = load_pmm(file_name, &settings, mf); break;
9801 case FT_PIXMAP: res0 = load_pixmap(&settings, mf); break;
9802 case FT_SVG:
9803 #ifdef MAY_HANDLE_SVG
9804 if (svg_check < 0) svg_check = svg_supported();
9805 if (svg_check) res0 = load_svg(file_name, &settings);
9806 else
9807 #endif
9808 res0 = import_svg(file_name, &settings); break;
9809 /* Palette files */
9810 case FT_GPL:
9811 case FT_TXT: res0 = load_txtpal(file_name, &settings); break;
9812 case FT_PAL:
9813 case FT_ACT: res0 = load_rawpal(file_name, &settings); break;
9814 }
9815
9816 /* Consider animated GIF a success */
9817 res = res0 == FILE_HAS_FRAMES ? 1 : res0;
9818 /* Ignore frames beyond first if in-memory (imported clipboard) */
9819 if (mf) res0 = res;
9820
9821 switch (mode)
9822 {
9823 case FS_PNG_LOAD: /* Image */
9824 /* Success, or lib failure with single image - commit load */
9825 if ((res == 1) || (!lim && (res == FILE_LIB_ERROR)))
9826 {
9827 if (!mem_img[CHN_IMAGE] || !undo)
9828 mem_new(settings.width, settings.height,
9829 settings.bpp, 0);
9830 else undo_next_core(UC_DELETE, settings.width,
9831 settings.height, settings.bpp, CMASK_ALL);
9832 memcpy(mem_img, settings.img, sizeof(chanlist));
9833 store_image_extras(&mem_image, &mem_state, &settings);
9834 update_undo(&mem_image);
9835 mem_undo_prepare();
9836 if (lim) layer_copy_from_main(0);
9837 /* Report whether the file is animated or multipage */
9838 res = res0;
9839 if ((res == FILE_HAS_FRAMES) &&
9840 /* If file contains frame delay value... */
9841 ((settings.gif_delay >= 0) ||
9842 /* ...or it cannot be multipage at all... */
9843 !(file_formats[ftype].flags & FF_LAYER)))
9844 res = FILE_HAS_ANIM; /* ...then it's animated */
9845 }
9846 /* Failure */
9847 else
9848 {
9849 mem_free_chanlist(settings.img);
9850 /* If loader managed to delete image before failing */
9851 if (!mem_img[CHN_IMAGE]) create_default_image();
9852 }
9853 break;
9854 case FS_CLIPBOARD: /* Imported clipboard */
9855 if ((res == 1) && mem_clip_alpha && !mem_clip_mask)
9856 {
9857 /* "Alpha" likely means clipboard mask here */
9858 mem_clip_mask = mem_clip_alpha;
9859 mem_clip_alpha = NULL;
9860 memcpy(settings.img, mem_clip.img, sizeof(chanlist));
9861 }
9862 /* Fallthrough */
9863 case FS_CLIP_FILE: /* Clipboard */
9864 /* Convert color transparency to alpha */
9865 tr = settings.bpp == 3 ? settings.rgb_trans : settings.xpm_trans;
9866 if ((res == 1) && (tr >= 0))
9867 {
9868 /* Add alpha channel if no alpha yet */
9869 if (!settings.img[CHN_ALPHA])
9870 {
9871 i = settings.width * settings.height;
9872 /* !!! Create committed */
9873 mem_clip_alpha = malloc(i);
9874 if (mem_clip_alpha)
9875 {
9876 settings.img[CHN_ALPHA] = mem_clip_alpha;
9877 memset(mem_clip_alpha, 255, i);
9878 }
9879 }
9880 if (!settings.img[CHN_ALPHA]) res = FILE_MEM_ERROR;
9881 else mem_mask_colors(settings.img[CHN_ALPHA],
9882 settings.img[CHN_IMAGE], 0, settings.width,
9883 settings.height, settings.bpp, tr, tr);
9884 }
9885 /* Success - accept data */
9886 if (res == 1); /* !!! Clipboard data committed already */
9887 /* Failure needing rollback */
9888 else if (settings.img[CHN_IMAGE])
9889 {
9890 /* !!! Too late to restore previous clipboard */
9891 mem_free_image(&mem_clip, FREE_ALL);
9892 }
9893 break;
9894 case FS_CHANNEL_LOAD:
9895 /* Success - commit load */
9896 if (res == 1)
9897 {
9898 /* Add frame & stuff data into it */
9899 undo_next_core(UC_DELETE, mem_width, mem_height, mem_img_bpp,
9900 CMASK_CURR);
9901 mem_img[mem_channel] = settings.img[CHN_IMAGE];
9902 update_undo(&mem_image);
9903 if (mem_channel == CHN_IMAGE)
9904 store_image_extras(&mem_image, &mem_state, &settings);
9905 mem_undo_prepare();
9906 }
9907 /* Failure */
9908 else free(settings.img[CHN_IMAGE]);
9909 break;
9910 case FS_LAYER_LOAD: /* Layer */
9911 /* Success - commit load */
9912 if (res == 1)
9913 {
9914 mem_alloc_image(0, &lim->image_, settings.width,
9915 settings.height, settings.bpp, 0, NULL);
9916 memcpy(lim->image_.img, settings.img, sizeof(chanlist));
9917 store_image_extras(&lim->image_, &lim->state_, &settings);
9918 update_undo(&lim->image_);
9919 }
9920 /* Failure */
9921 else mem_free_chanlist(settings.img);
9922 break;
9923 case FS_PATTERN_LOAD:
9924 /* Success - rebuild patterns */
9925 if (res == 1) set_patterns(&settings);
9926 free(settings.img[CHN_IMAGE]);
9927 break;
9928 case FS_PALETTE_LOAD:
9929 case FS_PALETTE_DEF:
9930 /* Drop image channels if any */
9931 mem_free_chanlist(settings.img);
9932 /* This "failure" in this context serves as shortcut */
9933 if (res == EXPLODE_FAILED) res = 1;
9934 /* In case of image format, retry as raw palette */
9935 if ((res != 1) && (file_formats[ftype].flags & FF_IMAGE))
9936 res = load_rawpal(file_name, &settings);
9937 /* Utter failure - do nothing */
9938 if ((res != 1) || (settings.colors <= 0));
9939 /* Replace default palette */
9940 else if (mode == FS_PALETTE_DEF)
9941 {
9942 mem_pal_copy(mem_pal_def, pal);
9943 mem_pal_def_i = settings.colors;
9944 }
9945 /* Change current palette */
9946 else
9947 {
9948 mem_undo_next(UNDO_PAL);
9949 mem_pal_copy(mem_pal, pal);
9950 mem_cols = settings.colors;
9951 }
9952 break;
9953 }
9954 free(settings.icc);
9955 return (res);
9956 }
9957
load_image(char * file_name,int mode,int ftype)9958 int load_image(char *file_name, int mode, int ftype)
9959 {
9960 return (load_image_x(file_name, NULL, mode, ftype, 0, 0));
9961 }
9962
load_mem_image(unsigned char * buf,int len,int mode,int ftype)9963 int load_mem_image(unsigned char *buf, int len, int mode, int ftype)
9964 {
9965 memFILE mf;
9966
9967 if (((ftype & FTM_FTYPE) != FT_PIXMAP) /* Special case */ &&
9968 !(file_formats[ftype & FTM_FTYPE].flags & FF_RMEM)) return (-1);
9969 memset(&mf, 0, sizeof(mf));
9970 mf.m.buf = buf; mf.top = mf.m.size = len;
9971 return (load_image_x(NULL, &mf, mode, ftype, 0, 0));
9972 }
9973
load_image_scale(char * file_name,int mode,int ftype,int w,int h)9974 int load_image_scale(char *file_name, int mode, int ftype, int w, int h)
9975 {
9976 return (load_image_x(file_name, NULL, mode, ftype, w, h));
9977 }
9978
9979 // !!! The only allowed modes for now are FS_LAYER_LOAD and FS_EXPLODE_FRAMES
9980 // !!! Load from memblock is not supported yet
load_frames_x(ani_settings * ani,int ani_mode,char * file_name,int mode,int ftype)9981 static int load_frames_x(ani_settings *ani, int ani_mode, char *file_name,
9982 int mode, int ftype)
9983 {
9984 png_color pal[256];
9985
9986
9987 ftype &= FTM_FTYPE;
9988 ani->mode = ani_mode;
9989 init_ls_settings(&ani->settings, NULL);
9990 #ifdef U_LCMS
9991 /* Set size to -1 when we don't want color profile */
9992 /* if (!apply_icc) */ ani->settings.icc_size = -1; // !!! Disable for now
9993 #endif
9994 ani->settings.mode = mode;
9995 ani->settings.ftype = ftype;
9996 ani->settings.pal = pal;
9997 /* Clear hotspot & transparency */
9998 ani->settings.hot_x = ani->settings.hot_y = -1;
9999 ani->settings.xpm_trans = ani->settings.rgb_trans = -1;
10000 /* No load progressbar when exploding frames */
10001 if (mode == FS_EXPLODE_FRAMES) ani->settings.silent = TRUE;
10002
10003 /* !!! Use default palette - for now */
10004 mem_pal_copy(pal, mem_pal_def);
10005 ani->settings.colors = mem_pal_def_i;
10006
10007 switch (ftype)
10008 {
10009 case FT_PNG: return (load_apng_frames(file_name, ani));
10010 case FT_GIF: return (load_gif_frames(file_name, ani));
10011 #ifdef U_TIFF
10012 case FT_TIFF: return (load_tiff_frames(file_name, ani));
10013 #endif
10014 #ifdef U_WEBP
10015 case FT_WEBP: return (load_webp_frames(file_name, ani));
10016 #endif
10017 case FT_PBM:
10018 case FT_PGM:
10019 case FT_PPM:
10020 case FT_PAM: return (load_pnm_frames(file_name, ani));
10021 case FT_PMM: return (load_pmm_frames(file_name, ani, NULL));
10022 }
10023 return (-1);
10024 }
10025
load_frameset(frameset * frames,int ani_mode,char * file_name,int mode,int ftype)10026 int load_frameset(frameset *frames, int ani_mode, char *file_name, int mode,
10027 int ftype)
10028 {
10029 ani_settings ani;
10030 int res;
10031
10032
10033 memset(&ani, 0, sizeof(ani_settings));
10034 res = load_frames_x(&ani, ani_mode, file_name, mode, ftype);
10035
10036 /* Treat out-of-memory error as fatal, to avoid worse things later */
10037 if ((res == FILE_MEM_ERROR) || !ani.fset.cnt)
10038 mem_free_frames(&ani.fset);
10039 /* Pass too-many-frames error along */
10040 else if (res == FILE_TOO_LONG);
10041 /* Consider all other errors partial failures */
10042 else if (res != 1) res = FILE_LIB_ERROR;
10043
10044 /* Just pass the frameset to the outside, for now */
10045 *frames = ani.fset;
10046 return (res);
10047 }
10048
10049 /* Write out the last frame to indexed sequence, and delete it */
write_out_frame(char * file_name,ani_settings * ani,ls_settings * f_set)10050 static int write_out_frame(char *file_name, ani_settings *ani, ls_settings *f_set)
10051 {
10052 ls_settings w_set;
10053 image_frame *frame = ani->fset.frames + ani->fset.cnt - 1;
10054 char new_name[PATHBUF + 32], *tmp;
10055 int n, deftype = ani->desttype, res;
10056
10057
10058 /* Show progress, for unknown final count */
10059 n = nextpow2(ani->cnt);
10060 if (n < 16) n = 16;
10061 progress_update((float)ani->cnt / n);
10062
10063 tmp = strrchr(file_name, DIR_SEP);
10064 if (!tmp) tmp = file_name;
10065 else tmp++;
10066 file_in_dir(new_name, ani->destdir, tmp, PATHBUF);
10067 tmp = new_name + strlen(new_name);
10068 sprintf(tmp, ".%03d", ani->cnt);
10069
10070 if (f_set) w_set = *f_set;
10071 else
10072 {
10073 init_ls_settings(&w_set, NULL);
10074 memcpy(w_set.img, frame->img, sizeof(chanlist));
10075 w_set.width = frame->width;
10076 w_set.height = frame->height;
10077 w_set.pal = frame->pal ? frame->pal : ani->fset.pal;
10078 w_set.bpp = frame->bpp;
10079 w_set.colors = frame->cols;
10080 w_set.xpm_trans = frame->trans;
10081 }
10082 w_set.ftype = deftype;
10083 w_set.silent = TRUE;
10084 if (!(file_formats[deftype].flags & FF_SAVE_MASK_FOR(w_set)))
10085 {
10086 w_set.ftype = FT_PNG;
10087 ani->miss++;
10088 }
10089 w_set.mode = ani->mode; // Only FS_EXPLODE_FRAMES for now
10090
10091 res = ani->error = save_image(new_name, &w_set);
10092 if (!res) ani->cnt++;
10093
10094 if (f_set) // Delete
10095 {
10096 mem_free_chanlist(f_set->img);
10097 memset(f_set->img, 0, sizeof(chanlist));
10098 }
10099 // Set for deletion
10100 else frame->flags |= FM_NUKE;
10101 return (res);
10102 }
10103
warn_miss(int miss,int total,int ftype)10104 static void warn_miss(int miss, int total, int ftype)
10105 {
10106 char *txt = g_strdup_printf(
10107 __("%d out of %d frames could not be saved as %s - saved as PNG instead"),
10108 miss, total, file_formats[ftype].name);
10109 alert_box(_("Warning"), txt, "", NULL); // Not an error
10110 g_free(txt);
10111 }
10112
explode_frames(char * dest_path,int ani_mode,char * file_name,int ftype,int desttype)10113 int explode_frames(char *dest_path, int ani_mode, char *file_name, int ftype,
10114 int desttype)
10115 {
10116 ani_settings ani;
10117 int res;
10118
10119
10120 memset(&ani, 0, sizeof(ani_settings));
10121 ani.desttype = desttype;
10122 ani.destdir = dest_path;
10123
10124 progress_init(_("Explode frames"), 0);
10125 progress_update(0.0);
10126 res = load_frames_x(&ani, ani_mode, file_name, FS_EXPLODE_FRAMES, ftype);
10127 progress_update(1.0);
10128 if (res == 1); // Everything went OK
10129 else if (res == FILE_MEM_ERROR); // Report memory problem
10130 else if (ani.error) // Sequence write failure - soft or hard?
10131 res = ani.cnt ? FILE_EXP_BREAK : EXPLODE_FAILED;
10132 else if (ani.cnt) // Failed to read some middle frame
10133 res = FILE_LIB_ERROR;
10134 mem_free_frames(&ani.fset);
10135 progress_end();
10136
10137 if (ani.miss && (res == 1))
10138 warn_miss(ani.miss, ani.cnt, ani.desttype & FTM_FTYPE);
10139
10140 return (res);
10141 }
10142
export_undo(char * file_name,ls_settings * settings)10143 int export_undo(char *file_name, ls_settings *settings)
10144 {
10145 char new_name[PATHBUF + 32];
10146 int start = mem_undo_done, res = 0, lenny, i, j;
10147 int deftype = settings->ftype, miss = 0;
10148
10149 strncpy(new_name, file_name, PATHBUF);
10150 lenny = strlen( file_name );
10151
10152 ls_init("UNDO", 1);
10153 settings->silent = TRUE;
10154
10155 for (j = 0; j < 2; j++)
10156 {
10157 for (i = 1; i <= start + 1; i++)
10158 {
10159 if (!res && (!j ^ (settings->mode == FS_EXPORT_UNDO)))
10160 {
10161 progress_update((float)i / (start + 1));
10162 settings->ftype = deftype;
10163 if (!(file_formats[deftype].flags & FF_SAVE_MASK))
10164 {
10165 settings->ftype = FT_PNG;
10166 miss++;
10167 }
10168 sprintf(new_name + lenny, "%03i.%s", i,
10169 file_formats[settings->ftype].ext);
10170 memcpy(settings->img, mem_img, sizeof(chanlist));
10171 settings->pal = mem_pal;
10172 settings->width = mem_width;
10173 settings->height = mem_height;
10174 settings->bpp = mem_img_bpp;
10175 settings->colors = mem_cols;
10176 res = save_image(new_name, settings);
10177 }
10178 if (!j) /* Goto first image */
10179 {
10180 if (mem_undo_done > 0) mem_do_undo(FALSE);
10181 }
10182 else if (mem_undo_done < start) mem_do_undo(TRUE);
10183 }
10184 }
10185
10186 progress_end();
10187
10188 if (miss && !res) warn_miss(miss, mem_undo_done, deftype);
10189
10190 return (res);
10191 }
10192
export_ascii(char * file_name)10193 int export_ascii ( char *file_name )
10194 {
10195 char ch[16] = " .,:;+=itIYVXRBM";
10196 int i, j;
10197 unsigned char pix;
10198 FILE *fp;
10199
10200 if ((fp = fopen(file_name, "w")) == NULL) return -1;
10201
10202 for ( j=0; j<mem_height; j++ )
10203 {
10204 for ( i=0; i<mem_width; i++ )
10205 {
10206 pix = mem_img[CHN_IMAGE][ i + mem_width*j ];
10207 fprintf(fp, "%c", ch[pix % 16]);
10208 }
10209 fprintf(fp, "\n");
10210 }
10211 fclose(fp);
10212
10213 return 0;
10214 }
10215
do_detect_format(char * name,FILE * fp)10216 static int do_detect_format(char *name, FILE *fp)
10217 {
10218 unsigned char buf[66], *stop;
10219 int i;
10220
10221 i = fread(buf, 1, 64, fp);
10222 buf[64] = '\0';
10223
10224 /* Check all unambiguous signatures */
10225 if (!memcmp(buf, "\x89PNG", 4)) return (FT_PNG);
10226 if (!memcmp(buf, "GIF8", 4)) return (FT_GIF);
10227 if (!memcmp(buf, "\xFF\xD8", 2))
10228 #ifdef U_JPEG
10229 return (FT_JPEG);
10230 #else
10231 return (FT_NONE);
10232 #endif
10233 if (!memcmp(buf, "\0\0\0\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A", 12))
10234 #ifdef HANDLE_JP2
10235 return (FT_JP2);
10236 #else
10237 return (FT_NONE);
10238 #endif
10239 if (!memcmp(buf, "\xFF\x4F", 2))
10240 #ifdef HANDLE_JP2
10241 return (FT_J2K);
10242 #else
10243 return (FT_NONE);
10244 #endif
10245 if (!memcmp(buf, "II", 2) || !memcmp(buf, "MM", 2))
10246 #ifdef U_TIFF
10247 return (FT_TIFF);
10248 #else
10249 return (FT_NONE);
10250 #endif
10251 if (!memcmp(buf, "RIFF", 4) && !memcmp(buf + 8, "WEBP", 4))
10252 #ifdef U_WEBP
10253 return (FT_WEBP);
10254 #else
10255 return (FT_NONE);
10256 #endif
10257 if (!memcmp(buf, "FORM", 4) && (!memcmp(buf + 8, "ILBM", 4) ||
10258 !memcmp(buf + 8, "PBM ", 4))) return (FT_LBM);
10259 if (!memcmp(buf, "BM", 2) || !memcmp(buf, "BA", 2)) return (FT_BMP);
10260
10261 if (!memcmp(buf, "\x3D\xF3\x13\x14", 4)) return (FT_LSS);
10262
10263 if (!memcmp(buf, PMM_ID1, 12)) return (FT_PMM);
10264
10265 if (!memcmp(buf, "P7", 2)) return (FT_PAM);
10266 if ((buf[0] == 'P') && (buf[1] >= '1') && (buf[1] <= '6'))
10267 {
10268 static const unsigned char pnms[3] = { FT_PBM, FT_PGM, FT_PPM };
10269 return (pnms[(buf[1] - '1') % 3]);
10270 }
10271
10272 if (!memcmp(buf, "GIMP Palette", strlen("GIMP Palette"))) return (FT_GPL);
10273
10274 /* Check layers signature and version */
10275 if (!memcmp(buf, LAYERS_HEADER, strlen(LAYERS_HEADER)))
10276 {
10277 stop = strchr(buf, '\n');
10278 if (!stop || (stop - buf > 32)) return (FT_NONE);
10279 i = atoi(++stop);
10280 if (i == 1) return (FT_LAYERS1);
10281 /* !!! Not implemented yet */
10282 // if (i == 2) return (FT_LAYERS2);
10283 return (FT_NONE);
10284 }
10285
10286 /* Assume generic XML is SVG */
10287 i = 0; sscanf(buf, " <?xml %n", &i);
10288 if (!i) sscanf(buf, " <svg%n", &i);
10289 if (!i) sscanf(buf, " <!DOCTYPE svg%n", &i);
10290 if (i) return (FT_SVG);
10291
10292 /* Discern PCX from TGA */
10293 while (buf[0] == 10)
10294 {
10295 if (buf[1] > 5) break;
10296 if (buf[1] > 1) return (FT_PCX);
10297 if (buf[2] != 1) break; // Uncompressed PCX is nonstandard
10298 /* Ambiguity - look at name as a last resort
10299 * Bias to PCX - TGAs usually have 0th byte = 0 */
10300 stop = strrchr(name, '.');
10301 if (!stop) return (FT_PCX);
10302 if (!strcasecmp(stop + 1, "tga")) break;
10303 return (FT_PCX);
10304 }
10305
10306 /* Check if this is TGA */
10307 if ((buf[1] < 2) && (buf[2] < 12) && ((1 << buf[2]) & 0x0E0F))
10308 return (FT_TGA);
10309
10310 /* Simple check for "txt" palette format */
10311 if ((sscanf(buf, "%i", &i) == 1) && (i > 0) && (i <= 256)) return (FT_TXT);
10312
10313 /* Simple check for XPM */
10314 stop = strstr(buf, "XPM");
10315 if (stop)
10316 {
10317 i = stop - buf;
10318 stop = strchr(buf, '\n');
10319 if (!stop || (stop - buf > i)) return (FT_XPM);
10320 }
10321 /* Check possibility of XBM by absence of control chars */
10322 for (i = 0; buf[i] && (buf[i] != '\n'); i++)
10323 {
10324 if (ISCNTRL(buf[i])) return (FT_NONE);
10325 }
10326 return (FT_XBM);
10327 }
10328
detect_file_format(char * name,int need_palette)10329 int detect_file_format(char *name, int need_palette)
10330 {
10331 FILE *fp;
10332 int i, f;
10333
10334 if (!(fp = fopen(name, "rb"))) return (-1);
10335 i = do_detect_format(name, fp);
10336 f = file_formats[i].flags;
10337 if (need_palette)
10338 {
10339 /* Check for PAL/ACT raw format */
10340 if (!(f & (FF_16 | FF_256 | FF_PALETTE)))
10341 {
10342 f_long l;
10343 fseek(fp, 0, SEEK_END);
10344 l = ftell(fp);
10345 i = (l > 0) && (l <= 768) && !(l % 3) ? FT_PAL : FT_NONE;
10346 }
10347 }
10348 else if (!(f & (FF_IMAGE | FF_LAYER))) i = FT_NONE;
10349 fclose(fp);
10350 return (i);
10351 }
10352
10353 // Can this file be opened for reading?
10354
10355 /* 0 = readable, -1 = not exists, 1 = error, 2 = a directory */
valid_file(char * filename)10356 int valid_file(char *filename)
10357 {
10358 FILE *fp = fopen(filename, "r");
10359 if (!fp) return (errno == ENOENT ? -1 : 1);
10360 else
10361 {
10362 struct stat buf;
10363 int d = fstat(fileno(fp), &buf) ? 1 : S_ISDIR(buf.st_mode) ? 2 : 0;
10364 fclose(fp);
10365 return (d);
10366 }
10367 }
10368