1 /* memory.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 #include "global.h"
21 #undef _
22 #define _(X) X
23
24 #include "mygtk.h"
25 #include "memory.h"
26 #include "vcode.h"
27 #include "ani.h"
28 #include "png.h"
29 #include "mainwindow.h"
30 #include "otherwindow.h"
31 #include "layer.h"
32 #include "inifile.h"
33 #include "canvas.h"
34 #include "prefs.h"
35 #include "channels.h"
36 #include "toolbar.h"
37 #include "viewer.h"
38 #include "csel.h"
39 #include "thread.h"
40
41
42 grad_info gradient[NUM_CHANNELS]; // Per-channel gradients
43 double grad_path, grad_x0, grad_y0; // Stroke gradient temporaries
44 grad_map graddata[NUM_CHANNELS + 1]; // RGB + per-channel gradient data
45 grad_store gradbytes; // Storage space for custom gradients
46 int grad_opacity; // Preview opacity
47
48 /// Vectorized low-level drawing functions
49
50 void (*put_pixel)(int x, int y) = put_pixel_def;
51 void (*put_pixel_row)(int x, int y, int len, unsigned char *xsel) = put_pixel_row_def;
52
53 #define ROW_BUFLEN 2048 /* Preferred length of internal row buffer */
54
55 /// Bayer ordered dithering
56
57 const unsigned char bayer[16] = {
58 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
59 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 };
60
61 /// Tint tool - contributed by Dmitry Groshev, January 2006
62
63 int tint_mode[3]; // [0] = off/on, [1] = add/subtract, [2] = button (none, left, middle, right : 0-3)
64
65 int mem_cselect;
66 int mem_blend;
67 int mem_unmask;
68 int mem_gradient;
69
70 int paint_gamma;
71
72 /// BLEND MODE SETTINGS
73
74 int blend_mode = BLEND_HUE;
75 int blend_src;
76
77 /// FLOOD FILL SETTINGS
78
79 double flood_step;
80 int flood_cube, flood_img, flood_slide;
81
82 int smudge_mode;
83
84 /// QUANTIZATION SETTINGS
85
86 int quan_sqrt; // "Diameter based weighting" - use sqrt of pixel count
87
88 /// IMAGE
89
90 int mem_undo_depth = DEF_UNDO; // Current undo depth
91 image_info mem_image; // Current image
92 image_info mem_clip; // Current clipboard
93 image_state mem_state; // Current edit settings
94
95 int mem_background = 180; // Non paintable area
96
97 unsigned char mem_brushes[PATCH_WIDTH * PATCH_HEIGHT * 3];
98 // Preset brushes screen memory
99 int mem_clip_x = -1, mem_clip_y = -1; // Clipboard location on canvas
100 int mem_nudge = -1; // Nudge pixels per SHIFT+Arrow key during selection/paste
101
102 transform_state mem_bcsp[2];
103
104 /// UNDO ENGINE
105
106 #define TILE_SIZE 64
107 #define TILE_SHIFT 6
108 #define MAX_TILEMAP ((((MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 7) / 8) * \
109 ((MAX_HEIGHT + TILE_SIZE - 1) / TILE_SIZE))
110 #define UF_TILED 0x01
111 #define UF_FLAT 0x02
112 #define UF_SIZED 0x04
113 #define UF_ORIG 0x08 /* Unmodified state */
114 #define UF_ACCUM 0x10 /* Cumulative */
115
116 int mem_undo_limit; // Max MB memory allocation limit
117 int mem_undo_common; // Percent of undo space in common arena
118 int mem_undo_opacity; // Use previous image for opacity calculations?
119
120 int mem_undo_fail; // Undo space shortfall
121
122 typedef struct {
123 unsigned int n, size, freecnt;
124 void *datastore, *freelist;
125 } memchunks;
126
127 #define UNDO_STORESIZE 1023 /* Leave space for memory block header */
128
129 static memchunks undo_datastore = { UNDO_STORESIZE, sizeof(undo_data) };
130 static memchunks undo_items = { DEF_UNDO, sizeof(undo_item) };
131
132 /// PATTERNS
133
134 int pattern_B; // Let colour B have its own pattern
135 unsigned char *mem_pattern; // Original 0-1 pattern
136 unsigned char mem_col_pat[8 * 8]; // Indexed 8x8 colourised pattern using colours A & B
137 unsigned char mem_col_pat24[8 * 8 * 3]; // RGB 8x8 colourised pattern using colours A & B
138
139 /// TOOLS
140
141 tool_info tool_state = { TOOL_SQUARE, TOOL_SQUARE, { 1, 1, 255 } };
142 // Type, brush, size/flow/opacity
143 int pen_down; // Are we drawing? - Used to see if we need to do an UNDO
144 int tool_ox, tool_oy; // Previous tool coords - used by continuous mode
145 int mem_continuous; // Area we painting the static shapes continuously?
146
147
148
149 /// PALETTE
150
151 int mem_pal_id_c, mem_pal_ab_c; // Text & A/B highlight colors
152
153 unsigned char mem_pals[PALETTE_WIDTH * PALETTE_HEIGHT * 3];
154 // RGB screen memory holding current palette
155 int mem_brush_list[NUM_BRUSHES][3] = { // Preset brushes parameters
156 { TOOL_SPRAY, 5, 1 }, { TOOL_SPRAY, 7, 1 }, { TOOL_SPRAY, 9, 2 },
157 { TOOL_SPRAY, 13, 2 }, { TOOL_SPRAY, 15, 3 }, { TOOL_SPRAY, 19, 3 },
158 { TOOL_SPRAY, 23, 4 }, { TOOL_SPRAY, 27, 5 }, { TOOL_SPRAY, 31, 6 },
159
160 { TOOL_SPRAY, 5, 5 }, { TOOL_SPRAY, 7, 7 }, { TOOL_SPRAY, 9, 9 },
161 { TOOL_SPRAY, 13, 13 }, { TOOL_SPRAY, 15, 15 }, { TOOL_SPRAY, 19, 19 },
162 { TOOL_SPRAY, 23, 23 }, { TOOL_SPRAY, 27, 27 }, { TOOL_SPRAY, 31, 31 },
163
164 { TOOL_SPRAY, 5, 15 }, { TOOL_SPRAY, 7, 21 }, { TOOL_SPRAY, 9, 27 },
165 { TOOL_SPRAY, 13, 39 }, { TOOL_SPRAY, 15, 45 }, { TOOL_SPRAY, 19, 57 },
166 { TOOL_SPRAY, 23, 69 }, { TOOL_SPRAY, 27, 81 }, { TOOL_SPRAY, 31, 93 },
167
168 { TOOL_CIRCLE, 3, -1 }, { TOOL_CIRCLE, 5, -1 }, { TOOL_CIRCLE, 7, -1 },
169 { TOOL_CIRCLE, 9, -1 }, { TOOL_CIRCLE, 13, -1 }, { TOOL_CIRCLE, 17, -1 },
170 { TOOL_CIRCLE, 21, -1 }, { TOOL_CIRCLE, 25, -1 }, { TOOL_CIRCLE, 31, -1 },
171
172 { TOOL_SQUARE, 1, -1 }, { TOOL_SQUARE, 2, -1 }, { TOOL_SQUARE, 3, -1 },
173 { TOOL_SQUARE, 4, -1 }, { TOOL_SQUARE, 8, -1 }, { TOOL_SQUARE, 12, -1 },
174 { TOOL_SQUARE, 16, -1 }, { TOOL_SQUARE, 24, -1 }, { TOOL_SQUARE, 32, -1 },
175
176 { TOOL_SLASH, 3, -1 }, { TOOL_SLASH, 5, -1 }, { TOOL_SLASH, 7, -1 },
177 { TOOL_SLASH, 9, -1 }, { TOOL_SLASH, 13, -1 }, { TOOL_SLASH, 17, -1 },
178 { TOOL_SLASH, 21, -1 }, { TOOL_SLASH, 25, -1 }, { TOOL_SLASH, 31, -1 },
179
180 { TOOL_BACKSLASH, 3, -1 }, { TOOL_BACKSLASH, 5, -1 }, { TOOL_BACKSLASH, 7, -1 },
181 { TOOL_BACKSLASH, 9, -1 }, { TOOL_BACKSLASH, 13, -1 }, { TOOL_BACKSLASH, 17, -1 },
182 { TOOL_BACKSLASH, 21, -1 }, { TOOL_BACKSLASH, 25, -1 }, { TOOL_BACKSLASH, 31, -1 },
183
184 { TOOL_VERTICAL, 3, -1 }, { TOOL_VERTICAL, 5, -1 }, { TOOL_VERTICAL, 7, -1 },
185 { TOOL_VERTICAL, 9, -1 }, { TOOL_VERTICAL, 13, -1 }, { TOOL_VERTICAL, 17, -1 },
186 { TOOL_VERTICAL, 21, -1 }, { TOOL_VERTICAL, 25, -1 }, { TOOL_VERTICAL, 31, -1 },
187
188 { TOOL_HORIZONTAL, 3, -1 }, { TOOL_HORIZONTAL, 5, -1 }, { TOOL_HORIZONTAL, 7, -1 },
189 { TOOL_HORIZONTAL, 9, -1 }, { TOOL_HORIZONTAL, 13, -1 }, { TOOL_HORIZONTAL, 17, -1 },
190 { TOOL_HORIZONTAL, 21, -1 }, { TOOL_HORIZONTAL, 25, -1 }, { TOOL_HORIZONTAL, 31, -1 },
191
192 };
193
194 int mem_pal_def_i = 256; // Items in default palette
195
196 png_color mem_pal_def[256]={ // Default palette entries for new image
197 /// All RGB in 3 bits per channel. i.e. 0..7 - multiply by 255/7 for full RGB ..
198 /// .. or: int lookup[8] = {0, 36, 73, 109, 146, 182, 219, 255};
199
200 /// Primary colours = 8
201
202 {0,0,0}, {7,0,0}, {0,7,0}, {7,7,0}, {0,0,7}, {7,0,7}, {0,7,7}, {7,7,7},
203
204 /// Primary fades to black: 7 x 6 = 42
205
206 {6,6,6}, {5,5,5}, {4,4,4}, {3,3,3}, {2,2,2}, {1,1,1},
207 {6,0,0}, {5,0,0}, {4,0,0}, {3,0,0}, {2,0,0}, {1,0,0},
208 {0,6,0}, {0,5,0}, {0,4,0}, {0,3,0}, {0,2,0}, {0,1,0},
209 {6,6,0}, {5,5,0}, {4,4,0}, {3,3,0}, {2,2,0}, {1,1,0},
210 {0,0,6}, {0,0,5}, {0,0,4}, {0,0,3}, {0,0,2}, {0,0,1},
211 {6,0,6}, {5,0,5}, {4,0,4}, {3,0,3}, {2,0,2}, {1,0,1},
212 {0,6,6}, {0,5,5}, {0,4,4}, {0,3,3}, {0,2,2}, {0,1,1},
213
214 /// Shading triangles: 6 x 21 = 126
215 /// RED
216 {7,6,6}, {6,5,5}, {5,4,4}, {4,3,3}, {3,2,2}, {2,1,1},
217 {7,5,5}, {6,4,4}, {5,3,3}, {4,2,2}, {3,1,1},
218 {7,4,4}, {6,3,3}, {5,2,2}, {4,1,1},
219 {7,3,3}, {6,2,2}, {5,1,1},
220 {7,2,2}, {6,1,1},
221 {7,1,1},
222
223 /// GREEN
224 {6,7,6}, {5,6,5}, {4,5,4}, {3,4,3}, {2,3,2}, {1,2,1},
225 {5,7,5}, {4,6,4}, {3,5,3}, {2,4,2}, {1,3,1},
226 {4,7,4}, {3,6,3}, {2,5,2}, {1,4,1},
227 {3,7,3}, {2,6,2}, {1,5,1},
228 {2,7,2}, {1,6,1},
229 {1,7,1},
230
231 /// BLUE
232 {6,6,7}, {5,5,6}, {4,4,5}, {3,3,4}, {2,2,3}, {1,1,2},
233 {5,5,7}, {4,4,6}, {3,3,5}, {2,2,4}, {1,1,3},
234 {4,4,7}, {3,3,6}, {2,2,5}, {1,1,4},
235 {3,3,7}, {2,2,6}, {1,1,5},
236 {2,2,7}, {1,1,6},
237 {1,1,7},
238
239 /// YELLOW (red + green)
240 {7,7,6}, {6,6,5}, {5,5,4}, {4,4,3}, {3,3,2}, {2,2,1},
241 {7,7,5}, {6,6,4}, {5,5,3}, {4,4,2}, {3,3,1},
242 {7,7,4}, {6,6,3}, {5,5,2}, {4,4,1},
243 {7,7,3}, {6,6,2}, {5,5,1},
244 {7,7,2}, {6,6,1},
245 {7,7,1},
246
247 /// MAGENTA (red + blue)
248 {7,6,7}, {6,5,6}, {5,4,5}, {4,3,4}, {3,2,3}, {2,1,2},
249 {7,5,7}, {6,4,6}, {5,3,5}, {4,2,4}, {3,1,3},
250 {7,4,7}, {6,3,6}, {5,2,5}, {4,1,4},
251 {7,3,7}, {6,2,6}, {5,1,5},
252 {7,2,7}, {6,1,6},
253 {7,1,7},
254
255 /// CYAN (blue + green)
256 {6,7,7}, {5,6,6}, {4,5,5}, {3,4,4}, {2,3,3}, {1,2,2},
257 {5,7,7}, {4,6,6}, {3,5,5}, {2,4,4}, {1,3,3},
258 {4,7,7}, {3,6,6}, {2,5,5}, {1,4,4},
259 {3,7,7}, {2,6,6}, {1,5,5},
260 {2,7,7}, {1,6,6},
261 {1,7,7},
262
263
264 /// Scales: 11 x 6 = 66
265
266 /// RGB
267 {7,6,5}, {6,5,4}, {5,4,3}, {4,3,2}, {3,2,1}, {2,1,0},
268 {7,5,4}, {6,4,3}, {5,3,2}, {4,2,1}, {3,1,0},
269
270 /// RBG
271 {7,5,6}, {6,4,5}, {5,3,4}, {4,2,3}, {3,1,2}, {2,0,1},
272 {7,4,5}, {6,3,4}, {5,2,3}, {4,1,2}, {3,0,1},
273
274 /// BRG
275 {6,5,7}, {5,4,6}, {4,3,5}, {3,2,4}, {2,1,3}, {1,0,2},
276 {5,4,7}, {4,3,6}, {3,2,5}, {2,1,4}, {1,0,3},
277
278 /// BGR
279 {5,6,7}, {4,5,6}, {3,4,5}, {2,3,4}, {1,2,3}, {0,1,2},
280 {4,5,7}, {3,4,6}, {2,3,5}, {1,2,4}, {0,1,3},
281
282 /// GBR
283 {5,7,6}, {4,6,5}, {3,5,4}, {2,4,3}, {1,3,2}, {0,2,1},
284 {4,7,5}, {3,6,4}, {2,5,3}, {1,4,2}, {0,3,1},
285
286 /// GRB
287 {6,7,5}, {5,6,4}, {4,5,3}, {3,4,2}, {2,3,1}, {1,2,0},
288 {5,7,4}, {4,6,3}, {3,5,2}, {2,4,1}, {1,3,0},
289
290 /// Misc
291 {7,5,0}, {6,4,0}, {5,3,0}, {4,2,0}, // Oranges
292 {7,0,5}, {6,0,4}, {5,0,3}, {4,0,2}, // Red Pink
293 {0,5,7}, {0,4,6}, {0,3,5}, {0,2,4}, // Blues
294 {0,0,0}, {0,0,0}
295
296 /// End: Primary (8) + Fades (42) + Shades (126) + Scales (66) + Misc (14) = 256
297 };
298
299 /// FONT FOR PALETTE WINDOW
300
301 #define B8(A,B,C,D,E,F,G,H) (A|B<<1|C<<2|D<<3|E<<4|F<<5|G<<6|H<<7)
302
303 static unsigned char mem_cross[PALETTE_CROSS_H] = {
304 B8( 1,1,0,0,0,0,1,1 ),
305 B8( 1,1,1,0,0,1,1,1 ),
306 B8( 0,1,1,1,1,1,1,0 ),
307 B8( 0,0,1,1,1,1,0,0 ),
308 B8( 0,0,1,1,1,1,0,0 ),
309 B8( 0,1,1,1,1,1,1,0 ),
310 B8( 1,1,1,0,0,1,1,1 ),
311 B8( 1,1,0,0,0,0,1,1 )
312 };
313
314 #include "graphics/xbm_n7x7.xbm"
315 #if (PALETTE_DIGIT_W != xbm_n7x7_width) || (PALETTE_DIGIT_H * 10 != xbm_n7x7_height)
316 #error "Mismatched palette-window font"
317 #endif
318
319 /* While a number of unwieldy allocation APIs is provided by GLib, it's better
320 * to do it the right way once, than constantly invent workarounds - WJ */
321
322 #define WJMEM_DEFINCR 16384
323 #define WJMEM_RESERVED 64
324 #define WJMEM_DEFSIZE (WJMEM_DEFINCR - WJMEM_RESERVED)
325
wjmemnew(int minsize,int incr)326 wjmem *wjmemnew(int minsize, int incr)
327 {
328 wjmem *mem;
329
330 if (incr <= 0) incr = WJMEM_DEFINCR;
331 if (minsize <= (int)sizeof(wjmem)) minsize = WJMEM_DEFSIZE;
332 mem = calloc(1, minsize);
333 if (mem)
334 {
335 mem->block = (char *)mem;
336 mem->here = sizeof(wjmem);
337 mem->size = mem->minsize = minsize;
338 mem->incr = incr;
339 }
340 return (mem);
341 }
342
wjmemfree(wjmem * mem)343 void wjmemfree(wjmem *mem)
344 {
345 char *this, *next;
346
347 if (!mem) return;
348 for (this = mem->block; this != (char *)mem; this = next)
349 {
350 next = *(char **)this;
351 free(this);
352 }
353 free(mem);
354 }
355
wjmalloc(wjmem * mem,int size,int align)356 void *wjmalloc(wjmem *mem, int size, int align)
357 {
358 char *dest;
359 unsigned int sz, ds;
360
361 align += !align; // 0 -> 1
362 dest = mem->block + mem->here;
363 dest = ALIGNED(dest, align);
364 ds = dest - mem->block + size;
365 if (ds > mem->size)
366 {
367 sz = mem->minsize;
368 ds = sizeof(char *) + align + size;
369 if (sz < ds)
370 {
371 ds += WJMEM_RESERVED + mem->incr - 1;
372 sz = ds - ds % mem->incr - WJMEM_RESERVED;
373 }
374 dest = calloc(1, sz);
375 if (!dest) return (NULL);
376 *(char **)dest = mem->block;
377 mem->block = dest;
378 mem->size = sz;
379 dest += sizeof(char *);
380 dest = ALIGNED(dest, align);
381 ds = dest - mem->block + size;
382 }
383 mem->here = ds;
384 return ((void *)dest);
385 }
386
387 /* Simple doubling allocator */
388
getmemx2(memx2 * mem,size_t length)389 size_t getmemx2(memx2 *mem, size_t length)
390 {
391 size_t s = mem->size - mem->here;
392
393 if (length > s)
394 {
395 size_t l = mem->here + length, l2 = mem->size * 2;
396 unsigned char *tmp = NULL;
397
398 if ((l2 > l) && (l2 <= MEMX2_MAX)) tmp = realloc(mem->buf, l2);
399 if (!tmp && (l <= MEMX2_MAX)) tmp = realloc(mem->buf, l2 = l);
400 if (!tmp) return (s);
401 mem->buf = tmp;
402 mem->size = l2;
403 }
404 return (length);
405 }
406
addstr(memx2 * mem,char * s,int bk)407 void addstr(memx2 *mem, char *s, int bk)
408 {
409 int l;
410
411 if ((l = getmemx2(mem, strlen(s) + 1)))
412 {
413 memcpy(mem->buf + mem->here, s, l);
414 mem->buf[(l += mem->here) - 1] = '\0';
415 mem->here = l - bk;
416 }
417 }
418
addchars(memx2 * mem,int c,int l)419 void addchars(memx2 *mem, int c, int l)
420 {
421 l = getmemx2(mem, l);
422 memset(mem->buf + mem->here, c, l);
423 mem->here += l;
424 }
425
426 /* Calculate optimal number of objects in a memory chunk */
objcount(unsigned int n,unsigned int size,unsigned int hsize)427 static inline unsigned int objcount(unsigned int n, unsigned int size,
428 unsigned int hsize)
429 {
430 n = nextpow2(n * size + hsize + WJMEM_RESERVED);
431 if (n < WJMEM_DEFINCR) n = WJMEM_DEFINCR;
432 return ((n - hsize - WJMEM_RESERVED) / size);
433 }
434
newchunk(memchunks * mem)435 static void *newchunk(memchunks *mem)
436 {
437 void *node;
438
439 if ((node = mem->freelist))
440 {
441 mem->freelist = *(void **)node;
442 *(void **)node = NULL; // Clear
443 }
444 else
445 {
446 if (!mem->freecnt)
447 {
448 unsigned int n = objcount(mem->n, mem->size, 0);
449 node = calloc(n, mem->size);
450 if (!node) return (NULL);
451 mem->datastore = node;
452 mem->freecnt = n;
453 }
454 /* Datastores are never freed, so pointer is movable */
455 node = mem->datastore;
456 mem->datastore += mem->size;
457 mem->freecnt--;
458 }
459 return (node);
460 }
461
freechunk(memchunks * mem,void * chunk)462 static inline void freechunk(memchunks *mem, void *chunk)
463 {
464 *(void **)chunk = mem->freelist;
465 mem->freelist = chunk;
466 }
467
468 char MEM_NONE_[1]; /* Nothing is located here :-) */
469
470 /* This allocates several memory chunks in one block - making it one single
471 * point of allocation failure, and needing just a single free() later on.
472 * On Windows, allocations aren't guaranteed to be double-aligned, so
473 * MA_ALIGN_DOUBLE flag is necessary there unless no chunks contain doubles. */
multialloc(int flags,void * ptr,int size,...)474 void *multialloc(int flags, void *ptr, int size, ...)
475 {
476 va_list args;
477 void *res;
478 char *tmp;
479 size_t tsz, sz = size, align = 0;
480
481
482 if ((flags & MA_ALIGN_MASK) == MA_ALIGN_DOUBLE)
483 align = sizeof(double) - 1;
484
485 va_start(args, size);
486 while (va_arg(args, void *))
487 {
488 sz = (sz + align) & ~align;
489 sz += va_arg(args, int);
490 }
491 va_end(args);
492 if (!sz && (flags & MA_FLAG_NONE)) return (MEM_NONE);
493 if (align) sz += align + 1;
494 tmp = res = calloc(1, sz);
495 if (res)
496 {
497 tmp = ALIGNED(tmp, align + 1);
498 sz = 0; tsz = size;
499 va_start(args, size);
500 while (TRUE)
501 {
502 if (tsz || !(flags & MA_SKIP_ZEROSIZE))
503 *(void **)ptr = (void *)(tmp + sz);
504
505 if (!(ptr = va_arg(args, void *))) break;
506
507 sz = (sz + tsz + align) & ~align;
508 tsz = va_arg(args, int);
509 }
510 va_end(args);
511 }
512 return (res);
513 }
514
frameset_realloc(frameset * fset)515 static int frameset_realloc(frameset *fset)
516 {
517 image_frame *tmp;
518 int n;
519
520 /* Next power of 2 */
521 n = nextpow2(fset->cnt);
522 if (n < FRAMES_MIN) n = FRAMES_MIN;
523 if (n == fset->max) return (TRUE);
524 tmp = realloc(fset->frames, n * sizeof(image_frame));
525 if (!tmp) return (FALSE);
526 fset->frames = tmp;
527 fset->max = n;
528 fset->size = 0; // Recalculate it later
529 return (TRUE);
530 }
531
532 /* Add one more frame to a frameset */
mem_add_frame(frameset * fset,int w,int h,int bpp,int cmask,png_color * pal)533 int mem_add_frame(frameset *fset, int w, int h, int bpp, int cmask, png_color *pal)
534 {
535 image_frame *frm;
536 unsigned char *res;
537 size_t l, sz = (size_t)w * h;
538 int i;
539
540 /* Extend frames array if necessary */
541 if (fset->cnt >= fset->max)
542 {
543 if ((fset->cnt >= FRAMES_MAX) || !frameset_realloc(fset))
544 return (FALSE);
545 }
546
547 /* Initialize the frame */
548 frm = fset->frames + fset->cnt;
549 memset(frm, 0, sizeof(image_frame));
550 frm->width = w;
551 frm->height = h;
552 frm->bpp = bpp;
553
554 /* Allocate channels */
555 l = sz * bpp;
556 res = MEM_NONE;
557 for (i = CHN_IMAGE; res && (i < NUM_CHANNELS); i++)
558 {
559 if (cmask & CMASK_FOR(i))
560 res = frm->img[i] = malloc(l);
561 l = sz;
562 }
563
564 /* Allocate palette if it differs from default */
565 if (res && pal && (!fset->pal || memcmp(fset->pal, pal, SIZEOF_PALETTE)))
566 {
567 res = malloc(SIZEOF_PALETTE);
568 if (res)
569 {
570 /* Set as default if first frame and no default yet */
571 if (!fset->cnt && !fset->pal) fset->pal = (void *)res;
572 else frm->pal = (void *)res;
573 mem_pal_copy(res, pal);
574 }
575 }
576
577 if (!res) /* Not enough memory */
578 {
579 while (--i >= 0) free(frm->img[i]);
580 return (FALSE);
581 }
582
583 fset->cnt++;
584 fset->size = 0; // Recalculate it later
585 return (TRUE);
586 }
587
588 /* Remove specified frame from a frameset */
mem_remove_frame(frameset * fset,int frame)589 void mem_remove_frame(frameset *fset, int frame)
590 {
591 image_frame *tmp;
592 int l = fset->cnt;
593
594 if (frame >= l) return;
595 tmp = fset->frames + frame;
596 mem_free_chanlist(tmp->img);
597 free(tmp->pal);
598 memmove(tmp, tmp + 1, (--l - frame) * sizeof(image_frame));
599 fset->cnt = l;
600 // !!! Like with layers, you switch to another frame before deleting current one
601 if (fset->cur > frame) fset->cur--;
602 /* Reduce array size if 2/3+ empty */
603 if ((l * 3 <= fset->max) && (fset->max > FRAMES_MIN))
604 frameset_realloc(fset);
605 fset->size = 0; // Recalculate it later
606 }
607
608 /* Empty a frameset */
mem_free_frames(frameset * fset)609 void mem_free_frames(frameset *fset)
610 {
611 image_frame *frm;
612 int i;
613
614 if (fset->frames)
615 {
616 for (i = 0 , frm = fset->frames; i < fset->cnt; i++ , frm++)
617 {
618 mem_free_chanlist(frm->img);
619 free(frm->pal);
620 }
621 free(fset->frames);
622 }
623 free(fset->pal);
624 memset(fset, 0, sizeof(frameset));
625 }
626
627 /* Set initial state of image variables */
init_istate(image_state * state,image_info * image)628 void init_istate(image_state *state, image_info *image)
629 {
630 memset(state->prot_mask, 0, 256); /* Clear all mask info */
631 state->prot = 0;
632 state->col_[0] = 1;
633 state->col_[1] = 0;
634 state->col_24[0] = image->pal[1];
635 state->col_24[1] = image->pal[0];
636 state->tool_pat = 0;
637 state->tool_pat_B = 0;
638 }
639
640 /* Add a new undo data node */
undo_add_data(undo_item * undo,int type,void * ptr)641 static int undo_add_data(undo_item *undo, int type, void *ptr)
642 {
643 undo_data *node;
644 unsigned int tmap = 1 << type;
645
646
647 /* Reuse existing node */
648 if ((node = undo->dataptr))
649 {
650 if (node->map & tmap) goto fail; // Prevent duplication
651 tmap |= node->map;
652 }
653 /* Allocate a new node */
654 else if (!(node = newchunk(&undo_datastore))) goto fail;
655 node->map = tmap;
656 node->store[type] = ptr;
657 undo->dataptr = node;
658 return (TRUE);
659
660 fail: /* Cannot store - delete the data right now */
661 if (tmap & UD_FREE_MASK) free(ptr);
662 return (FALSE);
663 }
664
665 /* Free an undo data block, and delete its data */
undo_free_data(undo_item * undo)666 static void undo_free_data(undo_item *undo)
667 {
668 undo_data *tmp;
669 unsigned int tmap;
670 int i;
671
672 if (!(tmp = undo->dataptr)) return;
673 for (tmap = tmp->map & UD_FREE_MASK, i = 0; tmap; tmap >>= 1 , i++)
674 if (tmap & 1) free(tmp->store[i]);
675 freechunk(&undo_datastore, tmp);
676 undo->dataptr = NULL;
677 }
678
679 /* Swap undo data - move current set out, and replace by incoming set */
undo_swap_data(undo_item * outp)680 static void undo_swap_data(undo_item *outp)
681 {
682 undo_data *tmp = outp->dataptr;
683 unsigned int tmap;
684
685 outp->dataptr = NULL;
686 if (mem_tempfiles) undo_add_data(outp, UD_TEMPFILES, mem_tempfiles);
687 mem_tempfiles = NULL;
688 // !!! Other unconditionally outgoing stuff goes here
689
690 if (!tmp) return;
691 tmap = tmp->map;
692 if (tmap & (1 << UD_FILENAME))
693 {
694 undo_add_data(outp, UD_FILENAME, mem_filename);
695 mem_filename = tmp->store[UD_FILENAME];
696 }
697 if (tmap & (1 << UD_TEMPFILES)) mem_tempfiles = tmp->store[UD_TEMPFILES];
698 // !!! All stuff (swappable or incoming) goes here
699
700 /* Release the incoming node */
701 freechunk(&undo_datastore, tmp);
702 }
703
704 /* Change layer's filename
705 * Note: calling this with non-empty redo, for example when saving to a new
706 * name, will "reparent" its frames from the old filename to the new one - WJ */
mem_replace_filename(int layer,char * fname)707 void mem_replace_filename(int layer, char *fname)
708 {
709 image_info *image = &mem_image;
710 undo_stack *undo;
711 char *name;
712
713 if (layer != layer_selected) image = &layer_table[layer].image->image_;
714 name = image->filename;
715 if (fname && !fname[0]) fname = NULL; // Empty name is no name
716
717 /* Do nothing if "replacing" name by itself */
718 if (fname && name ? !strcmp(fname, name) : fname == name) return;
719
720 /* !!! Make a copy of new filename while the old filename still exists,
721 * because the new pointer must differ from the old one - WJ */
722 if (fname) fname = strdup(fname);
723
724 /* Store the old filename in _previous_ undo frame if possible */
725 undo = &image->undo_;
726 if (undo->done) undo_add_data(undo->items[(undo->pointer ?
727 undo->pointer : undo->max) - 1], UD_FILENAME, name);
728 else free(name);
729
730 /* Replace filename, and clear tempfiles too while we're at it */
731 image->filename = fname;
732 image->tempfiles = NULL;
733 }
734
735 /* Label file's frames in current layer as changed */
mem_file_modified(char * fname)736 void mem_file_modified(char *fname)
737 {
738 char *name;
739 undo_item *undo;
740 int i, j, k, l, changed;
741
742 l = mem_undo_done;
743 for (k = -1; k <= 1; k += 2)
744 {
745 name = mem_filename;
746 changed = name && !strcmp(name, fname) ? ~UF_ORIG : ~0;
747 for (i = 1; i <= l; i++)
748 {
749 j = (mem_undo_max + mem_undo_pointer + i * k) % mem_undo_max;
750 undo = mem_undo_im_[j];
751 if (undo->dataptr && (undo->dataptr->map & (1 << UD_FILENAME)))
752 {
753 name = undo->dataptr->store[UD_FILENAME];
754 changed = name && !strcmp(name, fname) ? ~UF_ORIG : ~0;
755 }
756 undo->flags &= changed;
757 }
758 l = mem_undo_redo;
759 }
760 }
761
762 /* Create new undo stack of a given depth, and put default frame onto it */
init_undo(undo_stack * ustack,int depth)763 int init_undo(undo_stack *ustack, int depth)
764 {
765 if ((ustack->items = calloc(depth, sizeof(undo_item *))) &&
766 (ustack->items[0] = newchunk(&undo_items)))
767 {
768 ustack->max = depth;
769 ustack->pointer = ustack->done = ustack->redo = 0;
770 ustack->size = 0;
771 return (TRUE);
772 }
773 free(ustack->items);
774 return (FALSE);
775 }
776
777 /* Copy image state into current undo frame */
update_undo(image_info * image)778 void update_undo(image_info *image)
779 {
780 undo_item *undo = image->undo_.items[image->undo_.pointer];
781
782 /* !!! If system is unable to allocate 768 bytes, may as well die by SIGSEGV
783 * !!! right here, and not hobble along till GUI does the dying - WJ */
784 if (!undo->pal_) undo->pal_ = malloc(SIZEOF_PALETTE);
785 mem_pal_copy(undo->pal_, image->pal);
786
787 memcpy(undo->img, image->img, sizeof(chanlist));
788 undo->dataptr = NULL;
789 undo->cols = image->cols;
790 undo->trans = image->trans;
791 undo->bpp = image->bpp;
792 undo->width = image->width;
793 undo->height = image->height;
794 undo->flags = image->changed ? 0 : UF_ORIG;
795 }
796
mem_free_chanlist(chanlist img)797 void mem_free_chanlist(chanlist img)
798 {
799 int i;
800
801 for (i = 0; i < NUM_CHANNELS; i++)
802 {
803 if (!img[i]) continue;
804 if (img[i] != MEM_NONE) free(img[i]);
805 }
806 }
807
undo_free_x(undo_item ** undo_)808 static size_t undo_free_x(undo_item **undo_)
809 {
810 undo_item *undo = *undo_;
811 size_t j;
812
813 if (!undo) return (0);
814 j = undo->size;
815 undo_free_data(undo);
816 free(undo->pal_);
817 mem_free_chanlist(undo->img);
818 memset(undo, 0, sizeof(undo_item));
819 freechunk(&undo_items, undo);
820 *undo_ = NULL;
821 return (j);
822 }
823
824 /* This resizes an in-use undo stack
825 * !!! Both old and new depths must be nonzero */
resize_undo(undo_stack * ustack,int depth)826 static int resize_undo(undo_stack *ustack, int depth)
827 {
828 undo_stack nstack;
829 int i, j, k, undo, redo, ptr, uptr, udepth, trim;
830
831 if (!init_undo(&nstack, depth)) return (FALSE);
832 undo_free_x(nstack.items); // Drop default item
833
834 undo = ustack->done;
835 redo = ustack->redo;
836 if ((trim = undo + redo + 1 > depth))
837 {
838 i = (depth - 1) / 2;
839 if (undo < i) redo = depth - undo - 1;
840 else
841 {
842 if (redo > i) redo = i;
843 undo = depth - redo - 1;
844 }
845 }
846 uptr = ptr = ustack->pointer;
847 if (ptr >= depth) ptr = 0;
848 udepth = ustack->max;
849 for (i = -undo; i <= redo; i++)
850 {
851 j = (uptr + i + udepth) % udepth;
852 k = (ptr + i + depth) % depth;
853 nstack.items[k] = ustack->items[j];
854 ustack->items[j] = NULL;
855 }
856 nstack.pointer = ptr;
857 nstack.done = undo;
858 nstack.redo = redo;
859 if (trim)
860 {
861 for (i = 0; i < udepth; i++)
862 undo_free_x(ustack->items + i);
863 }
864 free(ustack->items);
865 *ustack = nstack;
866 return (TRUE);
867 }
868
869 /* Resize all undo stacks */
update_undo_depth()870 void update_undo_depth()
871 {
872 image_info *image;
873 int l;
874
875 mem_undo_depth = mem_undo_depth <= MIN_UNDO ? MIN_UNDO :
876 mem_undo_depth >= MAX_UNDO ? MAX_UNDO : mem_undo_depth | 1;
877 for (l = 0; l <= layers_total; l++)
878 {
879 image = l == layer_selected ? &mem_image :
880 &layer_table[l].image->image_;
881 if (image->undo_.max == mem_undo_depth) continue;
882 resize_undo(&image->undo_, mem_undo_depth);
883 }
884 }
885
886 /* Clear/remove image data */
mem_free_image(image_info * image,int mode)887 void mem_free_image(image_info *image, int mode)
888 {
889 int i, j = image->undo_.max, p = image->undo_.pointer;
890
891 /* Delete current image (don't rely on undo frame being up to date) */
892 if (mode & FREE_IMAGE)
893 {
894 mem_free_chanlist(image->img);
895 memset(image->img, 0, sizeof(chanlist));
896 image->width = image->height = 0;
897
898 free(image->filename);
899 image->filename = image->tempfiles = NULL;
900 }
901
902 /* Delete undo frames if any */
903 image->undo_.pointer = image->undo_.done = image->undo_.redo = 0;
904 if (!image->undo_.items) return;
905 memset(image->undo_.items[p]->img, 0, sizeof(chanlist)); // Already freed
906 for (i = 0; i < j; i++) undo_free_x(image->undo_.items + i);
907
908 /* Delete undo stack if finalizing */
909 if (mode & FREE_UNDO)
910 {
911 free(image->undo_.items);
912 image->undo_.items = NULL;
913 image->undo_.max = 0;
914 }
915 /* Otherwise, allocate default frame */
916 else image->undo_.items[0] = newchunk(&undo_items);
917 }
918
919 /* Allocate new image data */
920 // !!! Does NOT copy palette in copy mode, as it may be invalid
mem_alloc_image(int mode,image_info * image,int w,int h,int bpp,int cmask,image_info * src)921 int mem_alloc_image(int mode, image_info *image, int w, int h, int bpp,
922 int cmask, image_info *src)
923 {
924 unsigned char *res;
925 size_t l, sz;
926 int i;
927
928 if (mode & AI_CLEAR) memset(image, 0, sizeof(image_info));
929 else
930 {
931 memset(image->img, 0, sizeof(chanlist));
932 image->filename = image->tempfiles = NULL; /* Paranoia */
933 image->changed = 0;
934 }
935
936 if (mode & AI_COPY)
937 {
938 if (src->filename && !(image->filename = strdup(src->filename)))
939 return (FALSE);
940 image->tempfiles = src->tempfiles;
941 image->changed = src->changed;
942
943 w = src->width;
944 h = src->height;
945 bpp = src->bpp;
946 cmask = cmask_from(src->img);
947 }
948
949 image->width = w;
950 image->height = h;
951 image->bpp = bpp;
952
953 if (!cmask) return (TRUE); /* Empty block requested */
954
955 sz = (size_t)w * h;
956 l = sz * bpp;
957 res = MEM_NONE;
958 for (i = CHN_IMAGE; res && (i < NUM_CHANNELS); i++)
959 {
960 if (cmask & CMASK_FOR(i)) res = image->img[i] = malloc(l);
961 l = sz;
962 }
963 if (res && image->undo_.items)
964 {
965 undo_item *undo = image->undo_.items[image->undo_.pointer];
966 if (!undo->pal_) res = (void *)(undo->pal_ = malloc(SIZEOF_PALETTE));
967 }
968 if (!res) /* Not enough memory */
969 {
970 free(image->filename);
971 image->filename = NULL;
972 while (--i >= 0) free(image->img[i]);
973 memset(image->img, 0, sizeof(chanlist));
974 return (FALSE);
975 }
976
977 l = sz * bpp;
978 if (mode & AI_COPY) /* Clone */
979 {
980 for (i = CHN_IMAGE; i < NUM_CHANNELS; i++)
981 {
982 if (image->img[i]) memcpy(image->img[i], src->img[i], l);
983 l = sz;
984 }
985 }
986 else if (!(mode & AI_NOINIT)) /* Init */
987 {
988 for (i = CHN_IMAGE; i < NUM_CHANNELS; i++)
989 {
990 if (image->img[i]) memset(image->img[i], channel_fill[i], l);
991 l = sz;
992 }
993 }
994
995 return (TRUE);
996 }
997
998 /* Allocate space for new image, removing old if needed */
mem_new(int width,int height,int bpp,int cmask)999 int mem_new( int width, int height, int bpp, int cmask )
1000 {
1001 int res;
1002
1003 mem_free_image(&mem_image, FREE_IMAGE);
1004 res = mem_alloc_image(0, &mem_image, width, height, bpp, cmask, NULL);
1005 if (!res) /* Not enough memory */
1006 {
1007 // 8x8 is bound to work!
1008 mem_alloc_image(0, &mem_image, 8, 8, bpp, CMASK_IMAGE, NULL);
1009 }
1010 mem_image.trans = -1;
1011
1012 // !!! If palette isn't set up before mem_new(), undo frame will get wrong one
1013 // !!! (not that it affects anything at this time)
1014 update_undo(&mem_image);
1015 mem_channel = CHN_IMAGE;
1016 mem_xbm_hot_x = mem_xbm_hot_y = -1;
1017
1018 return (!res);
1019 }
1020
cmask_from(chanlist img)1021 int cmask_from(chanlist img)
1022 {
1023 int i, j, k = 1;
1024
1025 for (i = j = 0; i < NUM_CHANNELS; i++ , k += k)
1026 if (img[i]) j |= k;
1027 return (j);
1028 }
1029
1030 /* Allocate new clipboard, removing or preserving old as needed */
mem_clip_new(int width,int height,int bpp,int cmask,chanlist backup)1031 int mem_clip_new(int width, int height, int bpp, int cmask, chanlist backup)
1032 {
1033 int res;
1034
1035
1036 /* Text flag defaults to cleared */
1037 text_paste = 0;
1038
1039 /* Clear everything if no backup needed */
1040 if (!backup)
1041 {
1042 mem_free_image(&mem_clip, FREE_ALL);
1043 mem_clip_paletted = 0;
1044 }
1045
1046 /* Backup current contents */
1047 else memcpy(backup, mem_clip.img, sizeof(chanlist));
1048
1049 /* Allocate new frame */
1050 res = mem_alloc_image(AI_NOINIT, &mem_clip, width, height, bpp, cmask, NULL);
1051
1052 /* Remove backup if allocation failed */
1053 if (!res && backup)
1054 {
1055 mem_free_chanlist(backup);
1056 mem_clip_paletted = 0;
1057 }
1058
1059 return (!res);
1060 }
1061
1062 /* Get address of previous channel data (or current if none) */
mem_undo_previous(int channel)1063 unsigned char *mem_undo_previous(int channel)
1064 {
1065 undo_item *undo;
1066 unsigned char *res;
1067
1068 undo = mem_undo_im_[(mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1];
1069 if (!undo || !(res = undo->img[channel]) || (res == MEM_NONE) ||
1070 (undo->flags & UF_TILED))
1071 res = mem_img[channel]; // No usable undo so use current
1072 return (res);
1073 }
1074
lose_oldest(undo_stack * ustack)1075 static size_t lose_oldest(undo_stack *ustack) // Lose the oldest undo image
1076 {
1077 int idx;
1078
1079 if (ustack->redo > ustack->done) idx = ustack->redo--;
1080 else if (ustack->done) idx = ustack->max - ustack->done--;
1081 else return (0);
1082 /* !!! mem_try_malloc() may call this on an unsized undo stack - but it
1083 * !!! doesn't need valid sizes anyway - WJ */
1084 return (undo_free_x(ustack->items + (ustack->pointer + idx) % ustack->max));
1085 }
1086
1087 /* Convert tile bitmap row into a set of spans (skip/copy), terminated by
1088 * a zero-length copy span; return copied length */
mem_undo_spans(int * spans,unsigned char * tmap,int width,int bpp)1089 static int mem_undo_spans(int *spans, unsigned char *tmap, int width, int bpp)
1090 {
1091 int bt = 0, bw = 0, tl = 0, l = 0, ll = bpp * TILE_SIZE;
1092
1093 while (width > 0)
1094 {
1095 if ((bw >>= 1) < 2) bw = 0x100 + *tmap++;
1096 if (bt ^ (bw & 1))
1097 {
1098 *spans++ = tl * ll;
1099 tl = 0;
1100 }
1101 tl++;
1102 l += (bt = bw & 1) * ll;
1103 width -= TILE_SIZE;
1104 }
1105 width *= bpp;
1106 *spans++ = tl * ll + width;
1107 l += bt * width;
1108 spans[0] = spans[bt] = 0;
1109 return (l);
1110 }
1111
1112 /* Endianness-aware byte shifts */
1113 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1114 #define SHIFTUP(X,N) (X) <<= ((N) << 3)
1115 #define SHIFTDN(X,N) (X) >>= ((N) << 3)
1116 #else /* G_BYTE_ORDER == G_BIG_ENDIAN */
1117 #define SHIFTUP(X,N) (X) >>= ((N) << 3)
1118 #define SHIFTDN(X,N) (X) <<= ((N) << 3)
1119 #endif
1120
1121 /* Register-sized unsigned integer - redefine if this isn't it */
1122 #include <stdint.h>
1123 #define R_INT uintptr_t
1124
1125 /* Integer-at-a-time byte array comparison function; its efficiency depends on
1126 * both arrays aligned, or misaligned, the same - which is natural for channel
1127 * strips when geometry and position match - WJ */
tile_row_compare(unsigned char * src,unsigned char * dest,int w,int h,unsigned char * buf)1128 static int tile_row_compare(unsigned char *src, unsigned char *dest,
1129 int w, int h, unsigned char *buf)
1130 {
1131 const int amask = sizeof(R_INT) - 1;
1132 int l = w * h, mc = (w + TILE_SIZE - 1) >> TILE_SHIFT, nc = 0;
1133
1134 /* Long enough & identically aligned - use fast path */
1135 if ((w > sizeof(R_INT)) && (l > sizeof(R_INT) * 4) &&
1136 (((int)src & amask) == ((int)dest & amask)))
1137 {
1138 R_INT v, vm, vt1, vt2, *isrc, *idest;
1139 int i, k, t, x, d0, d1, il;
1140
1141 /* Given that loose ends, if any, belong to tiles too, we
1142 * simply leave them for later - maybe there won't be need */
1143 d0 = (((int)src ^ amask) + 1) & amask;
1144 d1 = (int)(src + l) & amask;
1145 isrc = (R_INT *)(src + d0);
1146 idest = (R_INT *)(dest + d0);
1147 il = (l - d0 - d1) / sizeof(v);
1148 i = 0;
1149 while (TRUE)
1150 {
1151 /* Fast comparison loop - damn GCC's guts for not
1152 * allocating it on registers without heavy wizardry */
1153 {
1154 int wi = il - i;
1155 R_INT *wsrc = isrc + i, *wdest = idest + i;
1156 while (TRUE)
1157 {
1158 if (wi-- <= 0) goto done;
1159 if (*wsrc != *wdest) break;
1160 ++wsrc; ++wdest;
1161 }
1162 t = (unsigned char *)wsrc - src;
1163 }
1164 k = (unsigned int)t % w;
1165 x = TILE_SIZE - (k & (TILE_SIZE - 1));
1166 if (k + x > w) x = w - k;
1167 k >>= TILE_SHIFT;
1168
1169 /* Value overlaps two or three tiles */
1170 while (x < sizeof(v))
1171 {
1172 v = *(R_INT *)(src + t) ^ *(R_INT *)(dest + t);
1173 tile2: vm = ~0UL;
1174 SHIFTUP(vm, x);
1175 x += sizeof(v);
1176 if (!(vm &= v)) break;
1177 x -= sizeof(v);
1178
1179 /* Farther tile(s) differ */
1180 if ((v != vm) && !buf[k]) /* First one differs too */
1181 {
1182 buf[k] = 1;
1183 if (++nc >= mc) x = l; /* Done is done */
1184 }
1185 if (++k + 1 == mc) /* May be 3 tiles */
1186 {
1187 x += w & (TILE_SIZE - 1);
1188 if (x >= sizeof(v)) break;
1189 v = vm;
1190 goto tile2;
1191 }
1192 x += TILE_SIZE;
1193 if (k == mc) k = 0; /* Row wrap */
1194 break;
1195 }
1196 i = (t + x - d0) / sizeof(v);
1197 if (buf[k]) continue;
1198 buf[k] = 1;
1199 if (++nc >= mc) break;
1200 }
1201 done:
1202 /* Compare the ends - using the fact that memory blocks
1203 * *must* be aligned at least that much */
1204 if (d1 && !buf[mc - 1])
1205 {
1206 vt2 = isrc[il] ^ idest[il];
1207 SHIFTUP(vt2, sizeof(vt2) - d1);
1208 if (vt2) ++nc , buf[mc - 1] = 1;
1209 }
1210 if (d0 && !buf[0])
1211 {
1212 vt1 = *(isrc - 1) ^ *(idest - 1);
1213 SHIFTDN(vt1, d0);
1214 if (vt1) ++nc , buf[0] = 1;
1215 }
1216 }
1217 /* Misaligned - use slow path */
1218 else
1219 {
1220 int i, k, x;
1221
1222 for (i = 0; i < l; i++)
1223 {
1224 if (src[i] != dest[i])
1225 {
1226 k = (unsigned int)i % w;
1227 x = TILE_SIZE - (k & (TILE_SIZE - 1));
1228 if (k + x > w) x = w - k;
1229 i += x;
1230 k >>= TILE_SHIFT;
1231 if (buf[k]) continue;
1232 buf[k] = 1;
1233 if (++nc >= mc) break;
1234 }
1235 }
1236 }
1237 return (nc);
1238 }
1239
1240 /* Convert undo frame to tiled representation */
mem_undo_tile(undo_item * undo)1241 static void mem_undo_tile(undo_item *undo)
1242 {
1243 unsigned char buf[((MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE) * 3];
1244 unsigned char *tstrip, tmap[MAX_TILEMAP], *tmp = NULL;
1245 int spans[(MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 3];
1246 size_t sz, area = 0, msize = 0;
1247 int i, j, k, nt, dw, cc, bpp;
1248 int h, nc, bw, tw, tsz, nstrips, ntiles = 0;
1249
1250
1251 undo->flags |= UF_FLAT; /* Not tiled by default */
1252
1253 /* Not tileable if too small */
1254 if (mem_width + mem_height < TILE_SIZE * 3) return;
1255
1256 /* Not tileable if different geometry */
1257 if ((undo->width != mem_width) || (undo->height != mem_height) ||
1258 (undo->bpp != mem_img_bpp)) return;
1259
1260 for (i = nc = 0; i < NUM_CHANNELS; i++)
1261 {
1262 /* Not tileable if different set of channels */
1263 if (!!undo->img[i] ^ !!mem_img[i]) return;
1264 if (undo->img[i] && mem_img[i] &&
1265 (undo->img[i] != MEM_NONE)) nc |= 1 << i;
1266 }
1267 /* Not tileable if no matching channels */
1268 if (!nc) return;
1269
1270 /* Build tilemap */
1271 nstrips = (mem_height + TILE_SIZE - 1) / TILE_SIZE;
1272 dw = (TILE_SIZE - 1) & ~(mem_width - 1);
1273 bw = (mem_width + TILE_SIZE - 1) / TILE_SIZE;
1274 tw = (bw + 7) >> 3; tsz = tw * nstrips;
1275 memset(tmap, 0, tsz);
1276 for (i = 0 , tstrip = tmap; i < mem_height; i += TILE_SIZE , tstrip += tw)
1277 {
1278 h = mem_height - i;
1279 if (h > TILE_SIZE) h = TILE_SIZE;
1280
1281 /* Compare strip of image */
1282 memset(buf, 0, bw * 3);
1283 for (cc = 0; nc >= 1 << cc; cc++)
1284 {
1285 unsigned char *src, *dest;
1286 int j, k, j2, w;
1287
1288 if (!(nc & 1 << cc)) continue;
1289 bpp = BPP(cc);
1290 w = mem_width * bpp;
1291 k = i * w;
1292 src = undo->img[cc] + k;
1293 dest = mem_img[cc] + k;
1294 if (!tile_row_compare(src, dest, w, h, buf)) continue;
1295 if (bpp == 1) continue;
1296 /* 3 bpp happen only in image channel, which goes first;
1297 * so we can postprocess the results to match 1 bpp */
1298 for (j = j2 = 0; j < bw; j++ , j2 += 3)
1299 buf[j] = buf[j2] | buf[j2 + 1] | buf[j2 + 2];
1300 }
1301 /* Fill tilemap row */
1302 for (j = nt = 0; j < bw; j++)
1303 {
1304 nt += (k = buf[j]);
1305 tstrip[j >> 3] |= k << (j & 7);
1306 }
1307 ntiles += nt;
1308 area += (nt * TILE_SIZE - buf[bw - 1] * dw) * h;
1309 }
1310
1311 /* Not tileable if tilemap cannot fit in space gained */
1312 sz = (size_t)mem_width * mem_height;
1313 bpp = (nc & CMASK_IMAGE ? mem_img_bpp : 1);
1314 if ((sz - area) * bpp <= tsz) return;
1315
1316 /* Implement tiling */
1317 sz = (size_t)mem_width * mem_height;
1318 for (cc = 0; nc >= 1 << cc; cc++)
1319 {
1320 unsigned char *src, *dest, *blk;
1321 size_t l;
1322 int i;
1323
1324 if (!(nc & 1 << cc)) continue;
1325 if (!ntiles) /* Channels unchanged - free the memory */
1326 {
1327 free(undo->img[cc]);
1328 undo->img[cc] = MEM_NONE;
1329 continue;
1330 }
1331
1332 /* Try to reduce memory fragmentation - allocate small blocks
1333 * anew when possible, instead of carving up huge ones */
1334 src = blk = undo->img[cc];
1335 bpp = BPP(cc);
1336 l = area * bpp + (tmp ? 0 : tsz);
1337 if (l * 3 <= sz * bpp) /* Small enough */
1338 {
1339 blk = malloc(l);
1340 /* Use original chunk if cannot get new one */
1341 if (!blk) blk = src;
1342 }
1343 dest = blk;
1344
1345 /* Compress channel */
1346 for (i = 0; i < nstrips; i++)
1347 {
1348 int j, k, *span;
1349
1350 mem_undo_spans(spans, tmap + tw * i, mem_width, bpp);
1351 k = mem_height - i * TILE_SIZE;
1352 if (k > TILE_SIZE) k = TILE_SIZE;
1353 for (j = 0; j < k; j++)
1354 {
1355 span = spans;
1356 while (TRUE)
1357 {
1358 src += *span++;
1359 if (!*span) break;
1360 if (dest != src) memmove(dest, src, *span);
1361 src += *span; dest += *span++;
1362 }
1363 }
1364 }
1365
1366 /* Resize or free memory block */
1367 if (blk == undo->img[cc]) /* Resize old */
1368 {
1369 dest = realloc(undo->img[cc], l);
1370 /* Leave chunk alone if resizing failed */
1371 if (!dest) l = sz * bpp;
1372 else undo->img[cc] = dest;
1373 }
1374 else /* Replace with new */
1375 {
1376 free(undo->img[cc]);
1377 undo->img[cc] = blk;
1378 }
1379 msize += l + 32;
1380
1381 /* Place tilemap in first chunk */
1382 if (!tmp) tmp = undo->img[cc] + area * bpp;
1383 }
1384
1385 /* Re-label as tiled and store tilemap, if there *are* tiles */
1386 if (msize)
1387 {
1388 undo->flags ^= UF_FLAT | UF_TILED;
1389 undo->tileptr = tmp;
1390 memcpy(tmp, tmap, tsz);
1391 }
1392
1393 if (undo->pal_) msize += SIZEOF_PALETTE + 32;
1394 undo->size = msize;
1395 undo->flags |= UF_SIZED;
1396 }
1397
1398 /* Compress last undo frame */
mem_undo_prepare()1399 void mem_undo_prepare()
1400 {
1401 undo_item *undo;
1402
1403 if (!mem_undo_done) return;
1404 undo = mem_undo_im_[(mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1];
1405
1406 /* Already processed? */
1407 if (undo->flags & (UF_TILED | UF_FLAT)) return;
1408
1409 /* Cull palette if unchanged */
1410 if (undo->pal_ && !memcmp(undo->pal_, mem_pal, SIZEOF_PALETTE))
1411 {
1412 /* Free new block, reuse old */
1413 free(mem_undo_im_[mem_undo_pointer]->pal_);
1414 mem_undo_im_[mem_undo_pointer]->pal_ = undo->pal_;
1415 undo->pal_ = NULL;
1416 }
1417 /* Tile image */
1418 mem_undo_tile(undo);
1419 }
1420
mem_undo_size(undo_stack * ustack)1421 static size_t mem_undo_size(undo_stack *ustack)
1422 {
1423 undo_item *undo;
1424 size_t k, l, total = 0;
1425 int i, j, bpp, umax = ustack->max;
1426
1427 for (i = 0; i < umax; i++)
1428 {
1429 /* Anything there? */
1430 if (!(undo = ustack->items[i])) continue;
1431 /* Not empty and not yet scanned */
1432 if (undo->width && !(undo->flags & UF_SIZED))
1433 {
1434 k = (size_t)undo->width * undo->height;
1435 bpp = undo->bpp;
1436 for (j = l = 0; j < NUM_CHANNELS; j++)
1437 {
1438 if (undo->img[j] && (undo->img[j] != MEM_NONE))
1439 l += k * bpp + 32;
1440 bpp = 1;
1441 }
1442 if (undo->pal_) l += SIZEOF_PALETTE + 32;
1443 undo->size = l;
1444 undo->flags |= UF_SIZED;
1445 }
1446 total += undo->size;
1447 }
1448
1449 return (total);
1450 }
1451
1452 /* Add up sizes of all layers other than current */
mem_undo_lsize()1453 static size_t mem_undo_lsize()
1454 {
1455 undo_stack *ustack;
1456 size_t total = 0;
1457 int l;
1458
1459 for (l = 0; l <= layers_total; l++)
1460 {
1461 if (l == layer_selected) continue;
1462 ustack = &layer_table[l].image->image_.undo_;
1463 // !!! This relies on layer_table items already processed by update_undo()
1464 if (!ustack->size) ustack->size = mem_undo_size(ustack);
1465 total += ustack->size;
1466 }
1467
1468 return (total);
1469 }
1470
1471 /* Free requested amount of undo space */
mem_undo_space(size_t mem_req)1472 static int mem_undo_space(size_t mem_req)
1473 {
1474 undo_stack *heap[MAX_LAYERS + 2], *wp, *hp;
1475 size_t mem_lim, mem_max = (size_t)mem_undo_limit * (1024 * 1024);
1476 int i, l, l2, h, csz = mem_undo_common * layers_total;
1477
1478 /* Layer mem limit including common area */
1479 mem_lim = mem_max * (csz * 0.01 + 1) / (layers_total + 1);
1480
1481 /* Fail if hopeless */
1482 if (mem_req > mem_lim) return (mem_req - mem_lim);
1483
1484 /* Layer mem limit exceeded - drop oldest */
1485 mem_req += mem_undo_size(&mem_image.undo_);
1486 while (mem_req > mem_lim)
1487 {
1488 if (!mem_undo_done) return (mem_req - mem_lim);
1489 mem_req -= lose_oldest(&mem_image.undo_);
1490 }
1491 /* All done if no common area */
1492 if (!csz) return (0);
1493
1494 mem_req += mem_undo_lsize();
1495 if (mem_req <= mem_max) return (0); // No need to trim other layers yet
1496 mem_lim -= mem_max * (mem_undo_common * 0.01); // Reserved space per layer
1497
1498 /* Build heap of undo stacks */
1499 for (i = h = 0; i <= layers_total; i++)
1500 {
1501 // Skip current layer
1502 if (i == layer_selected) continue;
1503 wp = &layer_table[i].image->image_.undo_;
1504 // Skip layers without extra frames
1505 if (!(wp->done + wp->redo)) continue;
1506 // Skip layers under the memory limit
1507 if (wp->size <= mem_lim) continue;
1508 // Put undo stack onto heap
1509 for (l = ++h; l > 1; l = l2)
1510 {
1511 l2 = l >> 1;
1512 if ((hp = heap[l2])->size >= wp->size) break;
1513 heap[l] = hp;
1514 }
1515 heap[l] = wp;
1516 }
1517
1518 /* Drop frames of greediest layers */
1519 while (h > 0)
1520 {
1521 size_t mem_nx = h > 1 ? heap[2]->size : 0;
1522 if ((h > 2) && (heap[3]->size > mem_nx)) mem_nx = heap[3]->size;
1523 /* Drop frames */
1524 wp = heap[1];
1525 while (TRUE)
1526 {
1527 size_t res = lose_oldest(wp);
1528 wp->size -= res; // Maintain undo stack size
1529 mem_req -= res;
1530 if (mem_req <= mem_max) return (0);
1531 if (!(wp->done + wp->redo) || (wp->size <= mem_lim))
1532 wp = heap[h--];
1533 else if (wp->size >= mem_nx) continue;
1534 break;
1535 }
1536 /* Reheap layer */
1537 mem_nx = wp->size;
1538 for (l = 1; (l2 = l + l) <= h; l = l2)
1539 {
1540 if ((l2 < h) && (heap[l2]->size < heap[l2 + 1]->size)) l2++;
1541 if (mem_nx >= (hp = heap[l2])->size) break;
1542 heap[l] = hp;
1543 }
1544 heap[l] = wp;
1545 }
1546
1547 return (0);
1548 }
1549
1550 /* Try to allocate a memory block, releasing undo frames if needed */
mem_try_malloc(size_t size)1551 void *mem_try_malloc(size_t size)
1552 {
1553 void *ptr;
1554
1555 while (!((ptr = malloc(size))))
1556 {
1557 // !!! Hardcoded to work with mem_image for now
1558 if (!mem_undo_done) return (NULL);
1559 lose_oldest(&mem_image.undo_);
1560 }
1561 return (ptr);
1562 }
1563
undo_next_core(int mode,int new_width,int new_height,int new_bpp,int cmask)1564 int undo_next_core(int mode, int new_width, int new_height, int new_bpp, int cmask)
1565 {
1566 png_color *newpal;
1567 undo_item *undo;
1568 unsigned char *img;
1569 void *tempfiles = mem_tempfiles;
1570 chanlist holder, frame;
1571 size_t mem_req, mem_lim, wh;
1572 int i, j, k, need_frame;
1573
1574
1575 if (pen_down && (mode & UC_PENDOWN)) return (0);
1576 pen_down = mode & UC_PENDOWN ? 1 : 0;
1577
1578 /* Fill undo frame */
1579 update_undo(&mem_image);
1580
1581 /* Postpone change notify if nothing will be done without new frame */
1582 need_frame = mode & (UC_CREATE | UC_NOCOPY | UC_GETMEM);
1583 if (!need_frame) notify_changed();
1584
1585 /* Release redo data */
1586 if (mem_undo_redo)
1587 {
1588 k = mem_undo_pointer;
1589 for (i = 0; i < mem_undo_redo; i++)
1590 {
1591 k = (k + 1) % mem_undo_max;
1592 undo_free_x(mem_undo_im_ + k);
1593 }
1594 mem_undo_redo = 0;
1595 }
1596
1597 /* Let cumulative updates stack */
1598 if (mode & UC_ACCUM)
1599 {
1600 int i = (mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1;
1601 if (mem_undo_done && (mem_undo_im_[i]->flags & UF_ACCUM))
1602 return (0);
1603 mem_undo_im_[mem_undo_pointer]->flags |= UF_ACCUM;
1604 }
1605
1606 /* Compress last undo frame */
1607 mem_undo_prepare();
1608
1609 /* Calculate memory requirements */
1610 mem_req = SIZEOF_PALETTE + 32;
1611 wh = (size_t)new_width * new_height;
1612 if (!(mode & UC_DELETE))
1613 {
1614 for (i = j = 0; i < NUM_CHANNELS; i++)
1615 {
1616 if ((cmask & (1 << i)) && (mem_img[i] ||
1617 (mode & (UC_CREATE | UC_RESET)))) j++;
1618 }
1619 if (cmask & CMASK_IMAGE) j += new_bpp - 1;
1620 mem_req += (wh + 32) * j;
1621 // !!! Must be after update_undo() to get used memory right
1622 if ((mem_undo_fail = mem_undo_space(mem_req))) return (2);
1623 }
1624 if (mode & UC_GETMEM) return (0); // Enough memory was freed
1625
1626 /* Ensure a new frame */
1627 undo = newchunk(&undo_items);
1628 if (!undo) return (1);
1629 freechunk(&undo_items, undo); // It'll be waiting in the freelist
1630
1631 /* Prepare outgoing frame */
1632 undo = mem_undo_im_[mem_undo_pointer];
1633 memcpy(frame, undo->img, sizeof(chanlist));
1634 if (!(mode & UC_RESET)) for (i = 0; i < NUM_CHANNELS; i++)
1635 if (frame[i] && !(cmask & (1 << i))) frame[i] = MEM_NONE;
1636
1637 /* Allocate new palette */
1638 newpal = mem_try_malloc(SIZEOF_PALETTE);
1639 if (!newpal) return (1);
1640
1641 /* Duplicate affected channels */
1642 for (i = 0; i < NUM_CHANNELS; i++)
1643 {
1644 holder[i] = img = mem_img[i];
1645 if (!(cmask & (1 << i)))
1646 {
1647 if (mode & UC_RESET) holder[i] = NULL;
1648 continue;
1649 }
1650 if (mode & UC_DELETE)
1651 {
1652 holder[i] = NULL;
1653 continue;
1654 }
1655 if (!img && !(mode & (UC_CREATE | UC_RESET))) continue;
1656 mem_lim = i == CHN_IMAGE ? wh * new_bpp : wh;
1657 img = mem_try_malloc(mem_lim);
1658 if (!img) /* Release memory and fail */
1659 {
1660 free(newpal);
1661 for (j = 0; j < i; j++)
1662 if (holder[j] != mem_img[j]) free(holder[j]);
1663 return (1);
1664 }
1665 holder[i] = img;
1666 /* Copy */
1667 if (!frame[i] || (mode & UC_NOCOPY)) continue;
1668 memcpy(img, frame[i], mem_lim);
1669 }
1670
1671 /* Next undo step */
1672 mem_undo_pointer = (mem_undo_pointer + 1) % mem_undo_max;
1673 if (mem_undo_done >= mem_undo_max - 1)
1674 undo_free_x(mem_undo_im_ + mem_undo_pointer);
1675 else mem_undo_done++;
1676 mem_undo_im_[mem_undo_pointer] = newchunk(&undo_items); // Cannot fail
1677
1678 /* Commit */
1679 if (tempfiles) undo_add_data(undo, UD_TEMPFILES, tempfiles);
1680 memcpy(undo->img, frame, sizeof(chanlist));
1681 mem_undo_im_[mem_undo_pointer]->pal_ = newpal;
1682 memcpy(mem_img, holder, sizeof(chanlist));
1683 mem_width = new_width;
1684 mem_height = new_height;
1685 mem_img_bpp = new_bpp;
1686
1687 /* Do postponed change notify, now that new frame is created */
1688 if (need_frame) notify_changed();
1689
1690 update_undo(&mem_image);
1691 return (0);
1692 }
1693
1694 // Call this after a draw event but before any changes to image
mem_undo_next(int mode)1695 void mem_undo_next(int mode)
1696 {
1697 int cmask = CMASK_ALL, wmode = 0;
1698
1699 switch (mode)
1700 {
1701 case UNDO_TRANS: /* Transparent colour change (cumulative) */
1702 wmode = UC_ACCUM;
1703 /* Fallthrough */
1704 case UNDO_PAL: /* Palette changes */
1705 cmask = CMASK_NONE;
1706 break;
1707 case UNDO_XPAL: /* Palette and indexed image changes */
1708 cmask = mem_img_bpp == 1 ? CMASK_IMAGE : CMASK_NONE;
1709 break;
1710 case UNDO_COL: /* Palette and/or RGB image changes */
1711 cmask = mem_img_bpp == 3 ? CMASK_IMAGE : CMASK_NONE;
1712 break;
1713 case UNDO_TOOL: /* Continuous drawing */
1714 wmode = UC_PENDOWN;
1715 case UNDO_DRAW: /* Changes to current channel / RGBA */
1716 cmask = (mem_channel == CHN_IMAGE) && RGBA_mode ?
1717 CMASK_RGBA : CMASK_CURR;
1718 break;
1719 case UNDO_INV: /* "Invert" operation */
1720 if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
1721 cmask = CMASK_NONE;
1722 else cmask = CMASK_CURR;
1723 break;
1724 case UNDO_XFORM: /* Changes to all channels */
1725 cmask = CMASK_ALL;
1726 break;
1727 case UNDO_FILT: /* Changes to current channel */
1728 cmask = CMASK_CURR;
1729 break;
1730 case UNDO_PASTE: /* Paste to current channel / RGBA */
1731 wmode = UC_PENDOWN; /* !!! Workaround for move-with-RMB-pressed */
1732 cmask = (mem_channel == CHN_IMAGE) && !channel_dis[CHN_ALPHA] &&
1733 (mem_clip_alpha || RGBA_mode) ? CMASK_RGBA : CMASK_CURR;
1734 break;
1735 }
1736 undo_next_core(wmode, mem_width, mem_height, mem_img_bpp, cmask);
1737 }
1738
1739 /* Swap image & undo tiles; in process, normal order translates to reverse and
1740 * vice versa - in order to do it in same memory with minimum extra copies */
mem_undo_tile_swap(undo_item * undo,int redo)1741 static void mem_undo_tile_swap(undo_item *undo, int redo)
1742 {
1743 unsigned char buf[MAX_WIDTH * 3], *tmap, *src, *dest;
1744 int spans[(MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 3];
1745 int i, l, h, cc, nw, bpp, w;
1746
1747 nw = ((mem_width + TILE_SIZE - 1) / TILE_SIZE + 7) >> 3;
1748 for (cc = 0; cc < NUM_CHANNELS; cc++)
1749 {
1750 if (!undo->img[cc] || (undo->img[cc] == MEM_NONE))
1751 continue;
1752 tmap = undo->tileptr;
1753 bpp = BPP(cc);
1754 w = mem_width * bpp;
1755 src = undo->img[cc];
1756 for (i = 0; i < mem_height; i += TILE_SIZE , tmap += nw)
1757 {
1758 int j, j1, dj;
1759
1760 if (!(l = mem_undo_spans(spans, tmap, mem_width, bpp)))
1761 continue;
1762 dest = mem_img[cc] + w * i;
1763 h = mem_height - i;
1764 if (h > TILE_SIZE) h = TILE_SIZE;
1765
1766 /* First row stored after last in redo frames */
1767 if (!redo) j = 0 , j1 = h , dj = 1;
1768 else
1769 {
1770 j = h - 1; j1 = dj = -1;
1771 memcpy(buf, src + j * l, l);
1772 }
1773 /* Process undo normally, and redo backwards */
1774 for (; j != j1; j += dj)
1775 {
1776 unsigned char *ts, *td, *tm;
1777 int *span = spans;
1778
1779 td = dest + j * w;
1780 tm = ts = src + j * l;
1781 *(redo ? &ts : &tm) = j ? tm - l : buf;
1782 while (TRUE)
1783 {
1784 td += *span++;
1785 if (!*span) break;
1786 memcpy(tm, td, *span);
1787 memcpy(td, ts, *span);
1788 tm += *span;
1789 ts += *span; td += *span++;
1790 }
1791 }
1792 src += h * l;
1793 if (!redo) memcpy(src - l, buf, l);
1794 }
1795 }
1796 }
1797
mem_undo_swap(undo_item * prev,int redo)1798 static void mem_undo_swap(undo_item *prev, int redo)
1799 {
1800 undo_item tmp = *prev;
1801 png_color pal[256];
1802 int i;
1803
1804 if (prev->flags & UF_TILED)
1805 {
1806 mem_undo_tile_swap(prev, redo);
1807 prev->flags &= ~UF_ORIG;
1808 }
1809 else
1810 {
1811 for (i = 0; i < NUM_CHANNELS; i++)
1812 {
1813 if (prev->img[i] != MEM_NONE)
1814 {
1815 prev->img[i] = mem_img[i];
1816 mem_img[i] = tmp.img[i];
1817 }
1818 }
1819 /* !!! If more flags need preserving, add them to mask */
1820 prev->flags = (prev->flags & UF_ACCUM) | UF_FLAT;
1821 }
1822
1823 if (prev->pal_)
1824 {
1825 mem_pal_copy(pal, mem_pal);
1826 mem_pal_copy(mem_pal, prev->pal_);
1827 mem_pal_copy(prev->pal_, pal);
1828 }
1829
1830 undo_swap_data(prev);
1831
1832 prev->width = mem_width;
1833 prev->height = mem_height;
1834 prev->bpp = mem_img_bpp;
1835 prev->cols = mem_cols;
1836 prev->trans = mem_xpm_trans;
1837 if (!mem_changed) prev->flags |= UF_ORIG;
1838
1839 mem_width = tmp.width;
1840 mem_height = tmp.height;
1841 mem_img_bpp = tmp.bpp;
1842 mem_cols = tmp.cols;
1843 mem_xpm_trans = tmp.trans;
1844 mem_changed = !(tmp.flags & UF_ORIG);
1845 }
1846
mem_do_undo(int redo)1847 void mem_do_undo(int redo)
1848 {
1849 undo_item *curr, *prev;
1850 int i, j;
1851
1852 /* Compress last undo frame */
1853 mem_undo_prepare();
1854
1855 if ((redo ? mem_undo_redo : mem_undo_done) > 0 )
1856 {
1857 j = redo ? 1 : -1;
1858 i = (mem_undo_pointer + j + mem_undo_max) % mem_undo_max;
1859
1860 /* Swap data */
1861 curr = mem_undo_im_[mem_undo_pointer];
1862 prev = mem_undo_im_[i];
1863 mem_undo_swap(prev, redo);
1864
1865 /* Swap frames */
1866 mem_undo_im_[mem_undo_pointer] = prev;
1867 mem_undo_im_[i] = curr;
1868 mem_undo_pointer = i;
1869 mem_undo_done += j;
1870 mem_undo_redo -= j;
1871
1872 /* Update current */
1873 update_undo(&mem_image);
1874 }
1875 pen_down = 0;
1876 }
1877
1878 /* Return the number of bytes used in image + undo */
mem_used()1879 size_t mem_used()
1880 {
1881 update_undo(&mem_image);
1882 return mem_undo_size(&mem_image.undo_);
1883 }
1884
1885 /* Return the number of bytes used in image + undo in all layers */
mem_used_layers()1886 size_t mem_used_layers()
1887 {
1888 return (mem_used() + mem_undo_lsize());
1889 }
1890
1891 /* Fast approximate atan2() function, returning result in degrees. This code is
1892 * approximately 2x faster than using libm on P4/Linux, and 6x on Windows.
1893 * Absolute error is below 0.0003 degrees, which means 1/10 of a pixel in worst
1894 * possible case. - WJ */
1895
1896 #define ATANNUM 128
1897 static float ATAN[2 * ATANNUM + 2];
1898
atan360(int x,int y)1899 double atan360(int x, int y)
1900 {
1901 double d;
1902 int xa, ya, n;
1903
1904 if (!(x | y)) return (0.0);
1905 xa = abs(x); ya = abs(y);
1906 d = ya < xa ? (double)ya / (double)xa : 2.0 - (double)xa / (double)ya;
1907 d *= ATANNUM;
1908 n = d;
1909 d = ATAN[n] + (ATAN[n + 1] - ATAN[n]) * (d - n);
1910
1911 if (x < 0) d = 180.0 - d;
1912 return (y >= 0 ? d : 360.0 - d);
1913 }
1914
make_ATAN()1915 static void make_ATAN()
1916 {
1917 int i;
1918
1919 for (i = 0; i <= ATANNUM; i++)
1920 ATAN[2 * ATANNUM - i] = 90.0 -
1921 (ATAN[i] = atan(i * (1.0 / ATANNUM)) * (180.0 / M_PI));
1922 ATAN[2 * ATANNUM + 1] = 90.0;
1923 }
1924
load_def_palette(char * name)1925 int load_def_palette(char *name)
1926 {
1927 int i;
1928
1929 if (!name[0]) return (FALSE); // Useless
1930 i = detect_palette_format(name);
1931 if (i > FT_NONE) return (load_image(name, FS_PALETTE_DEF, i) == 1);
1932 return (FALSE);
1933 }
1934
load_def_patterns(char * name)1935 int load_def_patterns(char *name)
1936 {
1937 int i;
1938
1939 if (!name[0]) return (FALSE); // Useless
1940 i = detect_image_format(name);
1941 if ((i > FT_NONE) && (file_formats[i].flags & FF_IDX))
1942 return (load_image(name, FS_PATTERN_LOAD, i) == 1);
1943 return (FALSE);
1944 }
1945
mem_init()1946 void mem_init() // Initialise memory
1947 {
1948 static const unsigned char lookup[8] =
1949 { 0, 36, 73, 109, 146, 182, 219, 255 };
1950 unsigned char *dest;
1951 char txt[64];
1952 int i, j, ix, iy, bs, bf, bt;
1953
1954
1955 make_ATAN();
1956
1957 for (i = 0; i < 256; i++) // Load up normal palette defaults
1958 {
1959 mem_pal_def[i].red = lookup[mem_pal_def[i].red];
1960 mem_pal_def[i].green = lookup[mem_pal_def[i].green];
1961 mem_pal_def[i].blue = lookup[mem_pal_def[i].blue];
1962 }
1963
1964 load_def_palette(inifile_get(DEFAULT_PAL_INI, ""));
1965 load_def_patterns(inifile_get(DEFAULT_PAT_INI, ""));
1966
1967 /* Init editor settings */
1968 mem_channel = CHN_IMAGE;
1969 mem_icx = mem_icy = 0.5;
1970 mem_xbm_hot_x = mem_xbm_hot_y = -1;
1971 mem_col_A = 1;
1972 mem_col_B = 0;
1973
1974 /* Set up default undo stack */
1975 mem_undo_depth = mem_undo_depth <= MIN_UNDO ? MIN_UNDO :
1976 mem_undo_depth >= MAX_UNDO ? MAX_UNDO : mem_undo_depth | 1;
1977 if (!init_undo(&mem_image.undo_, mem_undo_depth))
1978 {
1979 memory_errors(1);
1980 exit(0);
1981 }
1982
1983 // Create brush presets
1984
1985 mem_cols = mem_pal_def_i;
1986 mem_pal_copy( mem_pal, mem_pal_def );
1987 if (mem_new(PATCH_WIDTH, PATCH_HEIGHT, 3, CMASK_IMAGE)) // Not enough memory!
1988 {
1989 memory_errors(1);
1990 exit(0);
1991 }
1992 mem_mask_setv(NULL, -1, FALSE);
1993
1994 mem_col_A24.red = 255;
1995 mem_col_A24.green = 255;
1996 mem_col_A24.blue = 255;
1997 mem_col_B24.red = 0;
1998 mem_col_B24.green = 0;
1999 mem_col_B24.blue = 0;
2000
2001 j = mem_width * mem_height;
2002 dest = mem_img[CHN_IMAGE];
2003 for (i = 0; i < j; i++)
2004 {
2005 *dest++ = mem_col_B24.red;
2006 *dest++ = mem_col_B24.green;
2007 *dest++ = mem_col_B24.blue;
2008 }
2009
2010 mem_pat_update();
2011
2012 for (i = 0; i < NUM_BRUSHES; i++) // Draw each brush
2013 {
2014 ix = BRUSH_CELL / 2 + BRUSH_CELL * (i % BRUSH_GRID_W);
2015 iy = BRUSH_CELL / 2 + BRUSH_CELL * (i / BRUSH_GRID_W);
2016 bt = mem_brush_list[i][0];
2017 bs = mem_brush_list[i][1];
2018 bf = mem_brush_list[i][2];
2019
2020 switch (bt)
2021 {
2022 case TOOL_SQUARE:
2023 f_rectangle(ix - bs / 2, iy - bs / 2, bs, bs); break;
2024 case TOOL_CIRCLE:
2025 f_circle(ix, iy, bs); break;
2026 case TOOL_VERTICAL:
2027 f_rectangle(ix, iy - bs / 2, 1, bs); break;
2028 case TOOL_HORIZONTAL:
2029 f_rectangle(ix - bs / 2, iy, bs, 1); break;
2030 case TOOL_SLASH:
2031 for (j = 0; j < bs; j++)
2032 put_pixel(ix - bs / 2 + j, iy + bs / 2 - j);
2033 break;
2034 case TOOL_BACKSLASH:
2035 for (j = 0; j < bs; j++)
2036 put_pixel(ix + bs / 2 - j, iy + bs / 2 - j);
2037 break;
2038 case TOOL_SPRAY:
2039 for (j = 0; j < bf * 3; j++)
2040 put_pixel(ix - bs / 2 + rand() % bs,
2041 iy - bs / 2 + rand() % bs);
2042 break;
2043 }
2044 }
2045
2046 j = PATCH_WIDTH * PATCH_HEIGHT * 3;
2047 memcpy(mem_brushes, mem_img[CHN_IMAGE], j); // Store image for later use
2048 memset(mem_img[CHN_IMAGE], 0, j); // Clear so user doesn't see it upon load fail
2049
2050 mem_set_brush(36); // Initial brush
2051
2052 for ( i=0; i<NUM_CHANNELS; i++ )
2053 {
2054 for ( j=0; j<4; j++ )
2055 {
2056 sprintf(txt, "overlay%i%i", i, j);
2057 if ( j<3 )
2058 {
2059 channel_rgb[i][j] = inifile_get_gint32(txt, channel_rgb[i][j] );
2060 }
2061 else channel_opacity[i] = inifile_get_gint32(txt, channel_opacity[i] );
2062 }
2063 }
2064
2065 /* Preset gradients */
2066 for (i = 0; i < NUM_CHANNELS; i++)
2067 {
2068 grad_info *grad = gradient + i;
2069
2070 grad->gmode = GRAD_MODE_LINEAR;
2071 grad->rmode = GRAD_BOUND_STOP;
2072 grad_update(grad);
2073 }
2074 for (i = 0; i <= NUM_CHANNELS; i++)
2075 {
2076 graddata[i].gtype = GRAD_TYPE_RGB;
2077 graddata[i].otype = GRAD_TYPE_CONST;
2078 }
2079 grad_def_update(-1);
2080 for (i = 0; i <= NUM_CHANNELS; i++)
2081 gmap_setup(graddata + i, gradbytes, i);
2082 }
2083
mem_swap_cols(int redraw)2084 void mem_swap_cols(int redraw)
2085 {
2086 int oc, flags;
2087 png_color o24;
2088
2089 if (pattern_B)
2090 {
2091 oc = mem_tool_pat;
2092 mem_tool_pat = mem_tool_pat_B;
2093 mem_tool_pat_B = oc;
2094 }
2095 if (mem_channel != CHN_IMAGE)
2096 {
2097 oc = channel_col_A[mem_channel];
2098 channel_col_A[mem_channel] = channel_col_B[mem_channel];
2099 channel_col_B[mem_channel] = oc;
2100 flags = redraw ? UPD_GRAD : CF_GRAD;
2101 }
2102 else
2103 {
2104 oc = mem_col_A;
2105 mem_col_A = mem_col_B;
2106 mem_col_B = oc;
2107
2108 o24 = mem_col_A24;
2109 mem_col_A24 = mem_col_B24;
2110 mem_col_B24 = o24;
2111
2112 if (RGBA_mode)
2113 {
2114 oc = channel_col_A[CHN_ALPHA];
2115 channel_col_A[CHN_ALPHA] = channel_col_B[CHN_ALPHA];
2116 channel_col_B[CHN_ALPHA] = oc;
2117 }
2118 flags = redraw ? UPD_AB : CF_AB | CF_GRAD;
2119 }
2120 update_stuff(flags);
2121 }
2122
mem_set_trans(int trans)2123 void mem_set_trans(int trans)
2124 {
2125 if (trans == mem_xpm_trans) return;
2126 mem_undo_next(UNDO_TRANS);
2127 mem_xpm_trans = trans;
2128 update_stuff(UPD_TRANS);
2129 }
2130
repaint_swatch(int index)2131 static void repaint_swatch(int index) // Update a palette colour swatch
2132 {
2133 static const int ll[3] = { PALETTE_SWATCH_X, PALETTE_SWATCH_W,
2134 PALETTE_WIDTH - PALETTE_CROSS_X };
2135 unsigned char *tr, *tmp;
2136 int i, j, k, n, d, c = PNG_2_INT(mem_pal[index]);
2137 int cc[4] = { mem_pal_ab_c, c, mem_pal_ab_c, mem_pal_id_c };
2138
2139 /* Unhighlight background if not A or B */
2140 if ((index ^ mem_col_A) | (c ^ PNG_2_INT(mem_col_A24))) cc[0] = 0;
2141 if ((index ^ mem_col_B) | (c ^ PNG_2_INT(mem_col_B24))) cc[2] = 0;
2142
2143 tr = mem_pals + index * PALETTE_SWATCH_H * PALETTE_W3 +
2144 PALETTE_SWATCH_Y * PALETTE_W3;
2145
2146 /* Draw color & background */
2147 tmp = tr;
2148 for (n = 0; n < 3; n++)
2149 {
2150 c = cc[n]; j = ll[n];
2151 for (i = 0; i < j; i++ , tmp += 3)
2152 {
2153 tmp[0] = INT_2_R(c);
2154 tmp[1] = INT_2_G(c);
2155 tmp[2] = INT_2_B(c);
2156 }
2157 }
2158 for (i = 1; i < PALETTE_SWATCH_H; i++)
2159 memcpy(tr + i * PALETTE_W3, tr, PALETTE_W3);
2160
2161 /* Draw index */
2162 cc[1] = mem_pal_id_c;
2163 tmp = tr + PALETTE_INDEX_DY * PALETTE_W3 + PALETTE_INDEX_X * 3;
2164 for (d = 100; d; d /= 10 , tmp += (PALETTE_DIGIT_W + 1) * 3)
2165 {
2166 if ((index < d) && (d > 1)) continue;
2167 n = ((index / d) % 10) * PALETTE_DIGIT_H;
2168 for (i = 0; i < PALETTE_DIGIT_H; i++)
2169 {
2170 k = xbm_n7x7_bits[n + i];
2171 for (j = 0; j < PALETTE_DIGIT_W; j++ , k >>= 1 , tmp += 3)
2172 {
2173 c = cc[k & 1];
2174 tmp[0] = INT_2_R(c);
2175 tmp[1] = INT_2_G(c);
2176 tmp[2] = INT_2_B(c);
2177 }
2178 tmp += PALETTE_W3 - PALETTE_DIGIT_W * 3;
2179 }
2180 tmp -= PALETTE_DIGIT_H * PALETTE_W3;
2181 }
2182
2183 /* Draw protection mask cross */
2184 if (!mem_prot_mask[index]) return;
2185 tmp = tr + PALETTE_CROSS_DY * PALETTE_W3 +
2186 (PALETTE_CROSS_X + PALETTE_CROSS_DX) * 3;
2187 for (i = 0; i < PALETTE_CROSS_H; i++)
2188 {
2189 k = mem_cross[i];
2190 for (j = 0; j < PALETTE_CROSS_W; j++ , k >>= 1 , tmp += 3)
2191 {
2192 c = cc[(k & 1) + 2];
2193 tmp[0] = INT_2_R(c);
2194 tmp[1] = INT_2_G(c);
2195 tmp[2] = INT_2_B(c);
2196 }
2197 tmp += PALETTE_W3 - PALETTE_CROSS_W * 3;
2198 }
2199 }
2200
mem_pal_init()2201 void mem_pal_init() // Redraw whole palette
2202 {
2203 int i;
2204
2205 memset(mem_pals, 0, PALETTE_WIDTH * PALETTE_HEIGHT * 3);
2206 for (i = 0; i < mem_cols; i++) repaint_swatch(i);
2207 }
2208
mem_pal_load_def()2209 void mem_pal_load_def() // Load default palette
2210 {
2211 mem_pal_copy( mem_pal, mem_pal_def );
2212 mem_cols = mem_pal_def_i;
2213 }
2214
2215 #define RGB_PROT_MAX 256
2216 /* The 16:8 split is optimal for up to 768 colors, then 17:7 etc */
2217 typedef struct {
2218 short nb[0x10000 / 32];
2219 uint32_t rg[0x10000 / 32], b[RGB_PROT_MAX * 0x100 / 32];
2220 } rgb_prot;
2221
2222 static rgb_prot mem_prot_map;
2223
mem_mask_init()2224 void mem_mask_init() // Initialise RGB protection bitmaps
2225 {
2226 int i, j, n, v, rgb[RGB_PROT_MAX];
2227
2228 memset(&mem_prot_map, 0, sizeof(mem_prot_map));
2229 for (i = n = 0; i < mem_cols; i++)
2230 {
2231 if (!mem_prot_mask[i]) continue;
2232 rgb[n++] = v = PNG_2_INT(mem_pal[i]);
2233 v >>= 8;
2234 mem_prot_map.rg[v >> 5] |= 1U << (v & 0x1F);
2235 }
2236 mem_prot = n;
2237 if (!n) return;
2238 for (i = v = 0; i < 0x10000 / 32 - 1; i++)
2239 mem_prot_map.nb[i + 1] = v += bitcount(mem_prot_map.rg[i]);
2240 for (i = 0; i < n; i++)
2241 {
2242 unsigned u;
2243 v = rgb[i] >> 8;
2244 u = (1U << (v & 0x1F)) - 1;
2245 v >>= 5;
2246 j = mem_prot_map.nb[v] + bitcount(u & mem_prot_map.rg[v]);
2247 v = rgb[i] & 0xFF;
2248 mem_prot_map.b[j * (0x100 >> 5) + (v >> 5)] |= 1U << (v & 0x1F);
2249 }
2250 }
2251
mem_mask_test(int rgb)2252 static inline int mem_mask_test(int rgb)
2253 {
2254 int v = rgb >> 8;
2255 unsigned u = 1U << (v & 0x1F), w = mem_prot_map.rg[v >> 5];
2256
2257 if (u &= w)
2258 {
2259 v = mem_prot_map.nb[v >> 5] + bitcount((u - 1) & w);
2260 rgb &= 0xFF;
2261 u = mem_prot_map.b[v * (0x100 >> 5) + (rgb >> 5)] >> (rgb & 0x1F);
2262 }
2263 return (u & 1);
2264 }
2265
mem_mask_setv(int * what,int n,int state)2266 void mem_mask_setv(int *what, int n, int state)
2267 {
2268 state = state ? 255 : 0;
2269 if (what)
2270 {
2271 while (n-- > 0)
2272 {
2273 int i = *what++;
2274 if ((i >= 0) && (i < mem_cols)) mem_prot_mask[i] = state;
2275 }
2276 }
2277 else if (n < 0) memset(mem_prot_mask, state, 256);
2278 else if (n < mem_cols) mem_prot_mask[n] = state;
2279 mem_mask_init();
2280 }
2281
mem_get_histogram(int channel)2282 void mem_get_histogram(int channel) // Calculate how many of each colour index is on the canvas
2283 {
2284 int i, j = mem_width * mem_height;
2285 unsigned char *img = mem_img[channel];
2286
2287 memset(mem_histogram, 0, sizeof(mem_histogram));
2288
2289 for (i = 0; i < j; i++) mem_histogram[*img++]++;
2290 }
2291
2292 typedef struct {
2293 int last_gamma, last_br, last_co, last_ps;
2294 unsigned char gamma_table[256], bc_table[256], ps_table[256];
2295 } transform_cache;
2296
do_transform(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0,int m0)2297 void do_transform(int start, int step, int cnt, unsigned char *mask,
2298 unsigned char *imgr, unsigned char *img0, int m0)
2299 {
2300 static const int ixx[7] = {0, 1, 2, 0, 1, 2, 0};
2301 static unsigned char fmask = 255;
2302 static transform_cache tc[2];
2303 int do_gamma, do_bc, /*do_sa,*/ do_ps;
2304 unsigned char rgb[3];
2305 int br, co, sa;
2306 int dH, sH, tH, ix0, ix1, ix2, c0, c1, c2, dc = 0, ops = 0;
2307 int j, mstep, r, g, b;
2308 transform_cache *tp = tc;
2309 transform_state *mp = mem_bcsp;
2310
2311 if (m0 > 255) tp++ , mp++; // Brush mode
2312
2313 if (!mp->allow[0]) ops |= 0xFF;
2314 if (!mp->allow[1]) ops |= 0xFF00;
2315 if (!mp->allow[2]) ops |= 0xFF0000;
2316
2317 br = mp->bcsp[0] * 256;
2318 co = mp->bcsp[1];
2319 if (co > 0) co *= 3;
2320 co += 100;
2321 co = (256 * co) / 100;
2322 sa = (256 * mp->bcsp[2]) / 100;
2323 dH = sH = mp->bcsp[5];
2324
2325 // Map bitwise to truncated
2326 do_ps = mp->pmode ? mp->bcsp[3] : 1 << mp->bcsp[3];
2327 // Disable if 1:1, else separate truncated from rounded
2328 if (do_ps &= 255) do_ps += (mp->pmode > 1) << 8;
2329
2330 do_gamma = mp->bcsp[4] - 100;
2331 do_bc = br | (co - 256);
2332 // do_sa = sa - 255;
2333
2334 /* Prepare posterize table */
2335 if (do_ps && (do_ps != tp->last_ps))
2336 {
2337 int mul = do_ps & 255, div = 256, add = 0, div2 = mul - 1;
2338 int i, j;
2339
2340 tp->last_ps = do_ps;
2341 if (do_ps > 255) // Rounded
2342 {
2343 mul += mul - 2;
2344 div = 255 * 2;
2345 add = 255;
2346 }
2347 for (i = 0; i < 256; i++)
2348 {
2349 j = (i * mul + add) / div;
2350 tp->ps_table[i] = (j * 255 * 2 + div2) / (div2 + div2);
2351 }
2352 }
2353 /* Prepare gamma table */
2354 if (do_gamma && (do_gamma != tp->last_gamma))
2355 {
2356 double w;
2357 int i;
2358
2359 tp->last_gamma = do_gamma;
2360 w = 100.0 / (double)(do_gamma + 100);
2361 for (i = 0; i < 256; i++)
2362 {
2363 tp->gamma_table[i] = rint(255.0 * pow((double)i / 255.0, w));
2364 }
2365 }
2366 /* Prepare brightness-contrast table */
2367 if (do_bc && ((br ^ tp->last_br) | (co ^ tp->last_co)))
2368 {
2369 int i, j;
2370
2371 tp->last_br = br; tp->last_co = co;
2372 for (i = 0; i < 256; i++)
2373 {
2374 j = ((i + i - 255) * co + (255 * 256)) / 2 + br;
2375 tp->bc_table[i] = j < 0 ? 0 : j > (255 * 256) ? 255 : j >> 8;
2376 }
2377 }
2378 if (dH)
2379 {
2380 if (dH < 0) dH += 1530;
2381 dc = (dH / 510) * 2; dH -= dc * 255;
2382 if ((sH = dH > 255))
2383 {
2384 dH = 510 - dH;
2385 dc = dc < 4 ? dc + 2 : 0;
2386 }
2387 }
2388 ix0 = ixx[dc]; ix1 = ixx[dc + 1]; ix2 = ixx[dc + 2];
2389
2390 /* Use fake mask if no real one provided */
2391 if (!mask) mask = &fmask , mstep = 0;
2392 else mask += start - step , mstep = step;
2393
2394 start *= 3; step *= 3; // Step by triples
2395 img0 += start - step;
2396 imgr += start - step;
2397 while (cnt-- > 0)
2398 {
2399 img0 += step; imgr += step; mask += mstep;
2400 if (*mask == (unsigned char)m0) continue;
2401 rgb[0] = img0[0];
2402 rgb[1] = img0[1];
2403 rgb[2] = img0[2];
2404 /* If we do gamma transform */
2405 if (do_gamma)
2406 {
2407 rgb[0] = tp->gamma_table[rgb[0]];
2408 rgb[1] = tp->gamma_table[rgb[1]];
2409 rgb[2] = tp->gamma_table[rgb[2]];
2410 }
2411 /* If we do hue transform & colour has a hue */
2412 if (dH && ((rgb[0] ^ rgb[1]) | (rgb[0] ^ rgb[2])))
2413 {
2414 /* Min. component */
2415 c2 = dc;
2416 if (rgb[ix2] < rgb[ix0]) c2++;
2417 if (rgb[ixx[c2]] >= rgb[ixx[c2 + 1]]) c2++;
2418 /* Actual indices */
2419 c2 = ixx[c2];
2420 c0 = ixx[c2 + 1];
2421 c1 = ixx[c2 + 2];
2422
2423 /* Max. component & edge dir */
2424 if ((tH = rgb[c0] <= rgb[c1]))
2425 {
2426 c0 = ixx[c2 + 2];
2427 c1 = ixx[c2 + 1];
2428 }
2429 /* Do adjustment */
2430 j = dH * (rgb[c0] - rgb[c2]) + 127; /* Round up (?) */
2431 j = (j + (j >> 8) + 1) >> 8;
2432 r = rgb[c0]; g = rgb[c1]; b = rgb[c2];
2433 if (tH ^ sH) /* Falling edge */
2434 {
2435 rgb[c1] = r = g > j + b ? g - j : b;
2436 rgb[c2] += j + r - g;
2437 }
2438 else /* Rising edge */
2439 {
2440 rgb[c1] = b = g < r - j ? g + j : r;
2441 rgb[c0] -= j + g - b;
2442 }
2443 }
2444 r = rgb[ix0];
2445 g = rgb[ix1];
2446 b = rgb[ix2];
2447 /* If we do brightness/contrast transform */
2448 if (do_bc)
2449 {
2450 r = tp->bc_table[r];
2451 g = tp->bc_table[g];
2452 b = tp->bc_table[b];
2453 }
2454 /* If we do saturation transform */
2455 if (sa)
2456 {
2457 j = (299 * r + 587 * g + 114 * b) / 1000;
2458 r = r * 256 + (r - j) * sa;
2459 r = r < 0 ? 0 : r > (255 * 256) ? 255 : r >> 8;
2460 g = g * 256 + (g - j) * sa;
2461 g = g < 0 ? 0 : g > (255 * 256) ? 255 : g >> 8;
2462 b = b * 256 + (b - j) * sa;
2463 b = b < 0 ? 0 : b > (255 * 256) ? 255 : b >> 8;
2464 }
2465 /* If we do posterize transform */
2466 if (do_ps)
2467 {
2468 r = tp->ps_table[r];
2469 g = tp->ps_table[g];
2470 b = tp->ps_table[b];
2471 }
2472 /* If we do channel masking */
2473 if (ops)
2474 {
2475 r ^= (r ^ img0[0]) & ops;
2476 g ^= (g ^ img0[1]) & (ops >> 8);
2477 b ^= (b ^ img0[2]) & (ops >> 16);
2478 }
2479 imgr[0] = r;
2480 imgr[1] = g;
2481 imgr[2] = b;
2482 }
2483 }
2484
2485 static unsigned char pal_dupes[256];
2486
scan_duplicates()2487 int scan_duplicates() // Find duplicate palette colours, return number found
2488 {
2489 int i, j, c, found, pmap[256];
2490
2491 for (i = 0; i < mem_cols; i++)
2492 pmap[i] = PNG_2_INT(mem_pal[i]);
2493 /* Transparent color is different from any normal one */
2494 if (mem_xpm_trans >= 0) pmap[mem_xpm_trans] = -1;
2495
2496 for (found = 0 , i = mem_cols - 1; i >= 0; i--)
2497 {
2498 c = pmap[i];
2499 for (j = 0; pmap[j] != c; j++);
2500 pal_dupes[i] = j;
2501 found += i != j;
2502 }
2503
2504 return (found);
2505 }
2506
remove_duplicates()2507 void remove_duplicates() // Remove duplicate palette colours - call AFTER scan_duplicates
2508 {
2509 do_xlate(pal_dupes, mem_img[CHN_IMAGE], mem_width * mem_height);
2510 }
2511
mem_remove_unused_check()2512 int mem_remove_unused_check()
2513 {
2514 int i, found = 0;
2515
2516 mem_get_histogram(CHN_IMAGE);
2517 for (i = 0; i < mem_cols; i++)
2518 if (!mem_histogram[i]) found++;
2519
2520 if (!found) return 0; // All palette colours are used on the canvas
2521 // Leave at least one colour even if canvas is 0x0
2522 return (mem_cols > found ? found : mem_cols - 1);
2523 }
2524
mem_remove_unused()2525 int mem_remove_unused()
2526 {
2527 unsigned char conv[256];
2528 int i, j, found = mem_remove_unused_check();
2529
2530 if (found <= 0) return (0);
2531
2532 conv[0] = 0; // Ensure this works even with empty histogram
2533 for (i = j = 0; i < 256; i++) // Create conversion table
2534 {
2535 if (mem_histogram[i])
2536 {
2537 mem_pal[j] = mem_pal[i];
2538 conv[i] = j++;
2539 }
2540 }
2541
2542 // Re-adjust transparent colour index if it exists
2543 mem_xpm_trans = (mem_xpm_trans < 0) || !mem_histogram[mem_xpm_trans] ?
2544 -1 : conv[mem_xpm_trans];
2545
2546 do_xlate(conv, mem_img[CHN_IMAGE], mem_width * mem_height);
2547
2548 mem_cols -= found;
2549
2550 return found;
2551 }
2552
2553 // Generate black-to-white palette
mem_bw_pal(png_color * pal,int i1,int i2)2554 void mem_bw_pal(png_color *pal, int i1, int i2)
2555 {
2556 int i, j, step = i2 > i1 ? 1 : -1, d = abs(i2 - i1);
2557
2558 if (!d) return;
2559 for (i = i1 , j = d , d += d; i != i2 + step; i += step , j += 255 * 2)
2560 {
2561 pal[i].red = pal[i].green = pal[i].blue = j / d;
2562 }
2563 }
2564
transform_pal(png_color * pal1,png_color * pal2,int p1,int p2)2565 void transform_pal(png_color *pal1, png_color *pal2, int p1, int p2)
2566 {
2567 int l = p2 - p1 + 1;
2568 unsigned char tmp[256 * 3];
2569
2570 pal2rgb(tmp, pal2 + p1, l, 0);
2571 do_transform(0, 1, l, NULL, tmp, tmp, 0);
2572 rgb2pal(pal1 + p1, tmp, l);
2573 }
2574
set_zoom_centre(int x,int y)2575 void set_zoom_centre( int x, int y )
2576 {
2577 IF_IN_RANGE( x, y )
2578 {
2579 mem_icx = ((float) x ) / mem_width;
2580 mem_icy = ((float) y ) / mem_height;
2581 mem_ics = 1;
2582 }
2583 }
2584
2585 // Convert image to RGB
do_convert_rgb(int start,int step,int cnt,unsigned char * dest,unsigned char * src,png_color * pal)2586 void do_convert_rgb(int start, int step, int cnt, unsigned char *dest,
2587 unsigned char *src, png_color *pal)
2588 {
2589 dest += start * 3;
2590 src += start;
2591 while (cnt-- > 0)
2592 {
2593 png_color *col = pal + *src;
2594 dest[0] = col->red;
2595 dest[1] = col->green;
2596 dest[2] = col->blue;
2597 dest += step * 3; src += step;
2598 }
2599 }
2600
2601 /* With 16-bit rg[], would be a little bit more compact (24K vs 26K) */
2602 typedef struct {
2603 uint32_t rg[0x10000 / 32], b[256 * (0x100 / 32)];
2604 unsigned char rgx[0x10000 / 32], vx[256 * 32];
2605 int nv, nb;
2606 } rgb_256_map;
2607
2608 // Convert RGB image to Indexed Palette
mem_convert_indexed(unsigned char * dest,unsigned char * src,int cnt,int cols,png_color * pal)2609 int mem_convert_indexed(unsigned char *dest, unsigned char *src, int cnt,
2610 int cols, png_color *pal)
2611 {
2612 rgb_256_map m;
2613 unsigned char bx[256 * (0x100 / 32)], idx[256];
2614 int i, j, k, l, n, v, vn, pix;
2615
2616 /* Put palette into bitmap */
2617 memset(&m, 0, sizeof(m));
2618 for (i = 0; i < cols; i++)
2619 {
2620 pix = PNG_2_INT(pal[i]);
2621 k = pix & 0xFF;
2622 n = (pix >> 8) & 0x1F;
2623 v = pix >> (8 + 5);
2624 /* Insert into tiers */
2625 if (!m.rg[v]) m.rgx[v] = m.nv++;
2626 vn = m.rgx[v] * 32 + n;
2627 if (!((m.rg[v] >> n) & 1))
2628 m.vx[vn] = m.nb++ , m.rg[v] |= 1U << n;
2629 m.b[m.vx[vn] * 8 + (k >> 5)] |= 1U << (k & 0x1F);
2630 }
2631 /* Calculate bitcounts */
2632 for (i = j = 0; i < sizeof(bx); i++)
2633 {
2634 bx[i] = j;
2635 j += bitcount(m.b[i]);
2636 }
2637 /* Prepare mapping */
2638 for (i = 0; i < cols; i++)
2639 {
2640 pix = PNG_2_INT(pal[i]);
2641 k = pix & 0xFF;
2642 n = (pix >> 8) & 0x1F;
2643 v = pix >> (8 + 5);
2644 /* Locate in bitmap */
2645 vn = m.rgx[v] * 32 + n;
2646 j = m.vx[vn] * 8 + (k >> 5);
2647 j = bx[j] + bitcount(m.b[j] & ((1U << (k & 0x1F)) - 1));
2648 /* Remember the palette slot for the location */
2649 idx[j] = i;
2650 }
2651
2652 for (i = 0; i < cnt; i++)
2653 {
2654 pix = MEM_2_INT(src, 0);
2655 k = pix & 0xFF;
2656 n = (pix >> 8) & 0x1F;
2657 v = pix >> (8 + 5);
2658 /* Test presence on both tiers at once: if the 1st is unset,
2659 * the 2nd simply defaults to block #0 */
2660 vn = m.rgx[v] * 32 + n;
2661 l = m.vx[vn] * 8 + (k >> 5);
2662 if (!((m.rg[v] >> n) & 1 & (m.b[l] >> (k & 0x1F))))
2663 return (1); // No index found - BAD ERROR!!
2664 /* Get index */
2665 l = bx[l] + bitcount(m.b[l] & ((1U << (k & 0x1F)) - 1));
2666 /* Map to palette */
2667 *dest++ = idx[l];
2668 src += 3;
2669 }
2670
2671 return (0);
2672 }
2673
2674 /* Max-Min quantization algorithm - good for preserving saturated colors,
2675 * and because of that, bad when used without dithering - WJ */
2676
2677 #define HISTSIZE (64 * 64 * 64)
maxminquan(unsigned char * inbuf,int width,int height,int quant_to,png_color * userpal)2678 int maxminquan(unsigned char *inbuf, int width, int height, int quant_to,
2679 png_color *userpal)
2680 {
2681 int i, j, k, ii, r, g, b, dr, dg, db, l = width * height, *hist;
2682
2683 /* Allocate histogram */
2684 hist = calloc(1, HISTSIZE * sizeof(int));
2685 if (!hist) return (-1);
2686
2687 /* Fill histogram */
2688 for (i = 0; i < l; i++)
2689 {
2690 ++hist[((inbuf[0] & 0xFC) << 10) + ((inbuf[1] & 0xFC) << 4) +
2691 (inbuf[2] >> 2)];
2692 inbuf += 3;
2693 }
2694
2695 /* Find the most frequent color */
2696 j = k = -1;
2697 for (i = 0; i < HISTSIZE; i++)
2698 {
2699 if (hist[i] <= k) continue;
2700 j = i; k = hist[i];
2701 }
2702
2703 /* Make it first */
2704 userpal[0].red = r = j >> 12;
2705 userpal[0].green = g = (j >> 6) & 0x3F;
2706 userpal[0].blue = b = j & 0x3F;
2707
2708 /* Find distances from all others to it */
2709 if (quant_to > 1)
2710 {
2711 for (i = 0; i < HISTSIZE; i++)
2712 {
2713 if (!hist[i]) continue;
2714 dr = (i >> 12) - r;
2715 dg = ((i >> 6) & 0x3F) - g;
2716 db = (i & 0x3F) - b;
2717 hist[i] = dr * dr + dg * dg + db * db;
2718 }
2719 }
2720
2721 /* Add more colors */
2722 for (ii = 1; ii < quant_to; ii++)
2723 {
2724 /* Find farthest color */
2725 j = -1;
2726 for (i = k = 0; i < HISTSIZE; i++)
2727 {
2728 if (hist[i] <= k) continue;
2729 j = i; k = hist[i];
2730 }
2731 /* No more colors? */
2732 if (j < 0) break;
2733
2734 /* Store into palette */
2735 userpal[ii].red = r = j >> 12;
2736 userpal[ii].green = g = (j >> 6) & 0x3F;
2737 userpal[ii].blue = b = j & 0x3F;
2738
2739 /* Update distances */
2740 for (i = 0; i < HISTSIZE; i++)
2741 {
2742 if (!hist[i]) continue;
2743 dr = (i >> 12) - r;
2744 dg = ((i >> 6) & 0x3F) - g;
2745 db = (i & 0x3F) - b;
2746 k = dr * dr + dg * dg + db * db;
2747 if (k < hist[i]) hist[i] = k;
2748 }
2749 }
2750
2751 /* Upconvert colors */
2752 for (i = 0; i < ii; i++)
2753 {
2754 userpal[i].red = (userpal[i].red << 2) + (userpal[i].red >> 4);
2755 userpal[i].green = (userpal[i].green << 2) + (userpal[i].green >> 4);
2756 userpal[i].blue = (userpal[i].blue << 2) + (userpal[i].blue >> 4);
2757 }
2758
2759 /* Clear empty slots */
2760 for (i = ii; i < quant_to; i++)
2761 userpal[i].red = userpal[i].green = userpal[i].blue = 0;
2762
2763 free(hist);
2764 return (0);
2765 }
2766
2767 /* Pairwise Nearest Neighbor quantization algorithm - minimizes mean square
2768 * error measure; time used is proportional to number of bins squared - WJ */
2769
2770 typedef struct {
2771 double rc, gc, bc, err;
2772 int cnt;
2773 unsigned short nn, fw, bk, tm, mtm;
2774 } pnnbin;
2775
find_nn(pnnbin * bins,int idx)2776 static void find_nn(pnnbin *bins, int idx)
2777 {
2778 pnnbin *bin1, *bin2;
2779 int i, nn = 0;
2780 double n1, wr, wg, wb, err = 1e100;
2781
2782 bin1 = bins + idx;
2783 n1 = bin1->cnt;
2784 wr = bin1->rc;
2785 wg = bin1->gc;
2786 wb = bin1->bc;
2787 for (i = bin1->fw; i; i = bin2->fw)
2788 {
2789 double nerr, n2;
2790
2791 bin2 = bins + i;
2792 nerr = (bin2->rc - wr) * (bin2->rc - wr) +
2793 (bin2->gc - wg) * (bin2->gc - wg) +
2794 (bin2->bc - wb) * (bin2->bc - wb);
2795 n2 = bin2->cnt;
2796 nerr *= (n1 * n2) / (n1 + n2);
2797 if (nerr >= err) continue;
2798 err = nerr;
2799 nn = i;
2800 }
2801 bin1->err = err;
2802 bin1->nn = nn;
2803 }
2804
pnnquan(unsigned char * inbuf,int width,int height,int quant_to,png_color * userpal)2805 int pnnquan(unsigned char *inbuf, int width, int height, int quant_to,
2806 png_color *userpal)
2807 {
2808 unsigned short heap[32769];
2809 pnnbin *bins, *tb, *nb;
2810 double d, err, n1, n2;
2811 int i, j, k, l, l2, h, b1, maxbins, extbins, res = 1;
2812
2813
2814 heap[0] = 0; // Empty
2815 bins = calloc(32768, sizeof(pnnbin));
2816 if (!bins) return (-1);
2817
2818 progress_init(_("Quantize Pass 1"), 1);
2819
2820 /* Build histogram */
2821 k = width * height;
2822 for (i = 0; i < k; i++ , inbuf += 3)
2823 {
2824 // !!! Can throw gamma correction in here, but what to do about perceptual
2825 // !!! nonuniformity then?
2826 j = ((inbuf[0] & 0xF8) << 7) + ((inbuf[1] & 0xF8) << 2) +
2827 (inbuf[2] >> 3);
2828 tb = bins + j;
2829 tb->rc += inbuf[0]; tb->gc += inbuf[1]; tb->bc += inbuf[2];
2830 tb->cnt++;
2831 }
2832
2833 /* Cluster nonempty bins at one end of array */
2834 tb = bins;
2835 for (i = 0; i < 32768; i++)
2836 {
2837 if (!bins[i].cnt) continue;
2838 *tb = bins[i];
2839 d = 1.0 / (double)tb->cnt;
2840 tb->rc *= d; tb->gc *= d; tb->bc *= d;
2841 if (quan_sqrt) tb->cnt = sqrt(tb->cnt);
2842 tb++;
2843 }
2844 maxbins = tb - bins;
2845 for (i = 0; i < maxbins - 1; i++)
2846 {
2847 bins[i].fw = i + 1;
2848 bins[i + 1].bk = i;
2849 }
2850 // !!! Already zeroed out by calloc()
2851 // bins[0].bk = bins[i].fw = 0;
2852
2853 /* Initialize nearest neighbors and build heap of them */
2854 for (i = 0; i < maxbins; i++)
2855 {
2856 if (((i * 50) % maxbins >= maxbins - 50))
2857 if (progress_update((float)i / maxbins)) goto quit;
2858
2859 find_nn(bins, i);
2860 /* Push slot on heap */
2861 err = bins[i].err;
2862 for (l = ++heap[0]; l > 1; l = l2)
2863 {
2864 l2 = l >> 1;
2865 if (bins[h = heap[l2]].err <= err) break;
2866 heap[l] = h;
2867 }
2868 heap[l] = i;
2869 }
2870
2871 progress_end();
2872 progress_init(_("Quantize Pass 2"), 1);
2873
2874 /* Merge bins which increase error the least */
2875 extbins = maxbins - quant_to;
2876 for (i = 0; i < extbins; )
2877 {
2878 if (((i * 50) % extbins >= extbins - 50))
2879 if (progress_update((float)i / extbins)) goto quit;
2880
2881 /* Use heap to find which bins to merge */
2882 while (TRUE)
2883 {
2884 tb = bins + (b1 = heap[1]); /* One with least error */
2885 /* Is stored error up to date? */
2886 if ((tb->tm >= tb->mtm) &&
2887 (bins[tb->nn].mtm <= tb->tm)) break;
2888 if (tb->mtm == 0xFFFF) /* Deleted node */
2889 b1 = heap[1] = heap[heap[0]--];
2890 else /* Too old error value */
2891 {
2892 find_nn(bins, b1);
2893 tb->tm = i;
2894 }
2895 /* Push slot down */
2896 err = bins[b1].err;
2897 for (l = 1; (l2 = l + l) <= heap[0]; l = l2)
2898 {
2899 if ((l2 < heap[0]) && (bins[heap[l2]].err >
2900 bins[heap[l2 + 1]].err)) l2++;
2901 if (err <= bins[h = heap[l2]].err) break;
2902 heap[l] = h;
2903 }
2904 heap[l] = b1;
2905 }
2906
2907 /* Do a merge */
2908 nb = bins + tb->nn;
2909 n1 = tb->cnt;
2910 n2 = nb->cnt;
2911 d = 1.0 / (n1 + n2);
2912 tb->rc = d * rint(n1 * tb->rc + n2 * nb->rc);
2913 tb->gc = d * rint(n1 * tb->gc + n2 * nb->gc);
2914 tb->bc = d * rint(n1 * tb->bc + n2 * nb->bc);
2915 tb->cnt += nb->cnt;
2916 tb->mtm = ++i;
2917
2918 /* Unchain deleted bin */
2919 bins[nb->bk].fw = nb->fw;
2920 bins[nb->fw].bk = nb->bk;
2921 nb->mtm = 0xFFFF;
2922 }
2923
2924 /* Fill palette */
2925 i = j = 0;
2926 while (TRUE)
2927 {
2928 userpal[j].red = rint(bins[i].rc);
2929 userpal[j].green = rint(bins[i].gc);
2930 userpal[j++].blue = rint(bins[i].bc);
2931 if (!(i = bins[i].fw)) break;
2932 }
2933
2934 /* Clear empty slots */
2935 for (; j < quant_to; j++)
2936 userpal[j].red = userpal[j].green = userpal[j].blue = 0;
2937 res = 0;
2938
2939 quit: progress_end();
2940 free(bins);
2941 return (res);
2942 }
2943
2944 /* Distance functions for 3 distance measures */
2945
2946 #if defined(__GNUC__) && defined(__i386__)
2947 #define REGPARM2 __attribute__ ((regparm (2)))
2948 #else
2949 #define REGPARM2
2950 #endif
2951
2952 typedef double REGPARM2 (*distance_func)(const double *v0, const double *v1);
2953
distance_linf(const double * v0,const double * v1)2954 static double REGPARM2 distance_linf(const double *v0, const double *v1)
2955 {
2956 double td, td2;
2957
2958 td = fabs(v0[0] - v1[0]);
2959 td2 = fabs(v0[1] - v1[1]);
2960 if (td < td2) td = td2;
2961 td2 = fabs(v0[2] - v1[2]);
2962 if (td < td2) td = td2;
2963 return (td);
2964 }
2965
distance_l1(const double * v0,const double * v1)2966 static double REGPARM2 distance_l1(const double *v0, const double *v1)
2967 {
2968 return (fabs(v0[0] - v1[0]) + fabs(v0[1] - v1[1]) + fabs(v0[2] - v1[2]));
2969 }
2970
distance_l2(const double * v0,const double * v1)2971 static double REGPARM2 distance_l2(const double *v0, const double *v1)
2972 {
2973 return (sqrt((v0[0] - v1[0]) * (v0[0] - v1[0]) +
2974 (v0[1] - v1[1]) * (v0[1] - v1[1]) +
2975 (v0[2] - v1[2]) * (v0[2] - v1[2])));
2976 }
2977
2978 static const distance_func distance_3d[NUM_DISTANCES] = {
2979 distance_linf, distance_l1, distance_l2
2980 };
2981
2982 /* Dithering works with 6-bit colours, because hardware VGA palette is 6-bit,
2983 * and any kind of dithering is imprecise by definition anyway - WJ */
2984
2985 typedef struct {
2986 double xyz256[768], gamma[256 * 2], lin[256 * 2];
2987 int cspace, cdist, ncols;
2988 guint32 xcmap[64 * 64 * 2 + 128 * 2]; /* Cache bitmap */
2989 guint32 lcmap[64 * 64 * 2]; /* Extension bitmap */
2990 unsigned char cmap[64 * 64 * 64 + 128 * 64]; /* Index cache */
2991 } ctable;
2992
2993 static ctable *ctp;
2994
2995 /* !!! Beware of GCC misoptimizing this! The two functions below is the result
2996 * of much trial and error, and hopefully not VERY brittle; but still, after any
2997 * modification to them, compare the performance to what it was before - WJ */
2998
find_nearest(int col[3],int n)2999 static int find_nearest(int col[3], int n)
3000 {
3001 /* !!! Stack misalignment is a very real issue here */
3002 unsigned char tmp_[4 * sizeof(double)];
3003 double *tmp = ALIGNED(tmp_, sizeof(double));
3004
3005
3006 /* Prepare colour coords */
3007 switch (ctp->cspace)
3008 {
3009 default:
3010 case CSPACE_RGB:
3011 tmp[0] = ctp->lin[n + col[0]];
3012 tmp[1] = ctp->lin[n + col[1]];
3013 tmp[2] = ctp->lin[n + col[2]];
3014 break;
3015 case CSPACE_SRGB:
3016 tmp[0] = ctp->gamma[n + col[0]];
3017 tmp[1] = ctp->gamma[n + col[1]];
3018 tmp[2] = ctp->gamma[n + col[2]];
3019 break;
3020 case CSPACE_LXN:
3021 rgb2LXN(tmp, ctp->gamma[n + col[0]], ctp->gamma[n + col[1]],
3022 ctp->gamma[n + col[2]]);
3023 break;
3024 }
3025
3026 /* Find nearest colour */
3027 {
3028 const distance_func dist = distance_3d[ctp->cdist];
3029 double d = 1000000000.0, td, *xyz = ctp->xyz256;
3030 int i, j, l = ctp->ncols;
3031
3032 for (i = j = 0; i < l; i++)
3033 {
3034 td = dist(tmp, xyz + i * 3);
3035 if (td < d) j = i , d = td;
3036 }
3037 return (j);
3038 }
3039 }
3040
lookup_srgb(double * srgb)3041 static int lookup_srgb(double *srgb)
3042 {
3043 int k, n = 0, col[3];
3044
3045 /* Convert to 8-bit RGB coords */
3046 col[0] = UNGAMMA256(srgb[0]);
3047 col[1] = UNGAMMA256(srgb[1]);
3048 col[2] = UNGAMMA256(srgb[2]);
3049
3050 /* Check if there is extended precision */
3051 k = ((col[0] & 0xFC) << 10) + ((col[1] & 0xFC) << 4) + (col[2] >> 2);
3052 if (ctp->lcmap[k >> 5] & (1U << (k & 31))) k = 64 * 64 * 64 +
3053 ctp->cmap[k] * 64 + ((col[0] & 3) << 4) +
3054 ((col[1] & 3) << 2) + (col[2] & 3);
3055 else n = 256; /* Use posterized values for 6-bit part */
3056
3057 /* Use colour cache if possible */
3058 if (!(ctp->xcmap[k >> 5] & (1U << (k & 31))))
3059 {
3060 ctp->xcmap[k >> 5] |= 1U << (k & 31);
3061 ctp->cmap[k] = find_nearest(col, n);
3062 }
3063
3064 return (ctp->cmap[k]);
3065 }
3066
3067 // !!! No support for transparency yet !!!
3068 /* Damping functions roughly resemble old GIMP's behaviour, but may need some
3069 * tuning because linear sRGB is just too different from normal RGB */
mem_dither(unsigned char * old,int ncols,short * dither,int cspace,int dist,int limit,int selc,int serpent,int rgb8b,double emult)3070 int mem_dither(unsigned char *old, int ncols, short *dither, int cspace,
3071 int dist, int limit, int selc, int serpent, int rgb8b, double emult)
3072 {
3073 int i, j, k, l, kk, j0, j1, dj, rlen, col0, col1, progress;
3074 unsigned char *ddata, *src, *dest;
3075 double *row0, *row1, *row2, *tmp;
3076 double err, intd, extd, *gamma6, *lin6;
3077 double tc0[3], tc1[3], color0[3], color1[3];
3078 double fdiv = 0, gamut[6] = {1, 1, 1, 0, 0, 0};
3079
3080 /* Allocate working space */
3081 rlen = (mem_width + 4) * 3 * sizeof(double);
3082 ddata = multialloc(MA_ALIGN_DOUBLE,
3083 &row0, rlen,
3084 &row1, rlen,
3085 &row2, rlen,
3086 &ctp, sizeof(ctable),
3087 NULL);
3088 if (!ddata) return (1);
3089
3090 if ((progress = mem_width * mem_height > 1000000))
3091 progress_init(_("Converting to Indexed Palette"), 0);
3092
3093 /* Preprocess palette to find whether to extend precision and where */
3094 for (i = 0; i < ncols; i++)
3095 {
3096 j = ((mem_pal[i].red & 0xFC) << 10) +
3097 ((mem_pal[i].green & 0xFC) << 4) +
3098 (mem_pal[i].blue >> 2);
3099 if (!(l = ctp->cmap[j]))
3100 {
3101 ctp->cmap[j] = l = i + 1;
3102 ctp->xcmap[l * 4 + 2] = j;
3103 }
3104 k = ((mem_pal[i].red & 3) << 4) +
3105 ((mem_pal[i].green & 3) << 2) +
3106 (mem_pal[i].blue & 3);
3107 ctp->xcmap[l * 4 + (k & 1)] |= 1U << (k >> 1);
3108 }
3109 memset(ctp->cmap, 0, 64 * 64 * 64);
3110 for (k = 0 , i = 4; i < 256 * 4; i += 4)
3111 {
3112 guint32 v = ctp->xcmap[i] | ctp->xcmap[i + 1];
3113 /* Are 2+ colors there somewhere? */
3114 if (!((v & (v - 1)) | (ctp->xcmap[i] & ctp->xcmap[i + 1])))
3115 continue;
3116 rgb8b = TRUE; /* Force 8-bit precision */
3117 j = ctp->xcmap[i + 2];
3118 ctp->lcmap[j >> 5] |= 1U << (j & 31);
3119 ctp->cmap[j] = k++;
3120 }
3121 memset(ctp->xcmap, 0, 257 * 4 * sizeof(guint32));
3122
3123 /* Prepare tables */
3124 for (i = 0; i < 256; i++)
3125 {
3126 j = (i & 0xFC) + (i >> 6);
3127 ctp->gamma[i] = gamma256[i];
3128 ctp->gamma[i + 256] = gamma256[j];
3129 ctp->lin[i] = i * (1.0 / 255.0);
3130 ctp->lin[i + 256] = j * (1.0 / 255.0);
3131 }
3132 /* Keep all 8 bits of input or posterize to 6 bits? */
3133 i = rgb8b ? 0 : 256;
3134 gamma6 = ctp->gamma + i; lin6 = ctp->lin + i;
3135 tmp = ctp->xyz256;
3136 for (i = 0; i < ncols; i++ , tmp += 3)
3137 {
3138 /* Update gamut limits */
3139 tmp[0] = gamma6[mem_pal[i].red];
3140 tmp[1] = gamma6[mem_pal[i].green];
3141 tmp[2] = gamma6[mem_pal[i].blue];
3142 for (j = 0; j < 3; j++)
3143 {
3144 if (tmp[j] < gamut[j]) gamut[j] = tmp[j];
3145 if (tmp[j] > gamut[j + 3]) gamut[j + 3] = tmp[j];
3146 }
3147 /* Store colour coords */
3148 switch (cspace)
3149 {
3150 default:
3151 case CSPACE_RGB:
3152 tmp[0] = lin6[mem_pal[i].red];
3153 tmp[1] = lin6[mem_pal[i].green];
3154 tmp[2] = lin6[mem_pal[i].blue];
3155 break;
3156 case CSPACE_SRGB:
3157 break; /* Done already */
3158 case CSPACE_LXN:
3159 rgb2LXN(tmp, tmp[0], tmp[1], tmp[2]);
3160 break;
3161 }
3162 }
3163 ctp->cspace = cspace; ctp->cdist = dist; ctp->ncols = ncols;
3164 serpent = serpent ? 0 : 2;
3165 if (dither) fdiv = 1.0 / *dither++;
3166
3167 /* Process image */
3168 for (i = 0; i < mem_height; i++)
3169 {
3170 src = old + i * mem_width * 3;
3171 dest = mem_img[CHN_IMAGE] + i * mem_width;
3172 memset(row2, 0, rlen);
3173 if (serpent ^= 1)
3174 {
3175 j0 = 0; j1 = mem_width * 3; dj = 1;
3176 }
3177 else
3178 {
3179 j0 = (mem_width - 1) * 3; j1 = -3; dj = -1;
3180 dest += mem_width - 1;
3181 }
3182 for (j = j0; j != j1; j += dj * 3)
3183 {
3184 for (k = 0; k < 3; k++)
3185 {
3186 /* Posterize to 6 bits as natural for palette */
3187 color0[k] = gamma6[src[j + k]];
3188 /* Add in error, maybe limiting it */
3189 err = row0[j + k + 6];
3190 if (limit == 1) /* To half of SRGB range */
3191 {
3192 err = err < -0.5 ? -0.5 :
3193 err > 0.5 ? 0.5 : err;
3194 }
3195 else if (limit == 2) /* To 1/4, with damping */
3196 {
3197 err = err < -0.1 ? (err < -0.4 ?
3198 -0.25 : 0.5 * err - 0.05) :
3199 err > 0.1 ? (err > 0.4 ?
3200 0.25 : 0.5 * err + 0.05) : err;
3201 }
3202 color1[k] = color0[k] + err;
3203 /* Limit result to palette gamut */
3204 if (color1[k] < gamut[k]) color1[k] = gamut[k];
3205 if (color1[k] > gamut[k + 3]) color1[k] = gamut[k + 3];
3206 }
3207 /* Output best colour */
3208 col1 = lookup_srgb(color1);
3209 *dest = col1;
3210 dest += dj;
3211 if (!dither) continue;
3212 /* Evaluate new error */
3213 tc1[0] = gamma6[mem_pal[col1].red];
3214 tc1[1] = gamma6[mem_pal[col1].green];
3215 tc1[2] = gamma6[mem_pal[col1].blue];
3216 if (selc) /* Selective error damping */
3217 {
3218 col0 = lookup_srgb(color0);
3219 tc0[0] = gamma6[mem_pal[col0].red];
3220 tc0[1] = gamma6[mem_pal[col0].green];
3221 tc0[2] = gamma6[mem_pal[col0].blue];
3222 /* Split error the obvious way */
3223 if (!(selc & 1) && (col0 == col1))
3224 {
3225 color1[0] = (color1[0] - color0[0]) * emult +
3226 color0[0] - tc0[0];
3227 color1[1] = (color1[1] - color0[1]) * emult +
3228 color0[1] - tc0[1];
3229 color1[2] = (color1[2] - color0[2]) * emult +
3230 color0[2] - tc0[2];
3231 }
3232 /* Weigh component errors separately */
3233 else if (selc < 3)
3234 {
3235 for (k = 0; k < 3; k++)
3236 {
3237 intd = fabs(color0[k] - tc0[k]);
3238 extd = fabs(color0[k] - color1[k]);
3239 if (intd + extd == 0.0) err = 1.0;
3240 else err = (intd + emult * extd) / (intd + extd);
3241 color1[k] = err * (color1[k] - tc1[k]);
3242 }
3243 }
3244 /* Weigh errors by vector length */
3245 else
3246 {
3247 intd = sqrt((color0[0] - tc0[0]) * (color0[0] - tc0[0]) +
3248 (color0[1] - tc0[1]) * (color0[1] - tc0[1]) +
3249 (color0[2] - tc0[2]) * (color0[2] - tc0[2]));
3250 extd = sqrt((color0[0] - color1[0]) * (color0[0] - color1[0]) +
3251 (color0[1] - color1[1]) * (color0[1] - color1[1]) +
3252 (color0[2] - color1[2]) * (color0[2] - color1[2]));
3253 if (intd + extd == 0.0) err = 1.0;
3254 else err = (intd + emult * extd) / (intd + extd);
3255 color1[0] = err * (color1[0] - tc1[0]);
3256 color1[1] = err * (color1[1] - tc1[1]);
3257 color1[2] = err * (color1[2] - tc1[2]);
3258 }
3259 }
3260 else /* Indiscriminate error damping */
3261 {
3262 color1[0] = (color1[0] - tc1[0]) * emult;
3263 color1[1] = (color1[1] - tc1[1]) * emult;
3264 color1[2] = (color1[2] - tc1[2]) * emult;
3265 }
3266 /* Distribute the error */
3267 color1[0] *= fdiv;
3268 color1[1] *= fdiv;
3269 color1[2] *= fdiv;
3270 for (k = 0; k < 5; k++)
3271 {
3272 kk = j + (k - 2) * dj * 3 + 6;
3273 for (l = 0; l < 3; l++ , kk++)
3274 {
3275 row0[kk] += color1[l] * dither[k];
3276 row1[kk] += color1[l] * dither[k + 5];
3277 row2[kk] += color1[l] * dither[k + 10];
3278 }
3279 }
3280 }
3281 tmp = row0; row0 = row1; row1 = row2; row2 = tmp;
3282 if (progress && (i * 10) % mem_height >= mem_height - 10)
3283 progress_update((float)(i + 1) / mem_height);
3284 }
3285
3286 if (progress) progress_end();
3287 free(ddata);
3288 return (0);
3289 }
3290
3291 /* Dumb (but fast) Floyd-Steinberg dithering in RGB space, loosely based on
3292 * Dennis Lee's dithering implementation from dl3quant.c, in turn based on
3293 * dithering code from the IJG's jpeg library - WJ */
mem_dumb_dither(unsigned char * old,unsigned char * new,png_color * pal,int width,int height,int ncols,int dither)3294 int mem_dumb_dither(unsigned char *old, unsigned char *new, png_color *pal,
3295 int width, int height, int ncols, int dither)
3296 {
3297 unsigned short cols[32768], sqrtb[512], *sqr;
3298 short limtb[512], *lim, fr[3] = {0, 0, 0};
3299 short *rows = NULL, *row0 = fr, *row1 = fr;
3300 unsigned char clamp[768], *src, *dest;
3301 int i, j, k, j0, dj, dj3, r, g, b, rlen, serpent = 2;
3302
3303 /* Allocate working space */
3304 rlen = (width + 2) * 3;
3305 if (dither)
3306 {
3307 rows = calloc(rlen * 2, sizeof(short));
3308 if (!rows) return (1);
3309 serpent = 0;
3310 }
3311
3312 /* Color cache, squares table, clamp table */
3313 memset(cols, 0, sizeof(cols));
3314 sqr = sqrtb + 256;
3315 for (i = -255; i < 256; i++) sqr[i] = i * i;
3316 memset(clamp, 0, 256);
3317 memset(clamp + 512, 255, 256);
3318 for (i = 0; i < 256; i++) clamp[i + 256] = i;
3319
3320 /* Error limiter table, Dennis Lee's way */
3321 #define ERR_LIM 20
3322 lim = limtb + 256;
3323 for (i = 0; i < ERR_LIM; i++)
3324 lim[i] = i , lim[-i] = -i;
3325 for (; i < 256; i++)
3326 lim[i] = ERR_LIM , lim[-i] = -ERR_LIM;
3327 #undef ERR_LIM
3328
3329 /* Process image */
3330 for (i = 0; i < height; i++)
3331 {
3332 src = old + i * width * 3;
3333 dest = new + i * width;
3334 if (serpent ^= 1)
3335 {
3336 j0 = 0; dj = 1;
3337 }
3338 else
3339 {
3340 j0 = (width - 1) * 3; dj = -1;
3341 dest += width - 1;
3342 }
3343 if (dither)
3344 {
3345 row0 = row1 = rows + 3;
3346 *(serpent ? &row1 : &row0) += rlen;
3347 memset(row1 - 3, 0, rlen * sizeof(short));
3348 src += j0; row0 += j0; row1 += j0;
3349 }
3350 dj3 = dj * 3;
3351 for (j = 0; j < width; j++ , src += dj3 , dest += dj)
3352 {
3353 r = clamp[src[0] + ((row0[0] + 0x1008) >> 4)];
3354 g = clamp[src[1] + ((row0[1] + 0x1008) >> 4)];
3355 b = clamp[src[2] + ((row0[2] + 0x1008) >> 4)];
3356 k = ((r & 0xF8) << 7) + ((g & 0xF8) << 2) + (b >> 3);
3357 if (!cols[k]) /* Find nearest color in RGB */
3358 {
3359 int i, j, n = 0, l = 1000000;
3360
3361 /* Searching for color nearest to first color in cell, instead of to cell
3362 * itself, looks like a bug, but works like a feature - makes FS dither less
3363 * prone to patterning. This trick I learned from Dennis Lee's code - WJ */
3364 for (i = 0; i < ncols; i++)
3365 {
3366 j = sqr[r - pal[i].red] +
3367 sqr[g - pal[i].green] +
3368 sqr[b - pal[i].blue];
3369 if (j >= l) continue;
3370 l = j; n = i;
3371 }
3372 cols[k] = n + 1;
3373 }
3374 *dest = k = cols[k] - 1;
3375 if (!dither) continue;
3376
3377 r = lim[r - pal[k].red];
3378 g = lim[g - pal[k].green];
3379 b = lim[b - pal[k].blue];
3380 k = r + r;
3381 row1[0 + dj3] += r;
3382 row1[0 - dj3] += (r += k);
3383 row1[0 + 0 ] += (r += k);
3384 row0[0 + dj3] += r + k;
3385 k = g + g;
3386 row1[1 + dj3] += g;
3387 row1[1 - dj3] += (g += k);
3388 row1[1 + 0 ] += (g += k);
3389 row0[1 + dj3] += g + k;
3390 k = b + b;
3391 row1[2 + dj3] += b;
3392 row1[2 - dj3] += (b += k);
3393 row1[2 + 0 ] += (b += k);
3394 row0[2 + dj3] += b + k;
3395 row0 += dj3; row1 += dj3;
3396 }
3397 }
3398
3399 free(rows);
3400 return (0);
3401 }
3402
mem_find_dither(int red,int green,int blue)3403 void mem_find_dither(int red, int green, int blue)
3404 {
3405 int pat = 4, dp = 3;
3406 int i, ix1, ix2, pn, tpn, pp2 = pat * pat * 2;
3407 double r, g, b, r1, g1, b1, dr0, dg0, db0, dr, dg, db;
3408 double l, l2, tl, t;
3409
3410 r = gamma256[red];
3411 g = gamma256[green];
3412 b = gamma256[blue];
3413 l = 16.0; ix1 = 0;
3414
3415 for (i = 0; i < mem_cols; i++)
3416 {
3417 dr = r - gamma256[mem_pal[i].red];
3418 dg = g - gamma256[mem_pal[i].green];
3419 db = b - gamma256[mem_pal[i].blue];
3420 tl = dr * dr + dg * dg + db * db;
3421 if (tl >= l) continue;
3422 l = tl;
3423 ix1 = i;
3424 }
3425
3426 r1 = gamma256[mem_pal[ix1].red];
3427 g1 = gamma256[mem_pal[ix1].green];
3428 b1 = gamma256[mem_pal[ix1].blue];
3429 dr0 = r - r1;
3430 dg0 = g - g1;
3431 db0 = b - b1;
3432
3433 l2 = l; ix2 = ix1; pn = 0;
3434
3435 for (i = 0; i < mem_cols; i++)
3436 {
3437 if (i == ix1) continue;
3438 dr = gamma256[mem_pal[i].red] - r1;
3439 dg = gamma256[mem_pal[i].green] - g1;
3440 db = gamma256[mem_pal[i].blue] - b1;
3441 t = pp2 * (dr0 * dr + dg0 * dg + db0 * db) /
3442 (dr * dr + dg * dg + db * db);
3443 if ((t <= dp) || (t >= pp2 - dp)) continue;
3444 t = (tpn = rint(0.5 * t)) / (double)(pp2 >> 1);
3445 dr = dr * t - dr0;
3446 dg = dg * t - dg0;
3447 db = db * t - db0;
3448 tl = dr * dr + dg * dg + db * db;
3449 if (tl >= l2) continue;
3450 l2 = tl;
3451 ix2 = i;
3452 pn = tpn;
3453 }
3454
3455 mem_col_A = ix1;
3456 mem_col_B = ix2;
3457 /* !!! A mix with less than half of nearest color cannot be better than it, so
3458 * !!! patterns less dense than 50:50 won't be needed */
3459 mem_tool_pat = -pn; /* pn*4 for 8x8 */
3460 if (pattern_B) mem_tool_pat_B = pn - 16; /* pat**2 */
3461
3462 mem_col_A24 = mem_pal[mem_col_A];
3463 mem_col_B24 = mem_pal[mem_col_B];
3464 }
3465
mem_quantize(unsigned char * old_mem_image,int target_cols,int type)3466 int mem_quantize( unsigned char *old_mem_image, int target_cols, int type )
3467 // type = 1:flat, 2:dither, 3:scatter
3468 {
3469 unsigned char *new_img = mem_img[CHN_IMAGE];
3470 int i, j, k;//, res=0;
3471 int closest[3][2];
3472 png_color pcol;
3473
3474 j = mem_width * mem_height;
3475
3476 progress_init(_("Converting to Indexed Palette"),1);
3477
3478 for ( j=0; j<mem_height; j++ ) // Convert RGB to indexed
3479 {
3480 if ( j%16 == 0)
3481 if (progress_update( ((float) j)/(mem_height) )) break;
3482 for ( i=0; i<mem_width; i++ )
3483 {
3484 pcol.red = old_mem_image[ 3*(i + mem_width*j) ];
3485 pcol.green = old_mem_image[ 1 + 3*(i + mem_width*j) ];
3486 pcol.blue = old_mem_image[ 2 + 3*(i + mem_width*j) ];
3487
3488 closest[0][0] = 0; // 1st Closest palette item to pixel
3489 closest[1][0] = 100000000;
3490 closest[0][1] = 0; // 2nd Closest palette item to pixel
3491 closest[1][1] = 100000000;
3492 for ( k=0; k<target_cols; k++ )
3493 {
3494 closest[2][0] = abs( pcol.red - mem_pal[k].red ) +
3495 abs( pcol.green - mem_pal[k].green ) +
3496 abs( pcol.blue - mem_pal[k].blue );
3497 if ( closest[2][0] < closest[1][0] )
3498 {
3499 closest[0][1] = closest[0][0];
3500 closest[1][1] = closest[1][0];
3501 closest[0][0] = k;
3502 closest[1][0] = closest[2][0];
3503 }
3504 else
3505 {
3506 if ( closest[2][0] < closest[1][1] )
3507 {
3508 closest[0][1] = k;
3509 closest[1][1] = closest[2][0];
3510 }
3511 }
3512 }
3513 if ( type == 1 ) k = closest[0][0]; // Flat conversion
3514 else
3515 {
3516 if ( closest[1][1] == 100000000 ) closest[1][0] = 0;
3517 if ( closest[1][0] == 0 ) k = closest[0][0];
3518 else
3519 {
3520 if ( type == 2 ) // Dithered
3521 {
3522 // if ( closest[1][1]/2 >= closest[1][0] )
3523 if ( closest[1][1]*.67 < (closest[1][1] - closest[1][0]) )
3524 k = closest[0][0];
3525 else
3526 {
3527 if ( closest[0][0] > closest[0][1] )
3528 k = closest[0][ (i+j) % 2 ];
3529 else
3530 k = closest[0][ (i+j+1) % 2 ];
3531 }
3532 }
3533 if ( type == 3 ) // Scattered
3534 {
3535 if ( (rand() % (closest[1][1] + closest[1][0])) <= closest[1][1] )
3536 k = closest[0][0];
3537 else k = closest[0][1];
3538 }
3539 }
3540 }
3541 *new_img++ = k;
3542 }
3543 }
3544 progress_end();
3545
3546 return 0;
3547 }
3548
3549 /* Linear brightness for palette color */
pal2B(png_color * c)3550 double pal2B(png_color *c)
3551 {
3552 return (rgb2B(gamma256[c->red], gamma256[c->green], gamma256[c->blue]));
3553 }
3554
3555 /* Convert image to greyscale */
mem_greyscale(int gcor)3556 void mem_greyscale(int gcor)
3557 {
3558 unsigned char *mask, *img = mem_img[CHN_IMAGE];
3559 int i, j, k, v, ch;
3560
3561 mask = malloc(mem_width);
3562 if (!mask)
3563 {
3564 memory_errors(1);
3565 return;
3566 }
3567 if (mem_img_bpp == 1)
3568 {
3569 for (i = 0; i < 256; i++)
3570 {
3571 if (gcor) /* Gamma correction + Helmholtz-Kohlrausch effect */
3572 {
3573 v = UNGAMMA256(pal2B(mem_pal + i));
3574 }
3575 else /* Usual braindead formula */
3576 {
3577 v = (299 * mem_pal[i].red +
3578 587 * mem_pal[i].green +
3579 114 * mem_pal[i].blue + 500) / 1000;
3580 }
3581 mem_pal[i].red = v;
3582 mem_pal[i].green = v;
3583 mem_pal[i].blue = v;
3584 }
3585 }
3586 else
3587 {
3588 ch = mem_channel;
3589 mem_channel = CHN_IMAGE;
3590 for (i = 0; i < mem_height; i++)
3591 {
3592 row_protected(0, i, mem_width, mask);
3593 for (j = 0; j < mem_width; j++)
3594 if (paint_gamma && mask[j] && (mask[j] != 255))
3595 {
3596 double d, d0, d1, d2, m;
3597 m = 1.0 - mask[j] / 255.0;
3598 d0 = gamma256[img[0]];
3599 d1 = gamma256[img[1]];
3600 d2 = gamma256[img[2]];
3601 /* Gamma + H-K effect / Usual */
3602 d = gcor ? rgb2B(d0, d1, d2) :
3603 gamma256[(299 * img[0] + 587 * img[1] +
3604 114 * img[2] + 500) / 1000];
3605 d0 += (d - d0) * m;
3606 d1 += (d - d1) * m;
3607 d2 += (d - d2) * m;
3608 *img++ = UNGAMMA256(d0);
3609 *img++ = UNGAMMA256(d1);
3610 *img++ = UNGAMMA256(d2);
3611 }
3612 else
3613 {
3614 /* Gamma + H-K effect / Usual */
3615 v = gcor ? UNGAMMA256(rgb2B(gamma256[img[0]],
3616 gamma256[img[1]], gamma256[img[2]])) :
3617 (299 * img[0] + 587 * img[1] +
3618 114 * img[2] + 500) / 1000;
3619 v *= 255 - mask[j];
3620 k = *img * mask[j] + v;
3621 *img++ = (k + (k >> 8) + 1) >> 8;
3622 k = *img * mask[j] + v;
3623 *img++ = (k + (k >> 8) + 1) >> 8;
3624 k = *img * mask[j] + v;
3625 *img++ = (k + (k >> 8) + 1) >> 8;
3626 }
3627 }
3628 mem_channel = ch;
3629 }
3630 free(mask);
3631 }
3632
3633 /* Valid for x=0..5, which is enough here */
3634 #define MOD3(x) ((((x) * 5 + 1) >> 2) & 3)
3635
3636 /* Nonclassical HSV: H is 0..6, S is 0..1, V is 0..255 */
rgb2hsv(unsigned char * rgb,double * hsv)3637 void rgb2hsv(unsigned char *rgb, double *hsv)
3638 {
3639 int c0, c1, c2;
3640
3641 if (!((rgb[0] ^ rgb[1]) | (rgb[0] ^ rgb[2])))
3642 {
3643 hsv[0] = hsv[1] = 0.0;
3644 hsv[2] = rgb[0];
3645 return;
3646 }
3647 c2 = rgb[2] < rgb[0] ? 1 : 0;
3648 if (rgb[c2] >= rgb[c2 + 1]) c2++;
3649 c0 = MOD3(c2 + 1);
3650 c1 = (c2 + c0) ^ 3;
3651 hsv[2] = rgb[c0] > rgb[c1] ? rgb[c0] : rgb[c1];
3652 hsv[1] = hsv[2] - rgb[c2];
3653 hsv[0] = c0 * 2 + 1 + (rgb[c1] - rgb[c0]) / hsv[1];
3654 hsv[1] /= hsv[2];
3655 }
3656
hsv2rgb(unsigned char * rgb,double * hsv)3657 void hsv2rgb(unsigned char *rgb, double *hsv)
3658 {
3659 double h0, h1, h2;
3660 int i;
3661
3662 h2 = hsv[2] * 2;
3663 h1 = h2 * (1.0 - hsv[1]);
3664 i = hsv[0];
3665 h0 = (hsv[0] - i) * (h2 - h1);
3666 if (i & 1) h2 -= h0 , h0 += h2;
3667 else h0 += h1;
3668 i >>= 1;
3669 rgb[i] = ((int)h2 + 1) >> 1;
3670 rgb[MOD3(i + 1)] = ((int)h0 + 1) >> 1;
3671 rgb[MOD3(i + 2)] = ((int)h1 + 1) >> 1;
3672 }
3673
rgb_hsl(int t,png_color col)3674 static double rgb_hsl(int t, png_color col)
3675 {
3676 double hsv[3];
3677 unsigned char rgb[3] = {col.red, col.green, col.blue};
3678
3679 if (t == 2) return (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
3680 rgb2hsv(rgb, hsv);
3681 return (hsv[t]);
3682 }
3683
mem_pal_index_move(int c1,int c2)3684 void mem_pal_index_move( int c1, int c2 ) // Move index c1 to c2 and shuffle in between up/down
3685 {
3686 png_color temp;
3687 int i, j;
3688
3689 if (c1 == c2) return;
3690
3691 j = c1 < c2 ? 1 : -1;
3692 temp = mem_pal[c1];
3693 for (i = c1; i != c2; i += j) mem_pal[i] = mem_pal[i + j];
3694 mem_pal[c2] = temp;
3695 }
3696
mem_canvas_index_move(int c1,int c2)3697 void mem_canvas_index_move( int c1, int c2 ) // Similar to palette item move but reworks canvas pixels
3698 {
3699 unsigned char table[256];
3700 int i;
3701
3702 if (c1 == c2) return;
3703
3704 for (i = 0; i < 256; i++)
3705 {
3706 table[i] = i + (i > c2) - (i > c1);
3707 }
3708 table[c1] = c2;
3709 table[c2] += (c1 > c2);
3710
3711 // Remap transparent color
3712 if (mem_xpm_trans >= 0) mem_xpm_trans = table[mem_xpm_trans];
3713
3714 // Change pixel index to new palette
3715 if (mem_img_bpp == 1) do_xlate(table, mem_img[CHN_IMAGE],
3716 mem_width * mem_height);
3717 }
3718
mem_pal_sort(int a,int i1,int i2,int rev)3719 void mem_pal_sort( int a, int i1, int i2, int rev ) // Sort colours in palette
3720 {
3721 int tab0[256], tab1[256], tmp, i, j;
3722 png_color old_pal[256];
3723 unsigned char map[256];
3724 double lxnA[3], lxn[3];
3725
3726 if ( i2 == i1 || i1>mem_cols || i2>mem_cols ) return;
3727 if ( i2 < i1 )
3728 {
3729 i = i1;
3730 i1 = i2;
3731 i2 = i;
3732 }
3733
3734 if (a == 4) get_lxn(lxnA, PNG_2_INT(mem_col_A24));
3735 if (a == 9) mem_get_histogram(CHN_IMAGE);
3736
3737 for (i = 0; i < 256; i++)
3738 tab0[i] = i;
3739 for (i = i1; i <= i2; i++)
3740 {
3741 switch (a)
3742 {
3743 /* Hue */
3744 case 0: tab1[i] = rint(1024 * rgb_hsl(0, mem_pal[i]));
3745 break;
3746 /* Saturation */
3747 case 1: tab1[i] = rint(1024 * rgb_hsl(1, mem_pal[i]));
3748 break;
3749 /* Luminance */
3750 case 2: tab1[i] = rint(1024 * rgb_hsl(2, mem_pal[i]));
3751 break;
3752 /* Brightness */
3753 case 3: tab1[i] = rint(1024 * pal2B(mem_pal + i));
3754 break;
3755 /* Distance to A */
3756 case 4: get_lxn(lxn, PNG_2_INT(mem_pal[i]));
3757 tab1[i] = rint(1024 * ((lxn[0] - lxnA[0]) *
3758 (lxn[0] - lxnA[0]) + (lxn[1] - lxnA[1]) *
3759 (lxn[1] - lxnA[1]) + (lxn[2] - lxnA[2]) *
3760 (lxn[2] - lxnA[2])));
3761 break;
3762 /* Red */
3763 case 5: tab1[i] = mem_pal[i].red;
3764 break;
3765 /* Green */
3766 case 6: tab1[i] = mem_pal[i].green;
3767 break;
3768 /* Blue */
3769 case 7: tab1[i] = mem_pal[i].blue;
3770 break;
3771 /* Projection on A->B */
3772 case 8: tab1[i] = mem_pal[i].red * (mem_col_B24.red - mem_col_A24.red) +
3773 mem_pal[i].green * (mem_col_B24.green - mem_col_A24.green) +
3774 mem_pal[i].blue * (mem_col_B24.blue - mem_col_A24.blue);
3775 break;
3776 /* Frequency */
3777 case 9: tab1[i] = mem_histogram[i];
3778 break;
3779 }
3780 }
3781
3782 rev = rev ? 1 : 0;
3783 for ( j=i2; j>i1; j-- ) // The venerable bubble sort
3784 for ( i=i1; i<j; i++ )
3785 {
3786 if (tab1[i + 1 - rev] < tab1[i + rev])
3787 {
3788 tmp = tab0[i];
3789 tab0[i] = tab0[i + 1];
3790 tab0[i + 1] = tmp;
3791
3792 tmp = tab1[i];
3793 tab1[i] = tab1[i + 1];
3794 tab1[i + 1] = tmp;
3795 }
3796 }
3797
3798 mem_pal_copy(old_pal, mem_pal);
3799 for (i = 0; i < 256; i++)
3800 {
3801 mem_pal[i] = old_pal[tab0[i]];
3802 map[tab0[i]] = i;
3803 }
3804 if (mem_xpm_trans >= 0) mem_xpm_trans = map[mem_xpm_trans];
3805
3806 if (mem_img_bpp != 1) return;
3807
3808 // Adjust canvas pixels if in indexed palette mode
3809 do_xlate(map, mem_img[CHN_IMAGE], mem_width * mem_height);
3810 /* Modify A & B */
3811 mem_col_A = map[mem_col_A];
3812 mem_col_B = map[mem_col_B];
3813 }
3814
mem_invert()3815 void mem_invert() // Invert the palette
3816 {
3817 int i, j;
3818 png_color *col = mem_pal;
3819 unsigned char *img;
3820
3821 if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
3822 {
3823 for ( i=0; i<256; i++ )
3824 {
3825 col->red = 255 - col->red;
3826 col->green = 255 - col->green;
3827 col->blue = 255 - col->blue;
3828 col++;
3829 }
3830 }
3831 else
3832 {
3833 unsigned char *mask = calloc(1, mem_width);
3834
3835 j = mem_width * mem_height;
3836 if (mem_channel == CHN_IMAGE) j *= 3;
3837 img = mem_img[mem_channel];
3838 for (i = 0; i < j; i++)
3839 {
3840 *img++ ^= 255;
3841 }
3842 if (mask)
3843 {
3844 mask_merge(mem_undo_previous(mem_channel), mem_channel, mask);
3845 free(mask);
3846 }
3847 }
3848 }
3849
mem_normalize()3850 void mem_normalize() // Normalize contrast in image or palette
3851 {
3852 unsigned char map[256], *img = NULL;
3853 png_color *col;
3854 int i, uninit_(j), k, k0, k1;
3855
3856 memset(map, 0, 256);
3857 if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
3858 {
3859 for (i = 0 , col = mem_pal; i < mem_cols; i++ , col++)
3860 {
3861 map[col->red] = 1;
3862 map[col->green] = 1;
3863 map[col->blue] = 1;
3864 }
3865 }
3866 else
3867 {
3868 j = mem_width * mem_height;
3869 if (mem_channel == CHN_IMAGE) j *= 3;
3870 img = mem_img[mem_channel];
3871 for (i = 0; i < j; i++) map[img[i]] = 1;
3872 }
3873
3874 /* Range */
3875 for (i = 0; (i < 255) && !map[i]; i++);
3876 k0 = k1 = i;
3877 for (; i < 256; i++) if (map[i]) k1 = i;
3878 /* Table */
3879 map[k0] = k0; // Default
3880 k = k1 - k0;
3881 if (k) for (i = k0; i <= k1; i++) map[i] = 255 * (i - k0) / k;
3882
3883 if (img)
3884 {
3885 unsigned char *mask = calloc(1, mem_width);
3886
3887 do_xlate(map, img, j);
3888 if (mask)
3889 {
3890 mask_merge(mem_undo_previous(mem_channel), mem_channel, mask);
3891 free(mask);
3892 }
3893 }
3894 else
3895 {
3896 for (i = 0 , col = mem_pal; i < mem_cols; i++ , col++)
3897 {
3898 col->red = map[col->red];
3899 col->green = map[col->green];
3900 col->blue = map[col->blue];
3901 }
3902 }
3903 }
3904
mem_prepare_map(unsigned char * map,int how)3905 void mem_prepare_map(unsigned char *map, int how)
3906 {
3907 int i, n, wrk[3];
3908
3909 memset(map, 0, 768); // Init
3910 /* Greyscale */
3911 if (how == MAP_GREY) for (i = 0; i < 256; i++ , map += 3)
3912 map[0] = map[1] = map[2] = i;
3913 /* Gradient */
3914 else if (how == MAP_GRAD) for (i = 0; i < 256; i++ , map += 3)
3915 {
3916 if (!grad_value(wrk, CHN_IMAGE, i / 255.0)) continue;
3917 map[0] = wrk[0] >> 8;
3918 map[1] = wrk[1] >> 8;
3919 map[2] = wrk[2] >> 8;
3920 }
3921 /* Palette */
3922 else if (how == MAP_PAL) pal2rgb(map, mem_pal, mem_cols, 0);
3923 /* Clipboard */
3924 else if (how == MAP_CLIP)
3925 {
3926 n = mem_clip_w * mem_clip_h;
3927 if (n > 256) n = 256;
3928 if (mem_clip_bpp == 3) memcpy(map, mem_clipboard, n * 3);
3929 else do_convert_rgb(0, 1, n, map, mem_clipboard, mem_pal);
3930 }
3931 }
3932
mem_remap_rgb(unsigned char * map,int what)3933 void mem_remap_rgb(unsigned char *map, int what) // Remap V/R/G/B to color
3934 {
3935 unsigned char *w, *img = mem_img[CHN_IMAGE];
3936 int cnt = mem_width * mem_height;
3937
3938 /* Value */
3939 if (!what) while (cnt-- > 0)
3940 {
3941 int n = img[0] > img[1] ? img[0] : img[1];
3942 n = n > img[2] ? n : img[2];
3943 w = map + n * 3;
3944 *img++ = w[0];
3945 *img++ = w[1];
3946 *img++ = w[2];
3947 }
3948 /* R/G/B */
3949 else while (cnt-- > 0)
3950 {
3951 w = map + img[what - 1] * 3;
3952 *img++ = w[0];
3953 *img++ = w[1];
3954 *img++ = w[2];
3955 }
3956
3957 w = calloc(1, mem_width);
3958 if (w)
3959 {
3960 mask_merge(mem_undo_previous(CHN_IMAGE), CHN_IMAGE, w);
3961 free(w);
3962 }
3963 }
3964
3965 /* Expand palette to RGB triples, pad with 0 if needed */
pal2rgb(unsigned char * rgb,png_color * pal,int cnt,int len)3966 void pal2rgb(unsigned char *rgb, png_color *pal, int cnt, int len)
3967 {
3968 len -= cnt;
3969 while (cnt-- > 0)
3970 {
3971 rgb[0] = pal->red;
3972 rgb[1] = pal->green;
3973 rgb[2] = pal->blue;
3974 rgb += 3; pal++;
3975 }
3976 if (len > 0) memset(rgb, 0, len * 3);
3977 }
3978
3979 /* Pack RGB triples into palette */
rgb2pal(png_color * pal,unsigned char * rgb,int cnt)3980 void rgb2pal(png_color *pal, unsigned char *rgb, int cnt)
3981 {
3982 while (cnt-- > 0)
3983 {
3984 pal->red = rgb[0];
3985 pal->green = rgb[1];
3986 pal->blue = rgb[2];
3987 pal++; rgb += 3;
3988 }
3989 }
3990
3991 /* !!! The rectangles here exclude bottom & right border */
clip(int * rxy,int x0,int y0,int x1,int y1,const int * vxy)3992 int clip(int *rxy, int x0, int y0, int x1, int y1, const int *vxy)
3993 {
3994 rxy[0] = x0 < vxy[0] ? vxy[0] : x0;
3995 rxy[1] = y0 < vxy[1] ? vxy[1] : y0;
3996 rxy[2] = x1 > vxy[2] ? vxy[2] : x1;
3997 rxy[3] = y1 > vxy[3] ? vxy[3] : y1;
3998 return ((rxy[2] > rxy[0]) && (rxy[3] > rxy[1]));
3999 }
4000
4001 /* Intersect outer & inner rectangle, write out 1 to 5 rectangles the outer one
4002 * separates into, return number of outer rectangles */
clip4(int * rect04,int xo,int yo,int wo,int ho,int xi,int yi,int wi,int hi)4003 int clip4(int *rect04, int xo, int yo, int wo, int ho, int xi, int yi, int wi, int hi)
4004 {
4005 int *p = rect04 + 4;
4006 int xo1 = xo + wo, yo1 = yo + ho, xi1 = xi + wi, yi1 = yi + hi;
4007
4008 // Whole outer rectangle
4009 p[0] = xo; p[1] = yo; p[2] = wo; p[3] = ho;
4010 // No intersection
4011 if ((xi >= xo1) || (yi >= yo1) || (xo >= xi1) || (yo >= yi1))
4012 {
4013 rect04[0] = xi; rect04[1] = yi; rect04[2] = rect04[3] = 0;
4014 return (1);
4015 }
4016 if (yi > yo) // Top rectangle
4017 p[3] = yi - yo , p += 4;
4018 else yi = yo;
4019 if (yi1 < yo1) // Bottom rectangle
4020 *p++ = xo , *p++ = yi1 , *p++ = wo , *p++ = yo1 - yi1;
4021 else yi1 = yo1;
4022 hi = yi1 - yi;
4023 if (xi > xo) // Left rectangle
4024 *p++ = xo , *p++ = yi , *p++ = xi - xo , *p++ = hi;
4025 else xi = xo;
4026 if (xi1 < xo1) // Right rectangle
4027 *p++ = xi1 , *p++ = yi , *p++ = xo1 - xi1 , *p++ = hi;
4028 else xi1 = xo1;
4029 wi = xi1 - xi;
4030 // Clipped inner rectangle
4031 rect04[0] = xi; rect04[1] = yi; rect04[2] = wi; rect04[3] = hi;
4032
4033 // Number of outer rectangles
4034 return ((p - rect04 - 4) >> 2);
4035 }
4036
xy_span(int * rxy,int scale,int yf)4037 int xy_span(int *rxy, int scale, int yf)
4038 {
4039 return (floor_div(rxy[2 + yf] - 1, scale) - floor_div(rxy[yf], scale) + 1);
4040 }
4041
xy_origin(int * rxy,int * vxy,int x,int y)4042 void xy_origin(int *rxy, int *vxy, int x, int y)
4043 {
4044 rxy[0] = vxy[0] - x;
4045 rxy[1] = vxy[1] - y;
4046 rxy[2] = vxy[2] - x;
4047 rxy[3] = vxy[3] - y;
4048 }
4049
line_init(linedata line,int x0,int y0,int x1,int y1)4050 void line_init(linedata line, int x0, int y0, int x1, int y1)
4051 {
4052 int i;
4053 line[0] = x0;
4054 line[1] = y0;
4055 line[4] = (x1 - x0) * (line[6] = line[8] = x1 - x0 < 0 ? -1 : 1);
4056 line[5] = (y1 - y0) * (line[7] = line[9] = y1 - y0 < 0 ? -1 : 1);
4057 i = line[4] >= line[5]; /* More horizontal? */
4058 line[2] = line[3] = line[5 - i];
4059 line[4] = 2 * line[4 + i];
4060 line[5] = 2 * line[2];
4061 line[6 + i] = 0;
4062 }
4063
line_step(linedata line)4064 int line_step(linedata line)
4065 {
4066 line[3] -= line[4];
4067 if (line[3] <= 0)
4068 {
4069 line[3] += line[5];
4070 line[0] += line[8];
4071 line[1] += line[9];
4072 }
4073 else
4074 {
4075 line[0] += line[6];
4076 line[1] += line[7];
4077 }
4078 return (--line[2]);
4079 }
4080
line_nudge(linedata line,int x,int y)4081 void line_nudge(linedata line, int x, int y)
4082 {
4083 while ((line[0] != x) && (line[1] != y) && (line[2] >= 0))
4084 line_step(line);
4085 }
4086
4087 /* !!! The clipping rectangle here includes both borders */
line_clip(linedata line,const int * vxy,int * step)4088 int line_clip(linedata line, const int *vxy, int *step)
4089 {
4090 int vh = !line[6], hv = vh ^ 1, hs = line[8 + vh], vs = line[8 + hv];
4091 int dh = hs < 0, dv = vs < 0, l4 = line[4], steps[2];
4092 int i, j, dx, dy;
4093
4094 for (i = 1; 1;)
4095 {
4096 dx = (vxy[(dh ^ i) * 2 + vh] - line[vh]) * hs + i;
4097 if (dx < 0) dx = 0;
4098 if (l4)
4099 {
4100 dy = (vxy[(dv ^ i) * 2 + hv] - line[hv]) * vs + i;
4101 if (dy < 0) dy = 0;
4102 dy = (line[5] * (dy - 1) + line[3] + l4 - 1) / l4;
4103 if ((dy > dx) ^ i) dx = dy;
4104 }
4105 steps[i] = dx;
4106 if (!i--) break;
4107 }
4108
4109 if (line[5]) // Makes no sense for a single point
4110 {
4111 /* Too short? */
4112 if ((line[2] -= dx) < 0) return (line[2]);
4113 dy = (j = l4 * dx + line[5] - line[3]) / line[5];
4114 line[vh] += hs * dx; line[hv] += vs * dy;
4115 line[3] = line[5] * (dy + 1) - j;
4116 }
4117 /* Misses the rectangle? */
4118 if ((line[0] < vxy[0]) || (line[0] > vxy[2]) ||
4119 (line[1] < vxy[1]) || (line[1] > vxy[3])) return (line[2] = -1);
4120 *step = dx;
4121 j = steps[1] - dx - 1;
4122 if (j < line[2]) line[2] = j;
4123 return (line[2]);
4124 }
4125
line_flip(linedata line)4126 void line_flip(linedata line)
4127 {
4128 int l, d2;
4129
4130 if (!line[2]) return; // Single point
4131 l = line[4] * line[2] + line[5] - line[3];
4132 d2 = l / line[5];
4133 line[3] = l - d2 * line[5] + 1;
4134 line[0] += line[2] * line[6] + d2 * (line[8] - line[6]);
4135 line[1] += line[2] * line[7] + d2 * (line[9] - line[7]);
4136 line[6] *= -1; line[7] *= -1;
4137 line[8] *= -1; line[9] *= -1;
4138 }
4139
4140 /* Produce a horizontal segment from two connected lines */
twoline_segment(int * xx,linedata line1,linedata line2)4141 static void twoline_segment(int *xx, linedata line1, linedata line2)
4142 {
4143 xx[0] = xx[1] = line1[0];
4144 while (TRUE)
4145 {
4146 if (!line1[7]) /* Segments longer than 1 pixel */
4147 {
4148 while ((line1[2] > 0) && (line1[3] > line1[4]))
4149 line_step(line1);
4150 }
4151 if (xx[0] > line1[0]) xx[0] = line1[0];
4152 if (xx[1] < line1[0]) xx[1] = line1[0];
4153 if ((line1[2] > 0) || (line2[2] < 0)) break;
4154 memcpy(line1, line2, sizeof(linedata));
4155 line2[2] = -1;
4156 if (xx[0] > line1[0]) xx[0] = line1[0];
4157 if (xx[1] < line1[0]) xx[1] = line1[0];
4158 }
4159 }
4160
sline(int x1,int y1,int x2,int y2)4161 void sline( int x1, int y1, int x2, int y2 ) // Draw single thickness straight line
4162 {
4163 linedata line;
4164
4165 line_init(line, x1, y1, x2, y2);
4166 for (; line[2] >= 0; line_step(line))
4167 {
4168 IF_IN_RANGE(line[0], line[1]) put_pixel(line[0], line[1]);
4169 }
4170 }
4171
4172 void circle_line(int x0, int y0, int dx, int dy, int thick);
4173
tline(int x1,int y1,int x2,int y2,int size)4174 void tline( int x1, int y1, int x2, int y2, int size ) // Draw size thickness straight line
4175 {
4176 linedata line;
4177 int xdo, ydo, todo;
4178
4179 xdo = abs(x2 - x1);
4180 ydo = abs(y2 - y1);
4181 todo = xdo > ydo ? xdo : ydo;
4182 if (todo < 2) return; // The 1st and last points are done by calling procedure
4183
4184 if (size < 2) /* One pixel wide */
4185 {
4186 sline(x1, y1, x2, y2);
4187 return;
4188 }
4189
4190 /* Draw middle segment */
4191 circle_line(x1, y1, x2 - x1, y2 - y1, size);
4192
4193 /* Add four more circles to cover all odd points */
4194 if (!xdo || !ydo || (xdo == ydo)) return; /* Not needed */
4195 line_init(line, x1, y1, x2, y2);
4196 line_nudge(line, x1 + line[8] - 2 * line[6],
4197 y1 + line[9] - 2 * line[7]); /* Jump to first diagonal step */
4198 f_circle(line[0], line[1], size);
4199 f_circle(line[0] - line[8], line[1] - line[9], size);
4200 line_nudge(line, x2, y2); /* Jump to last diagonal step */
4201 f_circle(line[0], line[1], size);
4202 f_circle(line[0] - line[8], line[1] - line[9], size);
4203 }
4204
4205 /* Draw whatever is bounded by two pairs of lines */
draw_quad(linedata line1,linedata line2,linedata line3,linedata line4)4206 void draw_quad(linedata line1, linedata line2, linedata line3, linedata line4)
4207 {
4208 int x1, x2, y1, xx[4];
4209 for (; line1[2] >= 0; line_step(line1) , line_step(line3))
4210 {
4211 y1 = line1[1];
4212 twoline_segment(xx + 0, line1, line2);
4213 twoline_segment(xx + 2, line3, line4);
4214 if ((y1 < 0) || (y1 >= mem_height)) continue;
4215 if (xx[0] > xx[2]) xx[0] = xx[2];
4216 if (xx[1] < xx[3]) xx[1] = xx[3];
4217 x1 = xx[0] < 0 ? 0 : xx[0];
4218 x2 = xx[1] >= mem_width ? mem_width - 1 : xx[1];
4219 put_pixel_row(x1, y1, x2 - x1 + 1, NULL);
4220 }
4221 }
4222
4223 /* Draw general parallelogram */
g_para(int x1,int y1,int x2,int y2,int xv,int yv)4224 void g_para( int x1, int y1, int x2, int y2, int xv, int yv )
4225 {
4226 linedata line1, line2, line3, line4;
4227 int i, j, x[2] = {x1, x2}, y[2] = {y1, y2};
4228
4229 j = (y1 < y2) ^ (yv < 0); i = j ^ 1;
4230 line_init(line1, x[i], y[i], x[i] + xv, y[i] + yv);
4231 line_init(line2, x[i] + xv, y[i] + yv, x[j] + xv, y[j] + yv);
4232 line_init(line3, x[i], y[i], x[j], y[j]);
4233 line_init(line4, x[j], y[j], x[j] + xv, y[j] + yv);
4234 draw_quad(line1, line2, line3, line4);
4235 }
4236
4237 /* Shapeburst engine */
4238
4239 int sb_dist = DIST_L1;
4240 int sb_rect[4];
4241 static void *sb_mem;
4242 static unsigned short *sb_buf;
4243 static uint32_t *sb_buf2;
4244
put_pixel_sb(int x,int y)4245 static void put_pixel_sb(int x, int y)
4246 {
4247 int j, x1, y1;
4248
4249 x1 = x - sb_rect[0];
4250 y1 = y - sb_rect[1];
4251 if ((x1 < 0) || (x1 >= sb_rect[2]) || (y1 < 0) || (y1 >= sb_rect[3]))
4252 return;
4253
4254 j = pixel_protected(x, y);
4255 if (IS_INDEXED ? j : j == 255) return;
4256
4257 if (!sb_buf2) sb_buf[y1 * sb_rect[2] + x1] = 0xFFFF;
4258 else sb_buf2[y1 * sb_rect[2] + x1] = 0xFFFF;
4259 }
4260
4261 static void mask_select(unsigned char *mask, unsigned char *xsel, int l);
4262
put_pixel_row_sb(int x,int y,int len,unsigned char * xsel)4263 static void put_pixel_row_sb(int x, int y, int len, unsigned char *xsel)
4264 {
4265 unsigned char mask[ROW_BUFLEN];
4266 int x1, y1, sb_ofs, offset, use_mask, masked;
4267
4268
4269 if ((len <= 0) || (x + len <= sb_rect[0])) return;
4270 x1 = x - sb_rect[0];
4271 y1 = y - sb_rect[1];
4272 if ((x1 >= sb_rect[2]) || (y1 < 0) || (y1 >= sb_rect[3]))
4273 return;
4274 if (x1 + len > sb_rect[2]) len = sb_rect[2] - x1; // Clip right side
4275 if (x1 < 0) x -= x1 , len += x1 , xsel -= x1 , x1 = 0; // Clip left side
4276
4277 sb_ofs = y1 * sb_rect[2] + x1;
4278 offset = x + mem_width * y;
4279 masked = IS_INDEXED ? 1 : 255;
4280 use_mask = (mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK];
4281
4282 while (TRUE)
4283 {
4284 int i, l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
4285
4286 prep_mask(0, 1, l, mask,
4287 use_mask ? mem_img[CHN_MASK] + offset : NULL,
4288 mem_img[CHN_IMAGE] + offset * mem_img_bpp);
4289
4290 if (xsel)
4291 {
4292 mask_select(mask, xsel, l);
4293 xsel += l;
4294 }
4295
4296 for (i = 0; i < l; i++)
4297 {
4298 if (mask[i] >= masked) continue;
4299 if (!sb_buf2) sb_buf[sb_ofs + i] = 0xFFFF;
4300 else sb_buf2[sb_ofs + i] = 0xFFFF;
4301 }
4302
4303 if (!(len -= l)) return;
4304 sb_ofs += l;
4305 offset += l;
4306 }
4307 }
4308
4309 /* Distance transform of binary image map, using L1 or Linf distance metric */
shapeburst()4310 static int shapeburst()
4311 {
4312 unsigned short *r0, *dmap = sb_buf;
4313 int i, j, k, l, dx, dy, maxd = 0, w = sb_rect[2], h = sb_rect[3];
4314
4315
4316 /* Calculate distance */
4317 r0 = dmap; dx = 1; dy = w; /* Forward pass */
4318 while (TRUE)
4319 {
4320 /* First row */
4321 for (i = 0; i < w; i++ , r0 += dx) if (*r0) *r0 = 1;
4322 /* Other rows */
4323 for (j = 1; j < h; j++)
4324 {
4325 /* 1st pixel */
4326 if (*r0) *r0 = 1; r0 += dx;
4327 /* Other pixels */
4328 for (i = w - 1; i > 0; i-- , r0 += dx)
4329 {
4330 /* L1 */
4331 k = *(r0 - dx); l = *(r0 - dy);
4332 if (k > l) k = l;
4333 if (*r0 > k) *r0 = k + 1;
4334 if (sb_dist != DIST_LINF) continue;
4335 /* Linf */
4336 k = *(r0 - dy - dx); l = *(r0 - dy + dx);
4337 if (k > l) k = l;
4338 if (*r0 > k) *r0 = k + 1;
4339 }
4340 }
4341 if (dx < 0) break; /* Both passes done */
4342 r0 = dmap + w * h - 1; dx = -1; dy = -w; /* Backward pass */
4343 }
4344
4345 /* Find largest */
4346 r0 = dmap;
4347 for (k = w * h; k; k-- , r0++) if (maxd < *r0) maxd = *r0;
4348 return (maxd);
4349 }
4350
4351 /* Meijster algorithm for squared Euclidean distance transform */
4352
4353 typedef struct {
4354 int x, e, v, w;
4355 } par_data;
4356
dist_pass1(int w,int h,uint32_t * dmap)4357 static void dist_pass1(int w, int h, uint32_t *dmap)
4358 {
4359 uint32_t m, *r0;
4360 int i, j, dy;
4361
4362
4363 /* Calculate distance by column */
4364 r0 = dmap; dy = w; /* Forward pass */
4365 while (TRUE)
4366 {
4367 /* First row */
4368 for (i = 0; i < w; i++) if (r0[i]) r0[i] = 1;
4369 /* Other rows */
4370 for (j = 1; j < h; j++)
4371 {
4372 r0 += dy;
4373 for (i = 0; i < w; i++)
4374 {
4375 m = r0[i - dy];
4376 if (r0[i] > m) r0[i] = m + 1;
4377 }
4378 }
4379 if (dy < 0) return; /* Both passes done */
4380 dy = -dy; /* Backward pass */
4381 }
4382 }
4383
dist_pass2_e2(int w,int h,uint32_t * dmap,par_data * pb)4384 static int dist_pass2_e2(int w, int h, uint32_t *dmap, par_data *pb)
4385 {
4386 par_data *pn;
4387 int x, y, mx = 0;
4388
4389 for (y = 0; y < h; y++ , dmap += w)
4390 {
4391 /* Left border */
4392 pn = pb;
4393 pn->x = -1;
4394 pn->e = pn->v = 0;
4395 pn->w = 1; /* v + x^2 */
4396 /* Find envelope */
4397 for (x = 0; ; x++)
4398 {
4399 int k = 0, v2 = 0;
4400
4401 if (x < w) v2 = dmap[x] * dmap[x];
4402 else if (x > w) break;
4403
4404 while (((x - pn->e) * (x - pn->e) + v2) < pn->w)
4405 if (--pn - pb < 0) break;
4406 if (pn - pb >= 0) /* Find intersection */
4407 {
4408 /* 1 + Sep(s[q], u) */
4409 k = (x * x + v2 - pn->x * pn->x - pn->v) /
4410 ((x - pn->x) * 2) + 1;
4411 if (k >= w) continue; // Not inside
4412 }
4413
4414 /* Add a segment */
4415 pn++;
4416 pn->x = x;
4417 pn->v = v2;
4418 pn->e = k;
4419 pn->w = (x - k) * (x - k) + v2;
4420 }
4421
4422 /* Fill up squared distances */
4423 // !!! Also possible to run left to right, by using _next_ slot's "e"
4424 // (only then need one extra slot allocated, and set pn[1].e=w every time)
4425 // (but then, may loop to e, and only then check if this e >= w)
4426 for (x = w - 1; x >= 0; x--)
4427 {
4428 int l = pn->v + (x - pn->x) * (x - pn->x);
4429 if (mx < l) mx = l; // Finding the max
4430 dmap[x] = l;
4431 if (x == pn->e) pn--;
4432 }
4433 }
4434
4435 return (mx);
4436 }
4437
4438 /* Euclidean (L2 metric) distance transform of binary image map */
shapeburst_m()4439 static int shapeburst_m()
4440 {
4441 int maxd, w = sb_rect[2], h = sb_rect[3];
4442
4443 dist_pass1(w, h, sb_buf2);
4444 maxd = dist_pass2_e2(w, h, sb_buf2, sb_mem);
4445 return (ceil(sqrt(maxd)));
4446 }
4447
init_sb()4448 int init_sb()
4449 {
4450 int l = sb_rect[2] + 3, wh = sb_rect[2] * sb_rect[3];
4451
4452 if (sb_dist != DIST_L2) /* Use simple distance algorithm */
4453 sb_mem = sb_buf = calloc(wh, sizeof(unsigned short));
4454 /* Use squared Euclidean distance */
4455 else if ((sb_mem = calloc(1, l * sizeof(par_data) + wh * sizeof(uint32_t))))
4456 {
4457 /* Pointer to uint32 array */
4458 sb_buf2 = (void *)((par_data *)sb_mem + l);
4459 }
4460 if (!sb_mem)
4461 {
4462 memory_errors(1);
4463 return (FALSE);
4464 }
4465 put_pixel = put_pixel_sb;
4466 put_pixel_row = put_pixel_row_sb;
4467 return (TRUE);
4468 }
4469
4470 /* Mask, if present, must be sb_rect[] sized */
render_sb(unsigned char * mask)4471 void render_sb(unsigned char *mask)
4472 {
4473 grad_info svgrad, *grad = gradient + mem_channel;
4474 int i, maxd;
4475
4476 if (!sb_mem) return; /* Uninitialized */
4477 put_pixel = put_pixel_def;
4478 put_pixel_row = put_pixel_row_def;
4479 maxd = sb_dist != DIST_L2 ? shapeburst() : shapeburst_m();
4480 if (maxd) /* Have something to draw */
4481 {
4482 svgrad = *grad;
4483 grad->gmode = GRAD_MODE_BURST;
4484 if (!grad->len) grad->len = maxd - (maxd > 1);
4485 grad_update(grad);
4486
4487 for (i = 0; i < sb_rect[3]; i++)
4488 put_pixel_row(sb_rect[0], sb_rect[1] + i, sb_rect[2],
4489 mask ? mask + sb_rect[2] * i : NULL);
4490
4491 *grad = svgrad;
4492 }
4493 free(sb_mem);
4494 sb_buf2 = sb_mem = sb_buf = NULL;
4495 }
4496
4497 /*
4498 * This flood fill algorithm processes image in quadtree order, and thus has
4499 * guaranteed upper bound on memory consumption, of order O(width + height).
4500 * This implementation takes O(max(width, height)) for simplicity - X and Y
4501 * bitmaps are interleaved.
4502 * (C) Dmitry Groshev
4503 */
4504
4505 #define QLEVELS 11
4506 #define QMINSIZE 32
4507 #define QMINLEVEL 5
4508
4509 /*
4510 * Level bitmaps are ordered from nearest to farthest, with cells interleaved
4511 * in the following order: Left-Y Right-Y Top-X Bottom-X.
4512 * Pixel bitmap is packed by Y, not by X: byte[x, y / 8] |= 1 << (y % 8)
4513 */
4514
wjfloodfill(int x,int y,int col,unsigned char * bmap)4515 static int wjfloodfill(int x, int y, int col, unsigned char *bmap)
4516 {
4517 short nearq[QMINSIZE * QMINSIZE * 2];
4518 /* QMINSIZE bits per cell */
4519 guint32 tmap, lmap[(MAX_DIM >> QMINLEVEL) * 12 + QLEVELS * 4], maps[4];
4520 int borders[4] = {0, mem_width, 0, mem_height};
4521 int corners[4], coords[4], slots[4];
4522 int i, j, k, tx, ty, fmode = 0, imgc = 0, lastr[3], thisr[3];
4523 int lmax, ntail, bidx = 0, bbit = 0;
4524 double lastc[3], thisc[3], dist2, mdist2 = flood_step * flood_step;
4525 csel_info *flood_data = NULL;
4526 char *tmp = NULL;
4527
4528 /* Init */
4529 if ((x < 0) || (x >= mem_width) || (y < 0) || (y >= mem_height) ||
4530 (get_pixel(x, y) != col) || (pixel_protected(x, y) == 255))
4531 return (FALSE);
4532 /* Exact limits are less, but it's too complicated */
4533 lmax = mem_width > mem_height ? mem_width : mem_height;
4534 lmax = (lmax >> QMINLEVEL) * 12 + QLEVELS * 4;
4535 memset(lmap, 0, lmax * sizeof(*lmap));
4536
4537 /* Start drawing */
4538 if (bmap) bmap[(y >> 3) * mem_width + x] |= 1 << (y & 7);
4539 else
4540 {
4541 put_pixel(x, y);
4542 if (get_pixel(x, y) == col) return (FALSE); /* Can't draw */
4543 }
4544
4545 /* Configure fuzzy flood fill */
4546 if (flood_step && ((mem_channel == CHN_IMAGE) || flood_img))
4547 {
4548 if (flood_slide) fmode = flood_cube ? 2 : 3;
4549 else flood_data = ALIGN(tmp = calloc(1, sizeof(csel_info) + sizeof(double)));
4550 if (flood_data)
4551 {
4552 flood_data->center = get_pixel_RGB(x, y);
4553 flood_data->range = flood_step;
4554 flood_data->mode = flood_cube ? 2 : 0;
4555 /* !!! Alpha isn't tested yet !!! */
4556 csel_reset(flood_data);
4557 fmode = 1;
4558 }
4559 }
4560 /* Configure by-image flood fill */
4561 else if (!flood_step && flood_img && (mem_channel != CHN_IMAGE))
4562 {
4563 imgc = get_pixel_img(x, y);
4564 fmode = -1;
4565 }
4566
4567 /* Set up initial area */
4568 corners[0] = x & ~(QMINSIZE - 1);
4569 corners[2] = y & ~(QMINSIZE - 1);
4570 nearq[0] = x; nearq[1] = y; ntail = 2;
4571
4572 while (1)
4573 {
4574 corners[1] = corners[0] + QMINSIZE;
4575 corners[3] = corners[2] + QMINSIZE;
4576
4577 for (i = 0; i < 4; i++)
4578 {
4579 int j, k, i2 = (i >> 1) ^ 1;
4580 int wx = corners[i2 + i2], wy = corners[i];
4581
4582 /* Locate map slots */
4583 j = ((unsigned)(wy & ~(wy - 1)) - 1) >> QMINLEVEL; // Level mask
4584 j += j; k = (wx >> QMINLEVEL) & (j + 1);
4585 slots[i] = k = (j + k) * 4 + i;
4586
4587 /* Prefill near queue */
4588 if (k >= lmax) continue; // Outside image
4589 k ^= 1; tmap = lmap[k]; lmap[k] = 0;
4590 for (wy -= i & 1; tmap; wx++ , tmap >>= 1)
4591 {
4592 if (!(tmap & 1)) continue;
4593 nearq[ntail++ + i2] = wx;
4594 nearq[ntail++ - i2] = wy;
4595 }
4596 }
4597
4598 /* Clear the side bitmaps */
4599 maps[0] = maps[1] = maps[2] = maps[3] = 0;
4600 // memset(maps, 0, sizeof(maps));
4601
4602 /* Process near points */
4603 while (ntail)
4604 {
4605 /* Unqueue last x & y */
4606 coords[2] = y = nearq[--ntail];
4607 coords[0] = x = nearq[--ntail];
4608 if (fmode > 1)
4609 {
4610 k = get_pixel_RGB(x, y);
4611 if (fmode == 3) get_lxn(lastc, k);
4612 else
4613 {
4614 lastr[0] = INT_2_R(k);
4615 lastr[1] = INT_2_G(k);
4616 lastr[2] = INT_2_B(k);
4617 }
4618 }
4619 for (i = 0; i < 4; i++)
4620 {
4621 coords[1] = x;
4622 coords[3] = y;
4623 coords[(i & 2) + 1] += ((i + i) & 2) - 1;
4624 /* Is pixel valid? */
4625 if (coords[i] == borders[i]) continue;
4626 tx = coords[1];
4627 ty = coords[3];
4628 if (bmap)
4629 {
4630 bidx = (ty >> 3) * mem_width + tx;
4631 bbit = 1 << (ty & 7);
4632 if (bmap[bidx] & bbit) continue;
4633 }
4634 /* Sliding mode */
4635 switch (fmode)
4636 {
4637 case 3: /* Sliding L*X*N* */
4638 get_lxn(thisc, get_pixel_RGB(tx, ty));
4639 dist2 = (thisc[0] - lastc[0]) * (thisc[0] - lastc[0]) +
4640 (thisc[1] - lastc[1]) * (thisc[1] - lastc[1]) +
4641 (thisc[2] - lastc[2]) * (thisc[2] - lastc[2]);
4642 if (dist2 > mdist2) continue;
4643 break;
4644 case 2: /* Sliding RGB */
4645 k = get_pixel_RGB(tx, ty);
4646 thisr[0] = INT_2_R(k);
4647 thisr[1] = INT_2_G(k);
4648 thisr[2] = INT_2_B(k);
4649 if ((abs(thisr[0] - lastr[0]) > flood_step) ||
4650 (abs(thisr[1] - lastr[1]) > flood_step) ||
4651 (abs(thisr[2] - lastr[2]) > flood_step))
4652 continue;
4653 break;
4654 case 1: /* Centered mode */
4655 if (!csel_scan(ty * mem_width + tx, 1, 1,
4656 NULL, mem_img[CHN_IMAGE], flood_data))
4657 continue;
4658 break;
4659 case 0: /* Normal mode */
4660 if (get_pixel(tx, ty) != col) continue;
4661 break;
4662 default: /* (-1) - By-image mode */
4663 if (get_pixel_img(tx, ty) != imgc) continue;
4664 break;
4665 }
4666 /* Is pixel writable? */
4667 if (bmap)
4668 {
4669 if (pixel_protected(tx, ty) == 255)
4670 continue;
4671 bmap[bidx] |= bbit;
4672 }
4673 else
4674 {
4675 put_pixel(tx, ty);
4676 if (get_pixel(tx, ty) == col) continue;
4677 }
4678 /* Near queue */
4679 // if (coords[i] != corners[i])
4680 if (coords[i] & (QMINSIZE - 1))
4681 {
4682 nearq[ntail++] = tx;
4683 nearq[ntail++] = ty;
4684 continue;
4685 }
4686 /* Far map */
4687 j = coords[(i & 2) ^ 3] & (QMINSIZE - 1);
4688 maps[i] |= 1U << j;
4689 }
4690 }
4691
4692 /* Store maps */
4693 for (i = 0; i < 4; i++)
4694 {
4695 /* !!! Condition prevents out-of-bounds access */
4696 if (maps[i]) lmap[slots[i]] |= maps[i];
4697 }
4698
4699 /* Find what else remains */
4700 for (i = 0; (i < lmax) && !lmap[i]; i++);
4701 if (i >= lmax) break; // All done
4702
4703 /* Determine where that happens to be */
4704 j = ((i >> 2) + 2) << QMINLEVEL;
4705 k = nextpow2(j) >> 1; // MSB
4706 x = (k >> 1) + ((i & 1) << QMINLEVEL) - QMINSIZE;
4707 y = j - k;
4708 i &= 2;
4709 corners[i] = (corners[i] & ~(k - 1)) + x;
4710 i ^= 2;
4711 corners[i] = (corners[i] & ~(k - 1)) + y;
4712 }
4713 free(tmp);
4714 return (TRUE);
4715 }
4716
4717 /* Determine Y-packed bitmap boundaries */
bitmap_bounds(int * rect,unsigned char * pat)4718 static int bitmap_bounds(int *rect, unsigned char *pat)
4719 {
4720 unsigned char u, c, buf[MAX_WIDTH];
4721 int n, x, y, y0, y1, w = rect[2], h = (rect[3] + 7) >> 3;
4722
4723
4724 /* Scan */
4725 memset(buf, 0, w);
4726 for (y0 = y1 = y = 0; y < h; y++)
4727 {
4728 for (u = x = 0; x < w; x++)
4729 u |= c = *pat++ , buf[x] |= c;
4730 if (!u) continue;
4731 y1 = (y << 8) + u;
4732 if (!y0) y0 = y1;
4733 }
4734 if (!y0) return (0); // Empty
4735
4736 /* Analyze */
4737 for (y = (y0 >> 8) * 8; !(y0 & 1); y++ , y0 >>= 1);
4738 rect[1] += n = y;
4739 for (y = (y1 >> 8) * 8 + 7; !(y1 & 0x80); y-- , y1 <<= 1);
4740 rect[3] = y -= n - 1; // h
4741 for (x = 0; !buf[x]; x++);
4742 rect[0] += n = x;
4743 for (x = w - 1; !buf[x]; x--);
4744 rect[2] = x -= n - 1; // w
4745
4746 return (x * y);
4747 }
4748
4749 /* Try drawing on a pixel */
try_pixel(int x,int y)4750 int try_pixel(int x, int y)
4751 {
4752 unsigned char uninit_(ab), ib[3], *img, *uninit_(alpha);
4753 int res, bpp = MEM_BPP, ofs = x + mem_width * y, op = mem_undo_opacity;
4754
4755 img = mem_img[mem_channel] + ofs * bpp;
4756 memcpy(ib, img, bpp);
4757 if (mem_img[CHN_ALPHA]) ab = *(alpha = mem_img[CHN_ALPHA] + ofs);
4758
4759 mem_undo_opacity = FALSE; // No prepared undo frame
4760 put_pixel_def(x, y);
4761 mem_undo_opacity = op;
4762
4763 res = memcmp(ib, img, bpp);
4764 memcpy(img, ib, bpp);
4765 if (mem_img[CHN_ALPHA])
4766 {
4767 res |= *alpha ^ ab;
4768 *alpha = ab;
4769 }
4770 return (res);
4771 }
4772
4773 /* Flood fill - may use temporary area (1 bit per pixel) */
flood_fill(int x,int y,unsigned int target)4774 int flood_fill(int x, int y, unsigned int target)
4775 {
4776 unsigned char *pat, *buf, *temp;
4777 int i, j, l, sb, res = FALSE;
4778
4779 /* Regular fill? */
4780 if (!mem_gradient && !(mem_blend && blend_src) && !mem_tool_pat &&
4781 !flood_step && (!flood_img || (mem_channel == CHN_IMAGE)))
4782 {
4783 /* Try modifying the first pixel */
4784 if (!try_pixel(x, y)) return (FALSE);
4785 spot_undo(UNDO_TOOL);
4786 return (wjfloodfill(x, y, target, NULL));
4787 }
4788
4789 /* Patterned or fuzzy fill - use bitmap */
4790 buf = calloc((mem_height + 7 + 8) >> 3, mem_width);
4791 if (!buf)
4792 {
4793 memory_errors(1);
4794 return (FALSE);
4795 }
4796 pat = buf + mem_width;
4797 while (wjfloodfill(x, y, target, pat))
4798 {
4799 /* Shapeburst - setup rendering backbuffer */
4800 sb = STROKE_GRADIENT;
4801 if (sb)
4802 {
4803 sb_rect[0] = sb_rect[1] = 0;
4804 sb_rect[2] = mem_width;
4805 sb_rect[3] = mem_height;
4806 l = bitmap_bounds(sb_rect, pat);
4807 if (!l) break; /* Nothing to draw */
4808 if (!init_sb()) break; /* Not enough memory */
4809 }
4810
4811 res = TRUE;
4812 spot_undo(UNDO_TOOL);
4813 for (i = 0; i < mem_height; i++)
4814 {
4815 unsigned u, f = 1 << (i & 7);
4816
4817 temp = pat + (i >> 3) * mem_width;
4818 for (u = j = 0; j < mem_width; j++)
4819 u |= buf[j] = (0x10000 - (temp[j] & f)) >> 8;
4820 if (!u) continue; // Avoid wasting time on empty rows
4821 put_pixel_row(0, i, mem_width, buf);
4822 }
4823
4824 if (sb) render_sb(NULL); /* Finalize */
4825
4826 break;
4827 }
4828 free(buf);
4829 return (res);
4830 }
4831
4832
f_rectangle(int x,int y,int w,int h)4833 void f_rectangle(int x, int y, int w, int h) // Draw a filled rectangle
4834 {
4835 w += x; h += y;
4836 if (x < 0) x = 0;
4837 if (y < 0) y = 0;
4838 if (w > mem_width) w = mem_width;
4839 if (h > mem_height) h = mem_height;
4840 w -= x;
4841
4842 /* !!! Test is oversimplified and is overkill, see rec_continuous() */
4843 if ((tool_type == TOOL_CLONE) && (clone_dy < 0))
4844 {
4845 while (--h >= y) put_pixel_row(x, h, w, NULL);
4846 return;
4847 }
4848
4849 for (; y < h; y++) put_pixel_row(x, y, w, NULL);
4850 }
4851
4852 /*
4853 * This code uses midpoint ellipse algorithm modified for uncentered ellipses,
4854 * with floating-point arithmetics to prevent overflows. (C) Dmitry Groshev
4855 */
trace_ellipse(int w,int h,int * left,int * right)4856 static void trace_ellipse(int w, int h, int *left, int *right)
4857 {
4858 int dx, dy;
4859 double err, stx, sty, w2, h2;
4860
4861 if (left[0] > w) left[0] = w;
4862 if (right[0] < w) right[0] = w;
4863
4864 if (h <= 1) return; /* Too small */
4865
4866 h2 = h * h;
4867 w2 = w * w;
4868 dx = w & 1;
4869 dy = h;
4870 stx = h2 * dx;
4871 sty = w2 * dy;
4872 err = h2 * (dx * 5 + 4) + w2 * (1 - h - h);
4873
4874 while (1) /* Have to force first step */
4875 {
4876 if (left[dy >> 1] > dx) left[dy >> 1] = dx;
4877 if (right[dy >> 1] < dx) right[dy >> 1] = dx;
4878 if (err >= 0.0)
4879 {
4880 dy -= 2;
4881 sty -= w2 + w2;
4882 err -= 4.0 * sty;
4883 }
4884 dx += 2;
4885 stx += h2 + h2;
4886 err += 4.0 * (h2 + stx);
4887 if ((dy < 2) || (stx >= sty)) break;
4888 }
4889
4890 err += 3.0 * (w2 - h2) - 2.0 * (stx + sty);
4891
4892 while (dy > 1)
4893 {
4894 if (left[dy >> 1] > dx) left[dy >> 1] = dx;
4895 if (right[dy >> 1] < dx) right[dy >> 1] = dx;
4896 if (err < 0.0)
4897 {
4898 dx += 2;
4899 stx += h2 + h2;
4900 err += 4.0 * stx;
4901 }
4902 dy -= 2;
4903 sty -= w2 + w2;
4904 err += 4.0 * (w2 - sty);
4905 }
4906
4907 /* For too-flat ellipses */
4908 if (left[1] > dx) left[1] = dx;
4909 if (right[1] < w - 2) right[1] = w - 2;
4910 }
4911
wjellipse(int xs,int ys,int w,int h,int type,int thick)4912 static void wjellipse(int xs, int ys, int w, int h, int type, int thick)
4913 {
4914 int i, j, k, dx0, dx1, dy, *left, *right;
4915
4916 /* Prepare */
4917 ys += ys + --h;
4918 xs += xs + --w;
4919 k = type ? w + 1 : w & 1;
4920 j = h / 2 + 1;
4921 left = malloc(2 * j * sizeof(int));
4922 if (!left) return;
4923 right = left + j;
4924 for (i = 0; i < j; i++)
4925 {
4926 left[i] = k;
4927 right[i] = 0;
4928 }
4929
4930 /* Plot outer */
4931 trace_ellipse(w, h, left, right);
4932
4933 /* Plot inner */
4934 if (type && (thick > 1))
4935 {
4936 int i, j, k;
4937
4938 /* Determine possible height */
4939 thick += thick - 2;
4940 for (i = h; i >= 0; i -= 2)
4941 {
4942 if (left[i >> 1] > thick + 1) break;
4943 }
4944 i = i >= h - thick ? h - thick : i + 2;
4945
4946 /* Determine possible width */
4947 j = left[thick >> 1];
4948 if (j > w - thick) j = w - thick;
4949 if (j < 2) i = h & 1;
4950
4951 /* Do the plotting */
4952 for (k = i >> 1; k <= h >> 1; k++) left[k] = w & 1;
4953 if (i > 1) trace_ellipse(j, i, left, right);
4954 }
4955
4956 /* Draw result */
4957 for (dy = h & 1; dy <= h; dy += 2)
4958 {
4959 int y0 = ys - dy, y1 = ys + dy;
4960
4961 if (y1 < 0) continue;
4962 if (y0 < 0) y0 = y1;
4963 y0 >>= 1; y1 >>= 1;
4964 if (y0 >= mem_height) continue;
4965
4966 dx0 = right[dy >> 1];
4967 dx1 = left[dy >> 1];
4968 if (dx1 <= 1) dx1 = -dx0; // Merge two spans
4969 while (TRUE)
4970 {
4971 int x0 = xs - dx0, x1 = xs - dx1;
4972
4973 if ((x1 >= 0) && (x0 < mem_width * 2))
4974 {
4975 x0 >>= 1; x1 >>= 1;
4976 if (x0 < 0) x0 = 0;
4977 if (++x1 > mem_width) x1 = mem_width;
4978 x1 -= x0;
4979 put_pixel_row(x0, y0, x1, NULL);
4980 if (y1 != y0) put_pixel_row(x0, y1, x1, NULL);
4981 }
4982 if (dx1 <= 0) break;
4983 x1 = -dx0; dx0 = -dx1; dx1 = x1;
4984 }
4985 }
4986
4987 free(left);
4988 }
4989
4990 /* Thickness 0 means filled */
mem_ellipse(int x1,int y1,int x2,int y2,int thick)4991 void mem_ellipse(int x1, int y1, int x2, int y2, int thick)
4992 {
4993 int xs, ys, xl, yl, sb = FALSE;
4994
4995 xs = x1 < x2 ? x1 : x2;
4996 ys = y1 < y2 ? y1 : y2;
4997 xl = abs(x2 - x1) + 1;
4998 yl = abs(y2 - y1) + 1;
4999
5000 /* Shapeburst mode */
5001 if (STROKE_GRADIENT)
5002 {
5003 sb_rect[0] = xs; sb_rect[1] = ys;
5004 sb_rect[2] = xl; sb_rect[3] = yl;
5005 sb = init_sb();
5006 }
5007
5008 /* Draw rectangle instead if too small */
5009 if ((xl <= 2) || (yl <= 2)) f_rectangle(xs, ys, xl, yl);
5010 else wjellipse(xs, ys, xl, yl, thick && (thick * 2 < xl) &&
5011 (thick * 2 < yl), thick);
5012
5013 if (sb) render_sb(NULL);
5014 }
5015
5016 static int circ_r, circ_trace[128];
5017
retrace_circle(int r)5018 static void retrace_circle(int r)
5019 {
5020 int sz, left[128];
5021
5022 circ_r = r--;
5023 sz = ((r >> 1) + 1) * sizeof(int);
5024 memset(left, 0, sz);
5025 memset(circ_trace, 0, sz);
5026 trace_ellipse(r, r, left, circ_trace);
5027 }
5028
f_circle(int x,int y,int r)5029 void f_circle( int x, int y, int r ) // Draw a filled circle
5030 {
5031 int i, x0, x1, y0, y1, r1 = r - 1, half = r1 & 1;
5032
5033 /* Prepare & cache circle contour */
5034 if (circ_r != r) retrace_circle(r);
5035
5036 /* Draw result */
5037 for (i = half; i <= r1; i += 2)
5038 {
5039 y0 = y - ((i + half) >> 1);
5040 y1 = y + ((i - half) >> 1);
5041 if ((y0 >= mem_height) || (y1 < 0)) continue;
5042
5043 x0 = x - ((circ_trace[i >> 1] + half) >> 1);
5044 x1 = x + ((circ_trace[i >> 1] - half) >> 1) + 1;
5045 if (x0 < 0) x0 = 0;
5046 if (x1 > mem_width) x1 = mem_width;
5047 x1 -= x0;
5048 if (y0 >= 0) put_pixel_row(x0, y0, x1, NULL);
5049 if ((y1 != y0) && (y1 < mem_height)) put_pixel_row(x0, y1, x1, NULL);
5050 }
5051 }
5052
find_tangent(int dx,int dy)5053 static int find_tangent(int dx, int dy)
5054 {
5055 int i, j = 0, yy = (circ_r + 1) & 1, d, dist = 0;
5056
5057 dx = abs(dx); dy = abs(dy);
5058 for (i = 0; i < (circ_r + 1) >> 1; i++)
5059 {
5060 d = (i + i + yy) * dy + circ_trace[i] * dx;
5061 if (d < dist) continue;
5062 dist = d;
5063 j = i;
5064 }
5065 return (j);
5066 }
5067
5068 /* Draw line as if traced by circle brush */
circle_line(int x0,int y0,int dx,int dy,int thick)5069 void circle_line(int x0, int y0, int dx, int dy, int thick)
5070 {
5071 int n, ix, iy, xx[2], yy[2], dt = (thick + 1) & 1;
5072
5073 if (circ_r != thick) retrace_circle(thick);
5074 n = find_tangent(dx, dy);
5075 ix = dx >= 0 ? 0 : 1;
5076 iy = dy >= 0 ? 0 : 1;
5077 xx[ix] = x0 - n - dt;
5078 xx[ix ^ 1] = x0 + n;
5079 yy[iy] = y0 + ((circ_trace[n] - dt) >> 1);
5080 yy[iy ^ 1] = y0 - ((circ_trace[n] + dt) >> 1);
5081
5082 g_para(xx[0], yy[0], xx[1], yy[1], dx, dy);
5083 }
5084
mem_flip_v(char * mem,char * tmp,int w,int h,int bpp)5085 void mem_flip_v(char *mem, char *tmp, int w, int h, int bpp)
5086 {
5087 unsigned char *src, *dest;
5088 int i, k;
5089
5090 k = w * bpp;
5091 src = mem;
5092 dest = mem + (h - 1) * k;
5093 h /= 2;
5094
5095 for (i = 0; i < h; i++)
5096 {
5097 memcpy(tmp, src, k);
5098 memcpy(src, dest, k);
5099 memcpy(dest, tmp, k);
5100 src += k;
5101 dest -= k;
5102 }
5103 }
5104
mem_flip_h(char * mem,int w,int h,int bpp)5105 void mem_flip_h( char *mem, int w, int h, int bpp )
5106 {
5107 unsigned char tmp, *src, *dest;
5108 int i, j, k;
5109
5110 k = w * bpp;
5111 w /= 2;
5112 for (i = 0; i < h; i++)
5113 {
5114 src = mem + i * k;
5115 dest = src + k - bpp;
5116 if (bpp == 1)
5117 {
5118 for (j = 0; j < w; j++)
5119 {
5120 tmp = *src;
5121 *src++ = *dest;
5122 *dest-- = tmp;
5123 }
5124 }
5125 else
5126 {
5127 for (j = 0; j < w; j++)
5128 {
5129 tmp = src[0];
5130 src[0] = dest[0];
5131 dest[0] = tmp;
5132 tmp = src[1];
5133 src[1] = dest[1];
5134 dest[1] = tmp;
5135 tmp = src[2];
5136 src[2] = dest[2];
5137 dest[2] = tmp;
5138 src += 3;
5139 dest -= 3;
5140 }
5141 }
5142 }
5143 }
5144
mem_bacteria(int val)5145 void mem_bacteria( int val ) // Apply bacteria effect val times the canvas area
5146 { // Ode to 1994 and my Acorn A3000
5147 int i, j, x, y, w = mem_width-2, h = mem_height-2, tot = w*h, np, cancel;
5148 unsigned int pixy;
5149 unsigned char *img;
5150
5151 while ( tot > PROGRESS_LIM ) // Ensure the user gets a regular opportunity to cancel
5152 {
5153 tot /= 2;
5154 val *= 2;
5155 }
5156
5157 cancel = (w * h * val > PROGRESS_LIM);
5158 if (cancel) progress_init(_("Bacteria Effect"), 1);
5159
5160 for ( i=0; i<val; i++ )
5161 {
5162 if (cancel && ((i * 20) % val >= val - 20))
5163 if (progress_update((float)i / val)) break;
5164
5165 for ( j=0; j<tot; j++ )
5166 {
5167 x = rand() % w;
5168 y = rand() % h;
5169 img = mem_img[CHN_IMAGE] + x + mem_width * y;
5170 pixy = img[0] + img[1] + img[2];
5171 img += mem_width;
5172 pixy += img[0] + img[1] + img[2];
5173 img += mem_width;
5174 pixy += img[0] + img[1] + img[2];
5175 np = ((pixy + pixy + 9) / 18 + 1) % mem_cols;
5176 *(img - mem_width + 1) = (unsigned char)np;
5177 }
5178 }
5179 if (cancel) progress_end();
5180 }
5181
mem_rotate(char * new,char * old,int old_w,int old_h,int dir,int bpp)5182 void mem_rotate( char *new, char *old, int old_w, int old_h, int dir, int bpp )
5183 {
5184 unsigned char *src;
5185 int i, j, k, l, flag;
5186
5187 flag = (old_w * old_h > PROGRESS_LIM * 4);
5188 j = old_w * bpp;
5189 l = dir ? -bpp : bpp;
5190 k = -old_w * l;
5191 old += dir ? j - bpp: (old_h - 1) * j;
5192
5193 if (flag) progress_init(_("Rotating"), 1);
5194 for (i = 0; i < old_w; i++)
5195 {
5196 if (flag && ((i * 5) % old_w >= old_w - 5))
5197 progress_update((float)i / old_w);
5198 src = old;
5199 if (bpp == 1)
5200 {
5201 for (j = 0; j < old_h; j++)
5202 {
5203 *new++ = *src;
5204 src += k;
5205 }
5206 }
5207 else
5208 {
5209 for (j = 0; j < old_h; j++)
5210 {
5211 *new++ = src[0];
5212 *new++ = src[1];
5213 *new++ = src[2];
5214 src += k;
5215 }
5216 }
5217 old += l;
5218 }
5219 if (flag) progress_end();
5220 }
5221
mem_sel_rot(int dir)5222 int mem_sel_rot( int dir ) // Rotate clipboard 90 degrees
5223 {
5224 unsigned char *buf = NULL;
5225 int i, j = mem_clip_w * mem_clip_h, bpp = mem_clip_bpp;
5226
5227 for (i = 0; i < NUM_CHANNELS; i++ , bpp = 1)
5228 {
5229 if (!mem_clip.img[i]) continue;
5230 buf = malloc(j * bpp);
5231 if (!buf) break; // Not enough memory
5232 mem_rotate(buf, mem_clip.img[i], mem_clip_w, mem_clip_h, dir, bpp);
5233 free(mem_clip.img[i]);
5234 mem_clip.img[i] = buf;
5235 }
5236
5237 /* Don't leave a mix of rotated and unrotated channels */
5238 if (!buf && i) mem_free_image(&mem_clip, FREE_ALL);
5239 if (!buf) return (1);
5240
5241 i = mem_clip_w;
5242 mem_clip_w = mem_clip_h; // Flip geometry
5243 mem_clip_h = i;
5244
5245 return (0);
5246 }
5247
5248 /* Clear the channels */
mem_clear_img(chanlist img,int w,int h,int bpp)5249 static void mem_clear_img(chanlist img, int w, int h, int bpp)
5250 {
5251 int i, j, k, l = w * h;
5252
5253 if (!img[CHN_IMAGE]); // !!! Here, image channel CAN be absent
5254 else if (bpp == 3)
5255 {
5256 unsigned char *tmp = img[CHN_IMAGE];
5257 tmp[0] = mem_col_A24.red;
5258 tmp[1] = mem_col_A24.green;
5259 tmp[2] = mem_col_A24.blue;
5260 j = l * 3;
5261 for (i = 3; i < j; i++) tmp[i] = tmp[i - 3];
5262 }
5263 else memset(img[CHN_IMAGE], mem_col_A, l);
5264
5265 for (k = CHN_IMAGE + 1; k < NUM_CHANNELS; k++)
5266 if (img[k]) memset(img[k], 0, l);
5267 }
5268
mem_rotate_free_real(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,int bpp,double angle,int mode,int gcor,int dis_a,int silent)5269 void mem_rotate_free_real(chanlist old_img, chanlist new_img, int ow, int oh,
5270 int nw, int nh, int bpp, double angle, int mode, int gcor, int dis_a,
5271 int silent)
5272 {
5273 unsigned char *src, *dest, *alpha, A_rgb[3];
5274 unsigned char *pix1, *pix2, *pix3, *pix4;
5275 int nx, ny, ox, oy, cc;
5276 double rangle = (M_PI / 180.0) * angle; // Radians
5277 double s1, s2, c1, c2; // Trig values
5278 double cx0, cy0, cx1, cy1;
5279 double x00, y00, x0y, y0y; // Quick look up values
5280 double fox, foy, k1, k2, k3, k4; // Pixel weights
5281 double aa1, aa2, aa3, aa4, aa;
5282 double rr, gg, bb;
5283 double tw, th, ta, ca, sa, sca, csa, Y00, Y0h, Yw0, Ywh, X00, Xwh;
5284
5285 c2 = cos(rangle);
5286 s2 = sin(rangle);
5287 c1 = -s2;
5288 s1 = c2;
5289
5290 /* Centerpoints, including half-pixel offsets */
5291 cx0 = (ow - 1) / 2.0;
5292 cy0 = (oh - 1) / 2.0;
5293 cx1 = (nw - 1) / 2.0;
5294 cy1 = (nh - 1) / 2.0;
5295
5296 x00 = cx0 - cx1 * s1 - cy1 * s2;
5297 y00 = cy0 - cx1 * c1 - cy1 * c2;
5298 A_rgb[0] = mem_col_A24.red;
5299 A_rgb[1] = mem_col_A24.green;
5300 A_rgb[2] = mem_col_A24.blue;
5301
5302 /* Prepare clipping rectangle */
5303 tw = 0.5 * (ow + (mode ? 1 : 0));
5304 th = 0.5 * (oh + (mode ? 1 : 0));
5305 ta = M_PI * (angle / 180.0 - floor(angle / 180.0));
5306 ca = cos(ta); sa = sin(ta);
5307 sca = ca ? sa / ca : 0.0;
5308 csa = sa ? ca / sa : 0.0;
5309 Y00 = cy1 - th * ca - tw * sa;
5310 Y0h = cy1 + th * ca - tw * sa;
5311 Yw0 = cy1 - th * ca + tw * sa;
5312 Ywh = cy1 + th * ca + tw * sa;
5313 X00 = cx1 - tw * ca + th * sa;
5314 Xwh = cx1 + tw * ca - th * sa;
5315
5316 mem_clear_img(new_img, nw, nh, bpp); /* Clear the channels */
5317
5318 for (ny = 0; ny < nh; ny++)
5319 {
5320 int xl, xm;
5321 if (!silent && ((ny * 10) % nh >= nh - 10))
5322 progress_update((float)ny / nh);
5323
5324 /* Clip this row */
5325 if (ny < Y0h) xl = ceil(X00 + (Y00 - ny) * sca);
5326 else if (ny < Ywh) xl = ceil(Xwh + (ny - Ywh) * csa);
5327 else /* if (ny < Yw0) */ xl = ceil(Xwh + (Ywh - ny) * sca);
5328 if (ny < Y00) xm = ceil(X00 + (Y00 - ny) * sca);
5329 else if (ny < Yw0) xm = ceil(X00 + (ny - Y00) * csa);
5330 else /* if (ny < Ywh) */ xm = ceil(Xwh + (Ywh - ny) * sca);
5331 if (xl < 0) xl = 0;
5332 if (--xm >= nw) xm = nw - 1;
5333
5334 x0y = ny * s2 + x00;
5335 y0y = ny * c2 + y00;
5336 for (cc = 0; cc < NUM_CHANNELS; cc++)
5337 {
5338 if (!new_img[cc]) continue;
5339 /* RGB nearest neighbour */
5340 if (!mode && (cc == CHN_IMAGE) && (bpp == 3))
5341 {
5342 dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
5343 for (nx = xl; nx <= xm; nx++ , dest += 3)
5344 {
5345 WJ_ROUND(ox, nx * s1 + x0y);
5346 WJ_ROUND(oy, nx * c1 + y0y);
5347 src = old_img[CHN_IMAGE] +
5348 (oy * ow + ox) * 3;
5349 dest[0] = src[0];
5350 dest[1] = src[1];
5351 dest[2] = src[2];
5352 }
5353 continue;
5354 }
5355 /* One-bpp nearest neighbour */
5356 if (!mode)
5357 {
5358 dest = new_img[cc] + ny * nw + xl;
5359 for (nx = xl; nx <= xm; nx++)
5360 {
5361 WJ_ROUND(ox, nx * s1 + x0y);
5362 WJ_ROUND(oy, nx * c1 + y0y);
5363 *dest++ = old_img[cc][oy * ow + ox];
5364 }
5365 continue;
5366 }
5367 /* RGB/RGBA bilinear */
5368 if (cc == CHN_IMAGE)
5369 {
5370 alpha = NULL;
5371 if (new_img[CHN_ALPHA] && !dis_a)
5372 alpha = new_img[CHN_ALPHA] + ny * nw + xl;
5373 dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
5374 for (nx = xl; nx <= xm; nx++ , dest += 3)
5375 {
5376 fox = nx * s1 + x0y;
5377 foy = nx * c1 + y0y;
5378 /* floor() is *SLOW* on Win32 - avoiding... */
5379 ox = (int)(fox + 2.0) - 2;
5380 oy = (int)(foy + 2.0) - 2;
5381 fox -= ox;
5382 foy -= oy;
5383 k4 = fox * foy;
5384 k3 = foy - k4;
5385 k2 = fox - k4;
5386 k1 = 1.0 - fox - foy + k4;
5387 pix1 = old_img[CHN_IMAGE] + (oy * ow + ox) * 3;
5388 pix2 = pix1 + 3;
5389 pix3 = pix1 + ow * 3;
5390 pix4 = pix3 + 3;
5391 if (ox > ow - 2) pix2 = pix4 = A_rgb;
5392 else if (ox < 0) pix1 = pix3 = A_rgb;
5393 if (oy > oh - 2) pix3 = pix4 = A_rgb;
5394 else if (oy < 0) pix1 = pix2 = A_rgb;
5395 if (alpha)
5396 {
5397 aa1 = aa2 = aa3 = aa4 = 0.0;
5398 src = old_img[CHN_ALPHA] + oy * ow + ox;
5399 if (pix1 != A_rgb) aa1 = src[0] * k1;
5400 if (pix2 != A_rgb) aa2 = src[1] * k2;
5401 if (pix3 != A_rgb) aa3 = src[ow] * k3;
5402 if (pix4 != A_rgb) aa4 = src[ow + 1] * k4;
5403 aa = aa1 + aa2 + aa3 + aa4;
5404 if ((*alpha++ = rint(aa)))
5405 {
5406 aa = 1.0 / aa;
5407 k1 = aa1 * aa;
5408 k2 = aa2 * aa;
5409 k3 = aa3 * aa;
5410 k4 = aa4 * aa;
5411 }
5412 }
5413 if (gcor) /* Gamma-correct */
5414 {
5415 rr = gamma256[pix1[0]] * k1 +
5416 gamma256[pix2[0]] * k2 +
5417 gamma256[pix3[0]] * k3 +
5418 gamma256[pix4[0]] * k4;
5419 gg = gamma256[pix1[1]] * k1 +
5420 gamma256[pix2[1]] * k2 +
5421 gamma256[pix3[1]] * k3 +
5422 gamma256[pix4[1]] * k4;
5423 bb = gamma256[pix1[2]] * k1 +
5424 gamma256[pix2[2]] * k2 +
5425 gamma256[pix3[2]] * k3 +
5426 gamma256[pix4[2]] * k4;
5427 dest[0] = UNGAMMA256(rr);
5428 dest[1] = UNGAMMA256(gg);
5429 dest[2] = UNGAMMA256(bb);
5430 }
5431 else /* Leave as is */
5432 {
5433 rr = pix1[0] * k1 + pix2[0] * k2 +
5434 pix3[0] * k3 + pix4[0] * k4;
5435 gg = pix1[1] * k1 + pix2[1] * k2 +
5436 pix3[1] * k3 + pix4[1] * k4;
5437 bb = pix1[2] * k1 + pix2[2] * k2 +
5438 pix3[2] * k3 + pix4[2] * k4;
5439 dest[0] = rint(rr);
5440 dest[1] = rint(gg);
5441 dest[2] = rint(bb);
5442 }
5443 }
5444 continue;
5445 }
5446 /* Alpha channel already done... maybe */
5447 if ((cc == CHN_ALPHA) && !dis_a)
5448 continue;
5449 /* Utility channel bilinear */
5450 dest = new_img[cc] + ny * nw + xl;
5451 for (nx = xl; nx <= xm; nx++)
5452 {
5453 fox = nx * s1 + x0y;
5454 foy = nx * c1 + y0y;
5455 /* floor() is *SLOW* on Win32 - avoiding... */
5456 ox = (int)(fox + 2.0) - 2;
5457 oy = (int)(foy + 2.0) - 2;
5458 fox -= ox;
5459 foy -= oy;
5460 k4 = fox * foy;
5461 k3 = foy - k4;
5462 k2 = fox - k4;
5463 k1 = 1.0 - fox - foy + k4;
5464 src = old_img[cc] + oy * ow + ox;
5465 aa1 = aa2 = aa3 = aa4 = 0.0;
5466 if (ox < ow - 1)
5467 {
5468 if (oy < oh - 1) aa4 = src[ow + 1] * k4;
5469 if (oy >= 0) aa2 = src[1] * k2;
5470 }
5471 if (ox >= 0)
5472 {
5473 if (oy < oh - 1) aa3 = src[ow] * k3;
5474 if (oy >= 0) aa1 = src[0] * k1;
5475 }
5476 *dest++ = rint(aa1 + aa2 + aa3 + aa4);
5477 }
5478 }
5479 }
5480 }
5481
5482 #define PIX_ADD (127.0 / 128.0) /* Include all _visibly_ altered pixels */
5483
mem_rotate_geometry(int ow,int oh,double angle,int * nw,int * nh)5484 void mem_rotate_geometry(int ow, int oh, double angle, int *nw, int *nh)
5485 // Get new image geometry of rotation. angle = degrees
5486 {
5487 int dx, dy;
5488 double rangle = (M_PI / 180.0) * angle, // Radians
5489 s2, c2; // Trig values
5490
5491
5492 c2 = fabs(cos(rangle));
5493 s2 = fabs(sin(rangle));
5494
5495 /* Preserve original centering */
5496 dx = ow & 1; dy = oh & 1;
5497 /* Exchange Y with X when rotated Y is nearer to old X */
5498 if ((dx ^ dy) && (c2 < s2)) dx ^= 1 , dy ^= 1;
5499 *nw = 2 * (int)(0.5 * (ow * c2 + oh * s2 - dx) + PIX_ADD) + dx;
5500 *nh = 2 * (int)(0.5 * (oh * c2 + ow * s2 - dy) + PIX_ADD) + dy;
5501 }
5502
5503 // Rotate canvas or clipboard by any angle (degrees)
mem_rotate_free(double angle,int type,int gcor,int clipboard)5504 int mem_rotate_free(double angle, int type, int gcor, int clipboard)
5505 {
5506 chanlist old_img, new_img;
5507 int ow, oh, nw, nh, res, rot_bpp;
5508
5509
5510 if (clipboard)
5511 {
5512 if (!mem_clipboard) return (-1); // Nothing to rotate
5513 ow = mem_clip_w;
5514 oh = mem_clip_h;
5515 rot_bpp = mem_clip_bpp;
5516 }
5517 else
5518 {
5519 ow = mem_width;
5520 oh = mem_height;
5521 rot_bpp = mem_img_bpp;
5522 }
5523
5524 mem_rotate_geometry(ow, oh, angle, &nw, &nh);
5525
5526 if ( nw>MAX_WIDTH || nh>MAX_HEIGHT ) return -5; // If new image is too big return -5
5527
5528 if (!clipboard)
5529 {
5530 memcpy(old_img, mem_img, sizeof(chanlist));
5531 res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL);
5532 if (res) return (res); // No undo space
5533 memcpy(new_img, mem_img, sizeof(chanlist));
5534 progress_init(_("Free Rotation"), 0);
5535 }
5536 else
5537 {
5538 /* Note: even if the original clipboard doesn't have a mask,
5539 * the rotation will need one to chop off the corners of
5540 * a rotated rectangle. */
5541 if (!mem_clip_mask && mem_clip_mask_init(255))
5542 return (1); // Not enough memory
5543
5544 res = mem_clip_new(nw, nh, mem_clip_bpp,
5545 cmask_from(mem_clip.img), old_img);
5546 if (res) return (1); // Not enough memory
5547 memcpy(new_img, mem_clip.img, sizeof(chanlist));
5548 }
5549
5550 if ( rot_bpp == 1 ) type = FALSE;
5551 mem_rotate_free_real(old_img, new_img, ow, oh, nw, nh, rot_bpp, angle, type,
5552 gcor, channel_dis[CHN_ALPHA] && !clipboard, clipboard);
5553 if (!clipboard) progress_end();
5554
5555 /* Lose old unwanted clipboard */
5556 if (clipboard) mem_free_chanlist(old_img);
5557
5558 return 0;
5559 }
5560
mem_image_rot(int dir)5561 int mem_image_rot( int dir ) // Rotate image 90 degrees
5562 {
5563 chanlist old_img;
5564 int i, ow = mem_width, oh = mem_height;
5565
5566 memcpy(old_img, mem_img, sizeof(chanlist));
5567 i = undo_next_core(UC_NOCOPY, oh, ow, mem_img_bpp, CMASK_ALL);
5568 if (i) return (i); // Not enough memory
5569
5570 for (i = 0; i < NUM_CHANNELS; i++)
5571 {
5572 if (!mem_img[i]) continue;
5573 mem_rotate(mem_img[i], old_img[i], ow, oh, dir, BPP(i));
5574 }
5575 mem_undo_prepare();
5576 return 0;
5577 }
5578
5579
5580
5581 /// Code for scaling contributed by Dmitry Groshev, January 2006
5582 /// Multicore support added by Dmitry Groshev, November 2010
5583
5584 typedef struct {
5585 float *k;
5586 int idx;
5587 } fstep;
5588
Cubic(double x,double A)5589 static double Cubic(double x, double A)
5590 {
5591 if (x < -1.5) return (0.0);
5592 else if (x < -0.5) return (A * (-1.0 / 8.0) * (((x * 8.0 + 28.0) * x +
5593 30.0) * x + 9.0));
5594 else if (x < 0.5) return (0.5 * (((-4.0 * A - 4.0) * x * x + A + 3.0) *
5595 x + 1.0));
5596 else if (x < 1.5) return (A * (-1.0 / 8.0) * (((x * 8.0 - 28.0) * x +
5597 30.0) * x - 9.0) + 1.0);
5598 else return (1.0);
5599 }
5600
BH1(double x)5601 static double BH1(double x)
5602 {
5603 if (x < 1e-7) return (1.0);
5604 return ((sin(M_PI * x) / (M_PI * x)) * (0.42323 +
5605 0.49755 * cos(x * (M_PI * 2.0 / 6.0)) +
5606 0.07922 * cos(x * (M_PI * 4.0 / 6.0))));
5607 }
5608
BH(double x)5609 static double BH(double x)
5610 {
5611 double y = 0.0, xx = fabs(x);
5612
5613 if (xx < 2.5)
5614 {
5615 y = BH1(xx + 0.5);
5616 if (xx < 1.5) y += BH1(xx + 1.5);
5617 if (xx < 0.5) y += BH1(xx + 2.5);
5618 }
5619 return (x > 0.0 ? 1.0 - y : y);
5620 }
5621
5622 static const double Aarray[4] = {-0.5, -2.0 / 3.0, -0.75, -1.0};
5623
5624 /* !!! Filter as a whole must be perfectly symmetric, and "idx" of step 0
5625 * must be <= 0; these natural properties are relied on when allocating and
5626 * extending horizontal temp arrays for BOUND_TILE mode.
5627 * 2 extra steps at end hold end pointer & index, and terminating NULL. */
make_filter(int l0,int l1,int type,int sharp,int bound)5628 static fstep *make_filter(int l0, int l1, int type, int sharp, int bound)
5629 {
5630 fstep *res, *buf;
5631 __typeof__(*res->k) *kp;
5632 double x, y, basept, scale;
5633 double A = 0.0, kk = 1.0, sum;
5634 int i, j, k, ix, j0, fwidth, delta, k0 = 0;
5635
5636
5637 /* Untransformed bilinear is useless for reduction */
5638 if (type == 1) sharp = TRUE;
5639
5640 /* 1:1 transform is special */
5641 if (l1 == l0) type = 0;
5642
5643 switch (type)
5644 {
5645 case 1: fwidth = 2; /* Bilinear / Area-mapping */
5646 break;
5647 case 2: case 3: case 4: case 5: /* Bicubic, all flavors */
5648 fwidth = 4;
5649 A = Aarray[type - 2];
5650 break;
5651 case 6: fwidth = 6; /* Blackman-Harris windowed sinc */
5652 break;
5653 default: /* 1:1 */
5654 fwidth = 0;
5655 break;
5656 }
5657 type *= 2;
5658
5659 scale = (double)l1 / (double)l0;
5660 /* !!! fwidth is rational (l1 denominator) to prevent rounding errors */
5661 if (l1 < l0)
5662 {
5663 kk = scale;
5664 fwidth *= l0;
5665 if (sharp) fwidth += l1 - l0 , type++;
5666 }
5667 else fwidth *= l1;
5668
5669 buf = multialloc(MA_ALIGN_DOUBLE, &res, (l1 + 2) * sizeof(*res),
5670 &kp, (fwidth + l1) * sizeof(*res->k), NULL);
5671 if (!buf) return (NULL);
5672 res = buf; /* No need to double-align the index array */
5673
5674 /* To correct scale-shift */
5675 delta = l0 - l1; // 2*l1 denominator
5676
5677 for (i = l1 , l1 *= 2; i > 0; i-- , buf++ , delta += l0 * 2)
5678 {
5679 basept = delta / (double)l1;
5680 j = j0 = ceil_div(delta - fwidth, l1);
5681 k = k0 = (delta + fwidth) / l1 + 1;
5682 if (j0 < 0) j0 = 0;
5683 if (k0 > l0) k0 = l0;
5684 /* If filter doesn't cover source from end to end, tiling will
5685 * require physical copying */
5686 if ((bound == BOUND_TILE) && (k0 - j0 < l0))
5687 k0 = k , j0 = j;
5688 buf->idx = j0;
5689 buf->k = kp;
5690 kp += k0 - j0;
5691 sum = 0.0;
5692 for (; j < k; j++)
5693 {
5694 ix = j;
5695 if ((j < j0) || (j >= k0))
5696 {
5697 if (bound == BOUND_VOID) continue;
5698 if (bound == BOUND_TILE)
5699 {
5700 if (ix < 0) ix = k0 - (-ix % k0);
5701 ix %= k0;
5702 }
5703 else if (k0 == 1) ix = 0;
5704 else
5705 {
5706 ix = abs(ix) % (k0 + k0 - 2);
5707 if (ix >= k0) ix = k0 + k0 - 2 - ix;
5708 }
5709 }
5710 ix -= j0;
5711 x = fabs(((double)j - basept) * kk);
5712 switch (type)
5713 {
5714 case 0: /* 1:1 */
5715 case 2: /* Bilinear */
5716 y = 1.0 - x;
5717 break;
5718 case 3: /* Area mapping */
5719 if (x <= 0.5 - scale / 2.0) y = 1.0;
5720 else y = 0.5 - (x - 0.5) / scale;
5721 break;
5722 case 4: case 6: case 8: case 10: /* Bicubic */
5723 if (x < 1.0) y = ((A + 2.0) * x - (A + 3)) * x * x + 1.0;
5724 else y = A * (((x - 5.0) * x + 8.0) * x - 4.0);
5725 break;
5726 case 5: case 7: case 9: case 11: /* Sharpened bicubic */
5727 y = Cubic(x + scale * 0.5, A) - Cubic(x - scale * 0.5, A);
5728 break;
5729 case 12: /* Blackman-Harris */
5730 y = BH1(x);
5731 break;
5732 case 13: /* Sharpened Blackman-Harris */
5733 y = BH(x + scale * 0.5) - BH(x - scale * 0.5);
5734 break;
5735 default: /* Bug */
5736 y = 0;
5737 break;
5738 }
5739 buf->k[ix] += y;
5740 sum += y;
5741 }
5742 /* Normalize */
5743 if ((sum != 0.0) && (sum != 1.0))
5744 {
5745 __typeof__(*kp) *tp = buf->k;
5746 sum = 1.0 / sum;
5747 while (tp != kp) *tp++ *= sum;
5748 }
5749 }
5750 /* Finalize */
5751 buf->idx = k0; // The rightmost extent
5752 buf->k = kp;
5753
5754 return (res);
5755 }
5756
5757 typedef struct {
5758 int tmask, gcor, progress;
5759 int ow, oh, nw, nh, bpp;
5760 unsigned char **src, **dest;
5761 double *rgb;
5762 fstep *hfilter, *vfilter;
5763 threaddata *tdata; // For simplicity
5764 } scale_context;
5765
clear_scale(scale_context * ctx)5766 static void clear_scale(scale_context *ctx)
5767 {
5768 free(ctx->hfilter);
5769 free(ctx->vfilter);
5770 free(ctx->tdata);
5771 }
5772
prepare_scale(scale_context * ctx,int type,int sharp,int bound)5773 static int prepare_scale(scale_context *ctx, int type, int sharp, int bound)
5774 {
5775 ctx->hfilter = ctx->vfilter = NULL;
5776 ctx->tdata = NULL;
5777
5778 /* We don't use threading for NN */
5779 if (!type || (ctx->bpp == 1)) return (TRUE);
5780
5781 if ((ctx->hfilter = make_filter(ctx->ow, ctx->nw, type, sharp, bound)) &&
5782 (ctx->vfilter = make_filter(ctx->oh, ctx->nh, type, sharp, bound)))
5783 {
5784 int l = (ctx->ow - ctx->hfilter[0].idx * 2) * sizeof(double);
5785 if ((ctx->tdata = talloc(MA_ALIGN_DOUBLE,
5786 image_threads(ctx->nw, ctx->nh), ctx, sizeof(*ctx),
5787 NULL,
5788 // !!! No space for RGBAS for now
5789 &ctx->rgb, l * (ctx->tmask ? 7 : 3),
5790 NULL))) return (TRUE);
5791 }
5792
5793 clear_scale(ctx);
5794 return (FALSE);
5795 }
5796
tile_extend(double * temp,int w,int l)5797 static void tile_extend(double *temp, int w, int l)
5798 {
5799 memcpy(temp - l, temp + w - l, l * sizeof(*temp));
5800 memcpy(temp + w, temp, l * sizeof(*temp));
5801 }
5802
5803 typedef void REGPARM2 (*istore_func)(unsigned char *img, const double *sum);
5804
istore_gc(unsigned char * img,const double * sum)5805 static void REGPARM2 istore_gc(unsigned char *img, const double *sum)
5806 {
5807 /* Reverse gamma correction */
5808 img[0] = UNGAMMA256X(sum[0]);
5809 img[1] = UNGAMMA256X(sum[1]);
5810 img[2] = UNGAMMA256X(sum[2]);
5811 }
5812
istore_3(unsigned char * img,const double * sum)5813 static void REGPARM2 istore_3(unsigned char *img, const double *sum)
5814 {
5815 int j = (int)rint(sum[0]);
5816 img[0] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5817 j = (int)rint(sum[1]);
5818 img[1] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5819 j = (int)rint(sum[2]);
5820 img[2] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5821 }
5822
istore_1(unsigned char * img,const double * sum)5823 static void REGPARM2 istore_1(unsigned char *img, const double *sum)
5824 {
5825 int j = (int)rint(sum[0]);
5826 img[0] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5827 }
5828
5829 /* !!! Once again, beware of GCC misoptimization! The two functions below
5830 * should not be both inlineable at once, otherwise poor code wasting both
5831 * time and space will be produced - WJ */
5832
scale_row(fstep * tmpy,fstep * hfilter,double * work_area,int bpp,int gc,int ow,int oh,int nw,int i,unsigned char * src,unsigned char * dest)5833 static void scale_row(fstep *tmpy, fstep *hfilter, double *work_area,
5834 int bpp, int gc, int ow, int oh, int nw, int i,
5835 unsigned char *src, unsigned char *dest)
5836 {
5837 /* !!! Protect from possible stack misalignment */
5838 unsigned char sum_[4 * sizeof(double)];
5839 double *sum = ALIGNED(sum_, sizeof(double));
5840 istore_func istore;
5841 unsigned char *img;
5842 fstep *tmpx;
5843 __typeof__(*tmpy->k) *kp = tmpy->k - tmpy->idx;
5844 int j, y, h = tmpy[1].k - kp, ll = hfilter[0].idx;
5845
5846
5847 work_area -= ll * bpp;
5848 ow *= bpp;
5849 memset(work_area, 0, ow * sizeof(double));
5850 /* Build one vertically-scaled row */
5851 for (y = tmpy->idx; y < h; y++)
5852 {
5853 const double tk = kp[y];
5854 double *wrk = work_area;
5855 /* Only simple tiling isn't built into filter */
5856 img = src + ((y + oh) % oh) * ow;
5857 if (gc) /* Gamma-correct */
5858 {
5859 for (j = 0; j < ow; j++)
5860 *wrk++ += gamma256[*img++] * tk;
5861 }
5862 else /* Leave as is */
5863 {
5864 for (j = 0; j < ow; j++)
5865 *wrk++ += *img++ * tk;
5866 }
5867 }
5868 tile_extend(work_area, ow, -ll * bpp);
5869 /* Scale it horizontally */
5870 istore = gc ? istore_gc : bpp == 1 ? istore_1 : istore_3;
5871 img = dest + i * nw * bpp;
5872 for (tmpx = hfilter; tmpx[1].k; tmpx++ , img += bpp)
5873 {
5874 __typeof__(*tmpx->k) *tp, *kp = tmpx[1].k;
5875 double *wrk = work_area + tmpx->idx * bpp;
5876 double sum0, sum1, sum2;
5877
5878 sum0 = sum1 = sum2 = 0.0;
5879 tp = tmpx->k;
5880 while (tp != kp)
5881 {
5882 const double kk = *tp++;
5883 sum0 += *wrk++ * kk;
5884 if (bpp == 1) continue;
5885 sum1 += *wrk++ * kk;
5886 sum2 += *wrk++ * kk;
5887 }
5888 sum[0] = sum0; sum[1] = sum1; sum[2] = sum2;
5889 istore(img, sum);
5890 }
5891 }
5892
scale_rgba(fstep * tmpy,fstep * hfilter,double * work_area,int bpp,int gc,int ow,int oh,int nw,int i,unsigned char * src,unsigned char * dest,unsigned char * srca,unsigned char * dsta)5893 static void scale_rgba(fstep *tmpy, fstep *hfilter, double *work_area,
5894 int bpp, int gc, int ow, int oh, int nw, int i,
5895 unsigned char *src, unsigned char *dest,
5896 unsigned char *srca, unsigned char *dsta)
5897 {
5898 /* !!! Protect from possible stack misalignment */
5899 unsigned char sum_[4 * sizeof(double)];
5900 double *sum = ALIGNED(sum_, sizeof(double));
5901 istore_func istore;
5902 unsigned char *img, *imga;
5903 fstep *tmpx;
5904 __typeof__(*tmpy->k) *kp = tmpy->k - tmpy->idx;
5905 int j, y, h = tmpy[1].k - kp, ll = hfilter[0].idx;
5906 double *wrka = work_area + ow * 6 - ll * 13;
5907
5908
5909 work_area -= ll * 6;
5910 memset(work_area, 0, (ow - ll) * 7 * sizeof(double));
5911 for (y = tmpy->idx; y < h; y++)
5912 {
5913 double *wrk = work_area;
5914 unsigned char *img, *imga;
5915 int ix = (y + oh) % oh;
5916
5917 img = src + ix * ow * 3;
5918 imga = srca + ix * ow;
5919 if (gc) /* Gamma-correct */
5920 {
5921 const double tk = kp[y];
5922 for (j = 0; j < ow; j++)
5923 {
5924 const double kk = imga[j] * tk;
5925 double tv;
5926
5927 wrka[j] += kk;
5928 wrk[0] += (tv = gamma256[img[0]]) * tk;
5929 wrk[3] += tv * kk;
5930 wrk[1] += (tv = gamma256[img[1]]) * tk;
5931 wrk[4] += tv * kk;
5932 wrk[2] += (tv = gamma256[img[2]]) * tk;
5933 wrk[5] += tv * kk;
5934 wrk += 6; img += 3;
5935 }
5936 }
5937 else /* Leave as is */
5938 {
5939 const double tk = kp[y];
5940 for (j = 0; j < ow; j++)
5941 {
5942 const double kk = imga[j] * tk;
5943 double tv;
5944
5945 wrka[j] += kk;
5946 wrk[0] += (tv = img[0]) * tk;
5947 wrk[3] += tv * kk;
5948 wrk[1] += (tv = img[1]) * tk;
5949 wrk[4] += tv * kk;
5950 wrk[2] += (tv = img[2]) * tk;
5951 wrk[5] += tv * kk;
5952 wrk += 6; img += 3;
5953 }
5954 }
5955 }
5956 tile_extend(work_area, ow * 6, -ll * 6);
5957 tile_extend(wrka, ow, -ll);
5958 /* Scale it horizontally */
5959 istore = gc ? istore_gc : bpp == 1 ? istore_1 : istore_3;
5960 img = dest + i * nw * 3;
5961 imga = dsta + i * nw;
5962 for (tmpx = hfilter; tmpx[1].k; tmpx++)
5963 {
5964 __typeof__(*tmpx->k) *tp, *kp = tmpx[1].k;
5965 double *wrk;
5966 double sum0, sum1, sum2, mult;
5967
5968 sum0 = 0.0;
5969 wrk = wrka + tmpx->idx;
5970 tp = tmpx->k;
5971 while (tp != kp) sum0 += *wrk++ * *tp++;
5972 j = (int)rint(sum0);
5973 *imga = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5974 wrk = work_area + tmpx->idx * 6;
5975 mult = 1.0;
5976 if (*imga++)
5977 {
5978 wrk += 3;
5979 mult /= sum0;
5980 }
5981 sum0 = sum1 = sum2 = 0.0;
5982 tp = tmpx->k;
5983 while (tp != kp)
5984 {
5985 const double kk = *tp++;
5986 sum0 += wrk[0] * kk;
5987 sum1 += wrk[1] * kk;
5988 sum2 += wrk[2] * kk;
5989 wrk += 6;
5990 }
5991 sum[0] = sum0 * mult; sum[1] = sum1 * mult; sum[2] = sum2 * mult;
5992 istore(img, sum);
5993 img += 3;
5994 }
5995 }
5996
do_scale(tcb * thread)5997 static void do_scale(tcb *thread)
5998 {
5999 scale_context ctx = *(scale_context *)thread->data;
6000 fstep *tmpy;
6001 int i, ii, cc, cnt = thread->nsteps;
6002
6003
6004 /* For each destination line */
6005 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
6006 {
6007 tmpy = ctx.vfilter + i;
6008 if (ctx.dest[CHN_IMAGE]) // Chanlist may contain, e.g., only mask
6009 {
6010 (ctx.tmask == CMASK_NONE ? (__typeof__(&scale_rgba))scale_row :
6011 scale_rgba)(tmpy, ctx.hfilter, ctx.rgb,
6012 3, ctx.gcor, ctx.ow, ctx.oh, ctx.nw, i,
6013 ctx.src[CHN_IMAGE], ctx.dest[CHN_IMAGE],
6014 ctx.src[CHN_ALPHA], ctx.dest[CHN_ALPHA]);
6015 }
6016
6017 for (cc = CHN_IMAGE + 1; cc < NUM_CHANNELS; cc++)
6018 {
6019 if (ctx.dest[cc] && !(ctx.tmask & CMASK_FOR(cc)))
6020 scale_row(tmpy, ctx.hfilter, ctx.rgb,
6021 1, FALSE, ctx.ow, ctx.oh, ctx.nw, i,
6022 ctx.src[cc], ctx.dest[cc]);
6023 }
6024
6025 if (ctx.progress && thread_step(thread, ii + 1, cnt, 10)) break;
6026 }
6027 thread_done(thread);
6028 }
6029
do_scale_nn(chanlist old_img,chanlist neo_img,int img_bpp,int type,int ow,int oh,int nw,int nh,int gcor,int progress)6030 static void do_scale_nn(chanlist old_img, chanlist neo_img, int img_bpp,
6031 int type, int ow, int oh, int nw, int nh, int gcor, int progress)
6032 {
6033 char *src, *dest;
6034 int i, j, oi, oj, cc, bpp;
6035 double scalex, scaley, deltax, deltay;
6036
6037
6038 scalex = (double)ow / (double)nw;
6039 scaley = (double)oh / (double)nh;
6040 deltax = 0.5 * scalex - 0.5;
6041 deltay = 0.5 * scaley - 0.5;
6042
6043 for (j = 0; j < nh; j++)
6044 {
6045 for (cc = 0 , bpp = img_bpp; cc < NUM_CHANNELS; cc++ , bpp = 1)
6046 {
6047 if (!neo_img[cc]) continue;
6048 dest = neo_img[cc] + nw * j * bpp;
6049 WJ_ROUND(oj, scaley * j + deltay);
6050 src = old_img[cc] + ow * oj * bpp;
6051 for (i = 0; i < nw; i++)
6052 {
6053 WJ_ROUND(oi, scalex * i + deltax);
6054 oi *= bpp;
6055 *dest++ = src[oi];
6056 if (bpp == 1) continue;
6057 *dest++ = src[oi + 1];
6058 *dest++ = src[oi + 2];
6059 }
6060 }
6061 if (progress && ((j * 10) % nh >= nh - 10))
6062 progress_update((float)(j + 1) / nh);
6063 }
6064 }
6065
6066
mem_image_scale_real(chanlist old_img,int ow,int oh,int bpp,chanlist new_img,int nw,int nh,int type,int gcor,int sharp)6067 int mem_image_scale_real(chanlist old_img, int ow, int oh, int bpp,
6068 chanlist new_img, int nw, int nh, int type, int gcor, int sharp)
6069 {
6070 scale_context ctx;
6071
6072 ctx.tmask = CMASK_NONE;
6073 ctx.gcor = gcor;
6074 ctx.progress = FALSE;
6075 ctx.ow = ow;
6076 ctx.oh = oh;
6077 ctx.nw = nw;
6078 ctx.nh = nh;
6079 ctx.bpp = bpp;
6080 ctx.src = old_img;
6081 ctx.dest = new_img;
6082
6083 if (!prepare_scale(&ctx, type, sharp, BOUND_MIRROR))
6084 return (1); // Not enough memory
6085
6086 if (type && (bpp == 3))
6087 launch_threads(do_scale, ctx.tdata, NULL, nh);
6088 else do_scale_nn(old_img, new_img, bpp, type, ow, oh, nw, nh, gcor, FALSE);
6089
6090 return (0);
6091 }
6092
mem_image_scale(int nw,int nh,int type,int gcor,int sharp,int bound)6093 int mem_image_scale(int nw, int nh, int type, int gcor, int sharp, int bound) // Scale image
6094 {
6095 scale_context ctx;
6096 chanlist old_img;
6097 int res;
6098
6099 memcpy(old_img, mem_img, sizeof(chanlist));
6100 nw = nw < 1 ? 1 : nw > MAX_WIDTH ? MAX_WIDTH : nw;
6101 nh = nh < 1 ? 1 : nh > MAX_HEIGHT ? MAX_HEIGHT : nh;
6102
6103 ctx.tmask = mem_img[CHN_ALPHA] && !channel_dis[CHN_ALPHA] ? CMASK_RGBA : CMASK_NONE;
6104 ctx.gcor = gcor;
6105 ctx.progress = TRUE;
6106 ctx.ow = mem_width;
6107 ctx.oh = mem_height;
6108 ctx.nw = nw;
6109 ctx.nh = nh;
6110 ctx.bpp = mem_img_bpp;
6111 ctx.src = old_img;
6112 ctx.dest = mem_img;
6113
6114 if (!prepare_scale(&ctx, type, sharp, bound))
6115 return (1); // Not enough memory
6116
6117 if (!(res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL)))
6118 {
6119 progress_init(_("Scaling Image"), 0);
6120 if (type && (mem_img_bpp == 3))
6121 launch_threads(do_scale, ctx.tdata, NULL, mem_height);
6122 else do_scale_nn(old_img, mem_img, mem_img_bpp, type,
6123 ctx.ow, ctx.oh, nw, nh, gcor, TRUE);
6124 progress_end();
6125 }
6126
6127 clear_scale(&ctx);
6128 return (res);
6129 }
6130
6131
6132
mem_isometrics(int type)6133 int mem_isometrics(int type)
6134 {
6135 unsigned char *wrk, *src, *dest, *fill;
6136 int i, j, k, l, cc, step, bpp, ow = mem_width, oh = mem_height;
6137
6138 if ( type<2 )
6139 {
6140 if ( (oh + (ow-1)/2) > MAX_HEIGHT ) return -5;
6141 i = mem_image_resize(ow, oh + (ow-1)/2, 0, 0, 0);
6142 }
6143 if ( type>1 )
6144 {
6145 if ( (ow+oh-1) > MAX_WIDTH ) return -5;
6146 i = mem_image_resize(ow + oh - 1, oh, 0, 0, 0);
6147 }
6148
6149 if (i) return (i);
6150
6151 for (cc = 0; cc < NUM_CHANNELS; cc++)
6152 {
6153 if (!mem_img[cc]) continue;
6154 bpp = BPP(cc);
6155 if ( type < 2 ) // Left/Right side down
6156 {
6157 fill = mem_img[cc] + (mem_height - 1) * ow * bpp;
6158 step = ow * bpp;
6159 if (type) step = -step;
6160 else fill += (2 - (ow & 1)) * bpp;
6161 for (i = mem_height - 1; i >= 0; i--)
6162 {
6163 k = i + i + 2;
6164 if (k > ow) k = ow;
6165 l = k;
6166 j = 0;
6167 dest = mem_img[cc] + i * ow * bpp;
6168 src = dest - step;
6169 if (!type)
6170 {
6171 j = ow - k;
6172 dest += j * bpp;
6173 src += (j - ow * ((ow - j - 1) >> 1)) * bpp;
6174 j = j ? 0 : ow & 1;
6175 k += j;
6176 if (j) src += step;
6177 }
6178 for (; j < k; j++)
6179 {
6180 if (!(j & 1)) src += step;
6181 *dest++ = *src++;
6182 if (bpp == 1) continue;
6183 *dest++ = *src++;
6184 *dest++ = *src++;
6185 }
6186 if (l < ow)
6187 {
6188 if (!type) dest = mem_img[cc] + i * ow * bpp;
6189 memcpy(dest, fill, (ow - l) * bpp);
6190 }
6191 }
6192 }
6193 else // Top/Bottom side right
6194 {
6195 step = mem_width * bpp;
6196 fill = mem_img[cc] + ow * bpp;
6197 k = (oh - 1) * mem_width * bpp;
6198 if (type == 2)
6199 {
6200 fill += k;
6201 step = -step;
6202 }
6203 wrk = fill + step - 1;
6204 k = ow * bpp;
6205 for (i = 1; i < oh; i++)
6206 {
6207 src = wrk;
6208 dest = wrk + i * bpp;
6209 for (j = 0; j < k; j++)
6210 *dest-- = *src--;
6211 memcpy(src + 1, fill, i * bpp);
6212 wrk += step;
6213 }
6214 }
6215 }
6216
6217 return 0;
6218 }
6219
6220 /* Modes: 0 - clear, 1 - tile, 2 - mirror tile */
mem_image_resize(int nw,int nh,int ox,int oy,int mode)6221 int mem_image_resize(int nw, int nh, int ox, int oy, int mode)
6222 {
6223 chanlist old_img;
6224 char *src, *dest;
6225 int i, h, ow = mem_width, oh = mem_height, hmode = mode;
6226 int res, hstep, vstep, vstep2 = 0, oxo = 0, oyo = 0, nxo = 0, nyo = 0;
6227 int rspan1 = 0, span1 = 0, rspan2 = 0, span2 = 0, rep = 0, tail = 0;
6228
6229 nw = nw < 1 ? 1 : nw > MAX_WIDTH ? MAX_WIDTH : nw;
6230 nh = nh < 1 ? 1 : nh > MAX_HEIGHT ? MAX_HEIGHT : nh;
6231
6232 memcpy(old_img, mem_img, sizeof(chanlist));
6233 res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL);
6234 if (res) return (res); // Not enough memory
6235
6236 /* Special mode for simplest, one-piece-covering case */
6237 if ((ox <= 0) && (nw - ox <= ow)) hmode = -1;
6238 if ((oy <= 0) && (nh - oy <= oh)) mode = -1;
6239
6240 /* Clear */
6241 if (!mode || !hmode)
6242 {
6243 int i, l, cc;
6244
6245 l = nw * nh;
6246 for (cc = 0; cc < NUM_CHANNELS; cc++)
6247 {
6248 if (!mem_img[cc]) continue;
6249 dest = mem_img[cc];
6250 if ((cc != CHN_IMAGE) || (mem_img_bpp == 1))
6251 {
6252 memset(dest, cc == CHN_IMAGE ? mem_col_A : 0, l);
6253 continue;
6254 }
6255 for (i = 0; i < l; i++) // Background is current colour A
6256 {
6257 *dest++ = mem_col_A24.red;
6258 *dest++ = mem_col_A24.green;
6259 *dest++ = mem_col_A24.blue;
6260 }
6261 }
6262 /* All done if source out of bounds */
6263 if ((ox >= nw) || (ox + ow <= 0) || (oy >= nh) ||
6264 (oy + oh <= 0)) return (0);
6265 }
6266
6267 /* Tiled vertically */
6268 if (mode > 0)
6269 {
6270 /* No mirror when height < 3 */
6271 if (oh < 3) mode = 1;
6272 /* Period length */
6273 if (mode == 2) vstep = 2 * (vstep2 = oh - 1);
6274 else vstep = oh;
6275 /* Normalize offset */
6276 oyo = oy <= 0 ? -oy % vstep : vstep - 1 - (oy - 1) % vstep;
6277 h = nh;
6278 }
6279 /* Single vertical span */
6280 else
6281 {
6282 /* No periodicity */
6283 vstep = nh + oh;
6284 /* Normalize offset */
6285 if (oy < 0) oyo = -oy;
6286 else nyo = oy;
6287 h = oh + oy;
6288 if (h > nh) h = nh;
6289 }
6290
6291 /* Tiled horizontally */
6292 if (hmode > 0)
6293 {
6294 /* No mirror when width < 3 */
6295 if (ow < 3) hmode = 1;
6296 /* Period length */
6297 if (hmode == 2) hstep = ow + ow - 2;
6298 else hstep = ow;
6299 /* Normalize offset */
6300 oxo = ox <= 0 ? -ox % hstep : hstep - 1 - (ox - 1) % hstep;
6301 /* Single direct span? */
6302 if ((oxo <= 0) && (oxo + ow >= nw)) hmode = -1;
6303 if (hmode == 2) /* Mirror tiling */
6304 {
6305 if (oxo < ow - 1) span1 = ow - 1 - oxo;
6306 res = nw - span1;
6307 rspan1 = hstep - oxo - span1;
6308 if (rspan1 > res) rspan1 = res;
6309 span2 = (res = res - rspan1);
6310 if (span2 > ow - 1 - span1) span2 = ow - 1 - span1;
6311 rspan2 = res - span2;
6312 if (rspan2 > ow - 1 - rspan1) rspan2 = ow - 1 - rspan1;
6313 }
6314 else /* Normal tiling */
6315 {
6316 span1 = ow - oxo;
6317 span2 = nw - span1;
6318 if (span2 > oxo) span2 = oxo;
6319 }
6320 rep = nw / hstep;
6321 if (rep) tail = nw % hstep;
6322 }
6323 /* Single horizontal span */
6324 else
6325 {
6326 /* No periodicity */
6327 hstep = nw;
6328 /* Normalize offset */
6329 if (ox < 0) oxo = -ox;
6330 else nxo = ox;
6331 /* First direct span */
6332 span1 = nw - nxo;
6333 if (span1 > ow - oxo) span1 = ow - oxo;
6334 }
6335
6336 /* Row loop */
6337 for (i = nyo; i < h; i++)
6338 {
6339 int j, k, l, bpp, cc;
6340
6341 /* Main period */
6342 k = i - vstep;
6343 /* Mirror period */
6344 if ((k < 0) && (vstep2 > 1)) k = i - ((i + oyo) % vstep2) * 2;
6345 /* The row is there - copy it */
6346 if ((k >= 0) && (k < i))
6347 {
6348 for (cc = 0; cc < NUM_CHANNELS; cc++)
6349 {
6350 if (!mem_img[cc]) continue;
6351 l = nw * BPP(cc);
6352 src = mem_img[cc] + k * l;
6353 dest = mem_img[cc] + i * l;
6354 memcpy(dest, src, l);
6355 }
6356 continue;
6357 }
6358 /* First encounter - have to build the row anew */
6359 k = (i - nyo + oyo) % vstep;
6360 if (k >= oh) k = vstep - k;
6361 for (cc = 0; cc < NUM_CHANNELS; cc++)
6362 {
6363 if (!mem_img[cc]) continue;
6364 bpp = BPP(cc);
6365 dest = mem_img[cc] + (i * nw + nxo) * bpp;
6366 /* First direct span */
6367 if (span1)
6368 {
6369 src = old_img[cc] + (k * ow + oxo) * bpp;
6370 memcpy(dest, src, span1 * bpp);
6371 if (hmode < 1) continue; /* Single-span mode */
6372 dest += span1 * bpp;
6373 }
6374 /* First reverse span */
6375 if (rspan1)
6376 {
6377 src = old_img[cc] + (k * ow + hstep - oxo -
6378 span1) * bpp;
6379 for (j = 0; j < rspan1; j++ , src -= bpp)
6380 {
6381 *dest++ = src[0];
6382 if (bpp == 1) continue;
6383 *dest++ = src[1];
6384 *dest++ = src[2];
6385 }
6386 }
6387 /* Second direct span */
6388 if (span2)
6389 {
6390 src = old_img[cc] + k * ow * bpp;
6391 memcpy(dest, src, span2 * bpp);
6392 dest += span2 * bpp;
6393 }
6394 /* Second reverse span */
6395 if (rspan2)
6396 {
6397 src = old_img[cc] + (k * ow + ow - 1) * bpp;
6398 for (j = 0; j < rspan2; j++ , src -= bpp)
6399 {
6400 *dest++ = src[0];
6401 if (bpp == 1) continue;
6402 *dest++ = src[1];
6403 *dest++ = src[2];
6404 }
6405 }
6406 /* Repeats */
6407 if (rep)
6408 {
6409 src = mem_img[cc] + i * nw * bpp;
6410 l = hstep * bpp;
6411 for (j = 1; j < rep; j++)
6412 {
6413 memcpy(dest, src, l);
6414 dest += l;
6415 }
6416 memcpy(dest, src, tail * bpp);
6417 }
6418 }
6419 }
6420 mem_undo_prepare();
6421
6422 return (0);
6423 }
6424
6425 /* Threshold channel values */
mem_threshold(unsigned char * img,int len,int level)6426 void mem_threshold(unsigned char *img, int len, int level)
6427 {
6428 if (!img) return; /* Paranoia */
6429 level += 0xFFFF;
6430 for (; len; len-- , img++)
6431 *img = (level - *img) >> 8;
6432 }
6433
6434 /* Industrial-grade thresholding */
do_xhold(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0)6435 void do_xhold(int start, int step, int cnt, unsigned char *mask,
6436 unsigned char *imgr, unsigned char *img0)
6437 {
6438 unsigned char lo = mem_ts.lo, hi = mem_ts.hi;
6439 int n, mstep = step, bpp = MEM_BPP;
6440
6441 mask += start - step;
6442 start *= bpp; step *= bpp;
6443 img0 += start - step;
6444 imgr += start - step;
6445 if ((bpp > 1) && (mem_ts.mode <= XHOLD_MIN)) /* By max or min */
6446 {
6447 int m = mem_ts.mode; // 0 for max, 1 for min
6448
6449 while (cnt-- > 0)
6450 {
6451 img0 += step; imgr += step; mask += mstep;
6452 if (*mask == 255) continue;
6453 n = (img0[0] > img0[1]) ^ m ? img0[0] : img0[1];
6454 n = (n > img0[2]) ^ m ? n : img0[2];
6455 imgr[0] = imgr[1] = imgr[2] =
6456 ((0xFFFF + lo - n) & (0xFFFF - hi + n)) >> 8;
6457 }
6458 }
6459 else /* By R/G/B/value */
6460 {
6461 unsigned char mx = 255;
6462
6463 if (bpp > 1) img0 += mem_ts.mode - XHOLD_RED;
6464 else if (mem_channel == CHN_IMAGE) mx = mem_cols - 1;
6465
6466 while (cnt-- > 0)
6467 {
6468 img0 += step; imgr += step; mask += mstep;
6469 if (*mask == 255) continue;
6470 n = *img0;
6471 imgr[0] = n = mx &
6472 (((0xFFFF + lo - n) & (0xFFFF - hi + n)) >> 8);
6473 if (bpp == 1) continue;
6474 imgr[1] = imgr[2] = n;
6475 }
6476 }
6477 }
6478
6479 /* Only supports BPP = 1 and 3 */
mem_demultiply(unsigned char * img,unsigned char * alpha,int len,int bpp)6480 void mem_demultiply(unsigned char *img, unsigned char *alpha, int len, int bpp)
6481 {
6482 int i, k;
6483 double d;
6484
6485 for (i = 0; i < len; i++ , img += bpp)
6486 {
6487 if (!alpha[i]) continue;
6488 d = 255.0 / (double)alpha[i];
6489 k = rint(d * img[0]);
6490 img[0] = k > 255 ? 255 : k;
6491 if (bpp == 1) continue;
6492 k = rint(d * img[1]);
6493 img[1] = k > 255 ? 255 : k;
6494 k = rint(d * img[2]);
6495 img[2] = k > 255 ? 255 : k;
6496 }
6497 }
6498
6499 /* Build value rescaling table */
set_xlate_n(unsigned char * xlat,int n)6500 void set_xlate_n(unsigned char *xlat, int n)
6501 {
6502 int i, j, m;
6503
6504 for (i = 0 , j = n , m = n + n; i <= n; i++ , j += 255 * 2)
6505 xlat[i] = j / m;
6506 }
6507
6508 /* Check if byte array is all one value */
is_filled(unsigned char * data,unsigned char val,int len)6509 int is_filled(unsigned char *data, unsigned char val, int len)
6510 {
6511 len++;
6512 while (--len && (*data++ == val));
6513 return (!len);
6514 }
6515
get_pixel(int x,int y)6516 int get_pixel( int x, int y ) /* Mixed */
6517 {
6518 x = mem_width * y + x;
6519 if ((mem_channel != CHN_IMAGE) || (mem_img_bpp == 1))
6520 return (mem_img[mem_channel][x]);
6521 x *= 3;
6522 return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6523 }
6524
get_pixel_RGB(int x,int y)6525 int get_pixel_RGB( int x, int y ) /* RGB */
6526 {
6527 x = mem_width * y + x;
6528 if (mem_img_bpp == 1)
6529 return (PNG_2_INT(mem_pal[mem_img[CHN_IMAGE][x]]));
6530 x *= 3;
6531 return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6532 }
6533
get_pixel_img(int x,int y)6534 int get_pixel_img( int x, int y ) /* RGB or indexed */
6535 {
6536 x = mem_width * y + x;
6537 if (mem_img_bpp == 1) return (mem_img[CHN_IMAGE][x]);
6538 x *= 3;
6539 return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6540 }
6541
mem_protected_RGB(int intcol)6542 int mem_protected_RGB(int intcol) // Is this intcol in bitmap?
6543 {
6544 return (mem_mask_test(intcol) * 255);
6545 }
6546
pixel_protected(int x,int y)6547 int pixel_protected(int x, int y)
6548 {
6549 int offset = y * mem_width + x;
6550
6551 if (mem_unmask) return (0);
6552
6553 /* Colour protection */
6554 if (mem_img_bpp == 1)
6555 {
6556 if (mem_prot_mask[mem_img[CHN_IMAGE][offset]]) return (255);
6557 }
6558 else
6559 {
6560 if (mem_prot && mem_protected_RGB(MEM_2_INT(mem_img[CHN_IMAGE],
6561 offset * 3))) return (255);
6562 }
6563
6564 /* Colour selectivity */
6565 if (mem_cselect && csel_scan(offset, 1, 1, NULL, mem_img[CHN_IMAGE], csel_data))
6566 return (255);
6567
6568 /* Mask channel */
6569 if ((mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
6570 return (mem_img[CHN_MASK][offset]);
6571
6572 return (0);
6573 }
6574
prep_mask(int start,int step,int cnt,unsigned char * mask,unsigned char * mask0,unsigned char * img0)6575 void prep_mask(int start, int step, int cnt, unsigned char *mask,
6576 unsigned char *mask0, unsigned char *img0)
6577 {
6578 int i, j;
6579
6580 j = start + step * (cnt - 1) + 1;
6581
6582 if (mem_unmask)
6583 {
6584 memset(mask, 0, j);
6585 return;
6586 }
6587
6588 /* Clear mask or copy mask channel into it */
6589 if (mask0) memcpy(mask, mask0, j);
6590 else memset(mask, 0, j);
6591
6592 /* Add colour protection to it */
6593 if (mem_img_bpp == 1)
6594 {
6595 for (i = start; i < j; i += step)
6596 {
6597 mask[i] |= mem_prot_mask[img0[i]];
6598 }
6599 }
6600 else if (mem_prot)
6601 {
6602 for (i = start; i < j; i += step)
6603 {
6604 mask[i] |= mem_protected_RGB(MEM_2_INT(img0, i * 3));
6605 }
6606 }
6607
6608 /* Add colour selectivity to it */
6609 if (mem_cselect) csel_scan(start, step, cnt, mask, img0, csel_data);
6610 }
6611
6612 /* Prepare mask array - for each pixel >0 if masked, 0 if not */
row_protected(int x,int y,int len,unsigned char * mask)6613 void row_protected(int x, int y, int len, unsigned char *mask)
6614 {
6615 unsigned char *mask0 = NULL;
6616 int ofs = y * mem_width + x;
6617
6618 /* Clear mask or copy mask channel into it */
6619 if ((mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
6620 mask0 = mem_img[CHN_MASK] + ofs;
6621
6622 prep_mask(0, 1, len, mask, mask0, mem_img[CHN_IMAGE] + ofs * mem_img_bpp);
6623 }
6624
6625 /* Make code not compile if it cannot work */
6626 typedef char Too_Many_Blend_Modes[2 * (BLEND_NMODES <= BLEND_MMASK + 1) - 1];
6627
blend_pixels(int start,int step,int cnt,const unsigned char * mask,unsigned char * imgr,unsigned char * img0,unsigned char * img,int bpp,int mode)6628 static void blend_pixels(int start, int step, int cnt, const unsigned char *mask,
6629 unsigned char *imgr, unsigned char *img0, unsigned char *img,
6630 int bpp, int mode)
6631 {
6632 static const unsigned char hhsv[8] = {
6633 0x24, /* 0, 1, 2 = #0: B..M */
6634 0x06, /* 2, 1, 0 = #1: M+..R- */
6635 0x24, /* 0, 1, 2 = #2: B..M alt */
6636 0x21, /* 1, 0, 2 = #3: C+..B- */
6637 0x12, /* 2, 0, 1 = #4: G..C */
6638 0x18, /* 0, 2, 1 = #5: Y+..G- */
6639 0x09, /* 1, 2, 0 = #6: R..Y */
6640 0x49 /* 1, 2, 0, 1 = #7: W */ };
6641 #define HHSV(X,N) (((X) >> ((N) * 2)) & 3)
6642 const unsigned char *new, *old;
6643 int j, step3, mx, uninit_(nhex), uninit_(ohex);
6644
6645
6646 /* Backward transfer? */
6647 if (mode & BLEND_REVERSE) new = img0 , old = img;
6648 else new = img , old = img0;
6649 mx = mode & BLENDF_IDX ? mem_cols - 1 : 255;
6650 mode &= BLEND_MMASK;
6651 if (bpp == 1) mode += BLEND_NMODES;
6652
6653 j = start - step;
6654 mask += j;
6655 j *= bpp;
6656 step3 = step * bpp;
6657 new += j; old += j;
6658 while (cnt-- > 0)
6659 {
6660 unsigned char *dest;
6661 int j0, j1, j2;
6662
6663 old += step3; new += step3; mask += step; j += step3;
6664 if (!*mask) continue;
6665
6666 dest = imgr + j;
6667
6668 if (mode < BLEND_1BPP)
6669 {
6670 nhex = hhsv[(((0x200 + new[0]) - new[1]) ^
6671 ((0x400 + new[1]) - new[2]) ^
6672 ((0x100 + new[2]) - new[0])) >> 8];
6673 ohex = hhsv[(((0x200 + old[0]) - old[1]) ^
6674 ((0x400 + old[1]) - old[2]) ^
6675 ((0x100 + old[2]) - old[0])) >> 8];
6676 }
6677
6678 switch (mode)
6679 {
6680 case BLEND_HUE: /* HS* Hue */
6681 {
6682 int i;
6683 unsigned char os, ov, ns;
6684
6685 ov = old[HHSV(ohex, 2)];
6686
6687 if (nhex & 0x40) /* New is white */
6688 {
6689 dest[0] = dest[1] = dest[2] = ov;
6690 break;
6691 }
6692
6693 os = old[HHSV(ohex, 1)];
6694 ns = new[HHSV(nhex, 1)];
6695
6696 i = new[HHSV(nhex, 2)] - ns;
6697 dest[HHSV(nhex, 0)] = (i + (ov - os) * 2 *
6698 (new[HHSV(nhex, 0)] - ns)) / (i + i) + os;
6699 dest[HHSV(nhex, 1)] = os;
6700 dest[HHSV(nhex, 2)] = ov;
6701 break;
6702 }
6703 case BLEND_SAT: /* HSV Saturation */
6704 {
6705 int i;
6706 unsigned char ov, os, ns, nv;
6707
6708 if (ohex & 0x40) /* Old is white - leave it so */
6709 {
6710 dest[0] = old[0]; dest[1] = old[1]; dest[2] = old[2];
6711 break;
6712 }
6713
6714 ov = old[HHSV(ohex, 2)];
6715
6716 if (nhex & 0x40) /* New is white */
6717 {
6718 dest[0] = dest[1] = dest[2] = ov;
6719 break;
6720 }
6721
6722 os = old[HHSV(ohex, 1)];
6723
6724 nv = new[HHSV(nhex, 2)];
6725 ns = (new[HHSV(nhex, 1)] * ov * 2 + nv) / (nv + nv);
6726
6727 i = ov - os;
6728 dest[HHSV(ohex, 0)] = (i + (ov - ns) * 2 *
6729 (old[HHSV(ohex, 0)] - os)) / (i + i) + ns;
6730 dest[HHSV(ohex, 1)] = ns;
6731 dest[HHSV(ohex, 2)] = ov;
6732 break;
6733 }
6734 case BLEND_VALUE: /* HSV Value */
6735 {
6736 unsigned char ov, nv;
6737
6738 nv = new[HHSV(nhex, 2)];
6739
6740 if (ohex & 0x40) /* Old is white */
6741 {
6742 dest[0] = dest[1] = dest[2] = nv;
6743 break;
6744 }
6745
6746 ov = old[HHSV(ohex, 2)];
6747
6748 dest[HHSV(ohex, 0)] =
6749 (old[HHSV(ohex, 0)] * nv * 2 + ov) / (ov + ov);
6750 dest[HHSV(ohex, 1)] =
6751 (old[HHSV(ohex, 1)] * nv * 2 + ov) / (ov + ov);
6752 dest[HHSV(ohex, 2)] = nv;
6753 break;
6754 }
6755 case BLEND_COLOR: /* HSL Hue + Saturation */
6756 {
6757 int x0, x1, y0, y1, vsy1, vs1y;
6758 unsigned char os, ov;
6759
6760 os = old[HHSV(ohex, 1)];
6761 ov = old[HHSV(ohex, 2)];
6762 x0 = os + ov;
6763
6764 /* New is white */
6765 if (nhex & 0x40)
6766 {
6767 dest[0] = dest[1] = dest[2] = (x0 + 1) >> 1;
6768 break;
6769 }
6770
6771 x1 = new[HHSV(nhex, 2)] + new[HHSV(nhex, 1)];
6772
6773 y1 = x1 > 255 ? 510 - x1 : x1;
6774 vs1y = (x0 + 1) * y1;
6775 y0 = x0 > 255 ? 510 - x0 : x0;
6776 vsy1 = (new[HHSV(nhex, 2)] - new[HHSV(nhex, 1)]) * y0;
6777 y1 += y1;
6778
6779 dest[HHSV(nhex, 0)] =
6780 (vs1y + (new[HHSV(nhex, 0)] * 2 - x1) * y0) / y1;
6781 dest[HHSV(nhex, 1)] = (vs1y - vsy1) / y1;
6782 dest[HHSV(nhex, 2)] = (vs1y + vsy1) / y1;
6783 break;
6784 }
6785 case BLEND_SATPP: /* Perceived saturation */
6786 {
6787 int i, xyz = (new[0] + new[1] + new[2]) / 3;
6788
6789 i = old[0] + new[0] - xyz;
6790 dest[0] = i < 0 ? 0 : i > 255 ? 255 : i;
6791 i = old[1] + new[1] - xyz;
6792 dest[1] = i < 0 ? 0 : i > 255 ? 255 : i;
6793 i = old[2] + new[2] - xyz;
6794 dest[2] = i < 0 ? 0 : i > 255 ? 255 : i;
6795 break;
6796 }
6797 case BLEND_SCREEN: // ~mult(~old, ~new)
6798 j1 = (old[1] + new[1]) * 255 - old[1] * new[1];
6799 dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6800 j2 = (old[2] + new[2]) * 255 - old[2] * new[2];
6801 dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6802 case BLEND_SCREEN + BLEND_NMODES:
6803 j0 = (old[0] + new[0]) * 255 - old[0] * new[0];
6804 dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6805 break;
6806 case BLEND_MULT:
6807 j1 = old[1] * new[1];
6808 dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6809 j2 = old[2] * new[2];
6810 dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6811 case BLEND_MULT + BLEND_NMODES:
6812 j0 = old[0] * new[0];
6813 dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6814 break;
6815 case BLEND_BURN: // ~div(~old, new)
6816 j1 = ((unsigned char)~old[1] << 8) / (new[1] + 1);
6817 dest[1] = 255 - j1 >= 0 ? 255 - j1 : 0;
6818 j2 = ((unsigned char)~old[2] << 8) / (new[2] + 1);
6819 dest[2] = 255 - j2 >= 0 ? 255 - j2 : 0;
6820 case BLEND_BURN + BLEND_NMODES:
6821 j0 = ((unsigned char)~old[0] << 8) / (new[0] + 1);
6822 dest[0] = 255 - j0 >= 0 ? 255 - j0 : 0;
6823 break;
6824 case BLEND_DODGE: // div(old, ~new)
6825 j1 = (old[1] << 8) / ((unsigned char)~new[1] + 1);
6826 dest[1] = j1 < 255 ? j1 : 255;
6827 j2 = (old[2] << 8) / ((unsigned char)~new[2] + 1);
6828 dest[2] = j2 < 255 ? j2 : 255;
6829 case BLEND_DODGE + BLEND_NMODES:
6830 j0 = (old[0] << 8) / ((unsigned char)~new[0] + 1);
6831 dest[0] = j0 < 255 ? j0 : 255;
6832 break;
6833 case BLEND_DIV:
6834 j1 = (old[1] << 8) / (new[1] + 1);
6835 dest[1] = j1 < 255 ? j1 : 255;
6836 j2 = (old[2] << 8) / (new[2] + 1);
6837 dest[2] = j2 < 255 ? j2 : 255;
6838 case BLEND_DIV + BLEND_NMODES:
6839 j0 = (old[0] << 8) / (new[0] + 1);
6840 dest[0] = j0 < 255 ? j0 : 255;
6841 break;
6842 case BLEND_HLIGHT:
6843 j1 = old[1] * new[1] * 2;
6844 if (new[1] >= 128)
6845 j1 = (old[1] + new[1]) * (255 * 2) - (255 * 255) - j1;
6846 dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6847 j2 = old[2] * new[2] * 2;
6848 if (new[2] >= 128)
6849 j2 = (old[2] + new[2]) * (255 * 2) - (255 * 255) - j2;
6850 dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6851 case BLEND_HLIGHT + BLEND_NMODES:
6852 j0 = old[0] * new[0] * 2;
6853 if (new[0] >= 128)
6854 j0 = (old[0] + new[0]) * (255 * 2) - (255 * 255) - j0;
6855 dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6856 break;
6857 case BLEND_SLIGHT:
6858 // !!! This formula is equivalent to one used in Pegtop XFader and GIMP,
6859 // !!! and differs from one used by Photoshop and PhotoPaint
6860 j1 = old[1] * ((255 * 255) - (unsigned char)~old[1] *
6861 (255 - (new[1] << 1)));
6862 // Precise division by 255^2
6863 j1 += j1 >> 7;
6864 dest[1] = (j1 + ((j1 * 3 + 0x480) >> 16)) >> 16;
6865 j2 = old[2] * ((255 * 255) - (unsigned char)~old[2] *
6866 (255 - (new[2] << 1)));
6867 j2 += j2 >> 7;
6868 dest[2] = (j2 + ((j2 * 3 + 0x480) >> 16)) >> 16;
6869 case BLEND_SLIGHT + BLEND_NMODES:
6870 j0 = old[0] * ((255 * 255) - (unsigned char)~old[0] *
6871 (255 - (new[0] << 1)));
6872 j0 += j0 >> 7;
6873 dest[0] = (j0 + ((j0 * 3 + 0x480) >> 16)) >> 16;
6874 break;
6875 // "Negation" : ~BLEND_DIFF(~old, new)
6876 case BLEND_DIFF:
6877 dest[1] = abs(old[1] - new[1]);
6878 dest[2] = abs(old[2] - new[2]);
6879 case BLEND_DIFF + BLEND_NMODES:
6880 dest[0] = abs(old[0] - new[0]);
6881 break;
6882 case BLEND_DARK:
6883 dest[1] = old[1] < new[1] ? old[1] : new[1];
6884 dest[2] = old[2] < new[2] ? old[2] : new[2];
6885 case BLEND_DARK + BLEND_NMODES:
6886 dest[0] = old[0] < new[0] ? old[0] : new[0];
6887 break;
6888 case BLEND_LIGHT:
6889 dest[1] = old[1] > new[1] ? old[1] : new[1];
6890 dest[2] = old[2] > new[2] ? old[2] : new[2];
6891 case BLEND_LIGHT + BLEND_NMODES:
6892 dest[0] = old[0] > new[0] ? old[0] : new[0];
6893 break;
6894 case BLEND_GRAINX:
6895 j1 = old[1] - new[1] + 128;
6896 dest[1] = j1 < 0 ? 0 : j1 > 255 ? 255 : j1;
6897 j2 = old[2] - new[2] + 128;
6898 dest[2] = j2 < 0 ? 0 : j2 > 255 ? 255 : j2;
6899 case BLEND_GRAINX + BLEND_NMODES:
6900 j0 = old[0] - new[0] + 128;
6901 dest[0] = j0 < 0 ? 0 : j0 > 255 ? 255 : j0;
6902 break;
6903 case BLEND_GRAINM:
6904 j1 = old[1] + new[1] - 128;
6905 dest[1] = j1 < 0 ? 0 : j1 > 255 ? 255 : j1;
6906 j2 = old[2] + new[2] - 128;
6907 dest[2] = j2 < 0 ? 0 : j2 > 255 ? 255 : j2;
6908 case BLEND_GRAINM + BLEND_NMODES:
6909 j0 = old[0] + new[0] - 128;
6910 dest[0] = j0 < 0 ? 0 : j0 > 255 ? 255 : j0;
6911 break;
6912 case BLEND_XHOLD:
6913 dest[1] = (0xFFFF + new[1] - old[1]) >> 8;
6914 dest[2] = (0xFFFF + new[2] - old[2]) >> 8;
6915 case BLEND_XHOLD + BLEND_NMODES:
6916 /* For indexed, upper limit is last palette index */
6917 dest[0] = mx & ((0xFFFF + new[0] - old[0]) >> 8);
6918 break;
6919 // Photoshop's "Linear light" is equivalent to XFader's "Stamp" with swapped A&B
6920 default: /* RGB mode applied to 1bpp */
6921 dest[0] = img0[j];
6922 break;
6923 }
6924 }
6925 #undef HHSV
6926 }
6927
put_pixel_def(int x,int y)6928 void put_pixel_def(int x, int y) /* Combined */
6929 {
6930 unsigned char *src, *ti, *old_image, *old_alpha = NULL;
6931 unsigned char fmask, opacity = 255, cset[NUM_CHANNELS + 3];
6932 int i, j, offset, idx, bpp, op = tool_opacity;
6933
6934
6935 idx = IS_INDEXED;
6936 j = pixel_protected(x, y);
6937 if (idx ? j : j == 255) return;
6938 bpp = MEM_BPP;
6939 ti = cset + (bpp == 3 ? 0 : mem_channel + 3);
6940
6941 old_image = mem_undo_opacity ? mem_undo_previous(mem_channel) :
6942 mem_img[mem_channel];
6943 if ((mem_channel == CHN_IMAGE) && RGBA_mode)
6944 old_alpha = mem_undo_opacity ? mem_undo_previous(CHN_ALPHA) :
6945 mem_img[CHN_ALPHA];
6946
6947 offset = x + mem_width * y;
6948
6949 if (mem_gradient) /* Gradient mode - ask for one pixel */
6950 {
6951 fmask = 0; // Fake mask on input
6952 grad_pixels(0, 1, 1, x, y, &fmask, &fmask, ti,
6953 cset + CHN_ALPHA + 3);
6954 if (!(op = fmask)) return;
6955 }
6956 else if (mem_blend && blend_src) /* Source mode - copy from layer */
6957 {
6958 cset[CHN_ALPHA + 3] = channel_col_A[CHN_ALPHA]; // Fake alpha
6959 if ((blend_src == SRC_IMAGE) || // Same layer
6960 (blend_src == SRC_LAYER + layer_selected))
6961 {
6962 if (bpp == 3) goto set3;
6963 cset[mem_channel + 3] = old_image[offset];
6964 goto seta;
6965 }
6966 else // Other layer
6967 {
6968 layer_node *t = layer_table + blend_src - SRC_LAYER;
6969 image_info *img = &t->image->image_;
6970 int u, w;
6971
6972 src = img->img[mem_channel];
6973 if (!src) return; // Nothing here
6974 w = img->width;
6975 u = floor_mod(y - t->y, img->height) * w +
6976 floor_mod(x - t->x, w);
6977
6978 if (mem_channel == CHN_IMAGE)
6979 {
6980 if (img->bpp > bpp) return; // Incompatible
6981 if (img->bpp < bpp)
6982 {
6983 png_color *p = img->pal + src[u];
6984 cset[0] = p->red;
6985 cset[1] = p->green;
6986 cset[2] = p->blue;
6987 }
6988 else if (bpp == 3)
6989 {
6990 src += u * 3;
6991 cset[0] = src[0];
6992 cset[1] = src[1];
6993 cset[2] = src[2];
6994 }
6995 else cset[CHN_IMAGE + 3] = src[u];
6996 }
6997 else cset[mem_channel + 3] = src[u];
6998 if ((src = img->img[CHN_ALPHA]))
6999 cset[CHN_ALPHA + 3] = src[u];
7000 }
7001 }
7002 /* Transform mode - copy from dest */
7003 else if (mem_blend && (blend_mode & BLEND_XFORM) && (bpp == 3))
7004 {
7005 set3: src = old_image + offset * 3;
7006 cset[0] = src[0];
7007 cset[1] = src[1];
7008 cset[2] = src[2];
7009 seta: if (old_alpha) cset[CHN_ALPHA + 3] = old_alpha[offset];
7010 }
7011 else /* Default mode - init from pattern */
7012 {
7013 i = ((x & 7) + 8 * (y & 7));
7014 cset[mem_channel + 3] = channel_col_[mem_pattern[i]][mem_channel];
7015 cset[CHN_ALPHA + 3] = channel_col_[mem_pattern[i]][CHN_ALPHA];
7016 cset[CHN_IMAGE + 3] = mem_col_pat[i]; /* !!! This must be last! */
7017 i *= 3;
7018 cset[0] = mem_col_pat24[i + 0];
7019 cset[1] = mem_col_pat24[i + 1];
7020 cset[2] = mem_col_pat24[i + 2];
7021 }
7022
7023 if (!idx) // No use for opacity with indexed images
7024 {
7025 j = (255 - j) * op;
7026 opacity = (j + (j >> 8) + 1) >> 8;
7027 }
7028
7029 /* Coupled alpha channel */
7030 if (old_alpha && mem_img[CHN_ALPHA])
7031 {
7032 unsigned char newc = cset[CHN_ALPHA + 3];
7033
7034 if (opacity < 255)
7035 {
7036 unsigned char oldc = old_alpha[offset];
7037 int j = oldc * 255 + (newc - oldc) * opacity;
7038
7039 if (j && !channel_dis[CHN_ALPHA])
7040 opacity = (255 * opacity * newc) / j;
7041 newc = (j + (j >> 8) + 1) >> 8;
7042 }
7043 mem_img[CHN_ALPHA][offset] = newc;
7044 }
7045
7046 offset *= bpp;
7047 process_img(0, 1, 1, &opacity,
7048 mem_img[mem_channel] + offset, old_image + offset, ti,
7049 ti, bpp, 0);
7050 }
7051
7052 /* Repeat pattern in buffer */
pattern_rep(unsigned char * dest,unsigned char * src,int ofs,int rep,int len,int bpp)7053 static void pattern_rep(unsigned char *dest, unsigned char *src,
7054 int ofs, int rep, int len, int bpp)
7055 {
7056 int l1;
7057
7058 ofs *= bpp; rep *= bpp; len *= bpp;
7059 l1 = rep - ofs;
7060 if (l1 > len) l1 = len;
7061 memcpy(dest, src + ofs, l1);
7062 if (!(len -= l1)) return;
7063 dest += l1;
7064 if ((len -= rep) > 0)
7065 {
7066 memcpy(dest, src, rep);
7067 src = dest;
7068 dest += rep;
7069 while ((len -= rep) > 0)
7070 {
7071 memcpy(dest, src, rep);
7072 dest += rep;
7073 rep += rep;
7074 }
7075 }
7076 memcpy(dest, src, len + rep);
7077 }
7078
7079 /* Merge mask with selection */
mask_select(unsigned char * mask,unsigned char * xsel,int l)7080 static void mask_select(unsigned char *mask, unsigned char *xsel, int l)
7081 {
7082 int i, j, k;
7083
7084 for (i = 0; i < l; i++)
7085 {
7086 k = mask[i] * (j = xsel[i]);
7087 mask[i] = ((k + (k >> 8) + 1) >> 8) + 255 - j;
7088 }
7089 }
7090
7091 enum {
7092 PP_DEF = 0, // Default (pattern)
7093 PP_OFS, // Offset
7094 PP_BUF, // Buffer
7095 PP_GRAD, // Gradient
7096 PP_LR, // Layer
7097 PP_L2R, // Indexed layer to RGB
7098 PP_LBUF // Buffered layer
7099 };
7100
7101 /* Faster function for large brushes and fills */
put_pixel_row_def(int x,int y,int len,unsigned char * xsel)7102 void put_pixel_row_def(int x, int y, int len, unsigned char *xsel)
7103 {
7104 unsigned char tmp_image[ROW_BUFLEN * 3], mask[ROW_BUFLEN],
7105 tmp_alpha[ROW_BUFLEN], tmp_opacity[ROW_BUFLEN],
7106 *source_image = tmp_image, *source_alpha = NULL,
7107 *source_opacity = NULL;
7108 unsigned char *old_image, *old_alpha, *srcp, src1[8];
7109 image_info *img = NULL;
7110 int offset, use_mask, bpp, idx, uninit_(cx), cy, d = 0, s = ROW_BUFLEN;
7111 int mode = PP_DEF;
7112
7113
7114 if (len <= 0) return;
7115
7116 old_image = mem_undo_opacity ? mem_undo_previous(mem_channel) :
7117 mem_img[mem_channel];
7118 old_alpha = mem_undo_opacity ? mem_undo_previous(CHN_ALPHA) :
7119 mem_img[CHN_ALPHA];
7120
7121 bpp = MEM_BPP; idx = IS_INDEXED;
7122 use_mask = (mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK];
7123 if ((mem_channel == CHN_IMAGE) && RGBA_mode && mem_img[CHN_ALPHA])
7124 source_alpha = tmp_alpha;
7125
7126 if (tool_type == TOOL_CLONE) /* Clone mode */
7127 {
7128 cy = y + clone_dy;
7129 if ((cy < 0) || (cy >= mem_height)) return;
7130 cx = x + clone_dx;
7131 if (cx + len > mem_width) len = mem_width - cx;
7132 if (cx < 0) len += cx , x -= cx;
7133 if (len <= 0) return;
7134 d = clone_dx + clone_dy * mem_width;
7135 mode = PP_OFS; // Use offset
7136 if (!clone_dy && (old_image == mem_img[mem_channel]))
7137 {
7138 mode = PP_BUF; // Use buffering
7139 // Backward step in the rare case of unbufferable overlap
7140 if ((clone_dx < 0) && (clone_dx > -len) && (len > ROW_BUFLEN))
7141 x += len - ROW_BUFLEN , s = -ROW_BUFLEN;
7142 }
7143 }
7144 else if (mem_gradient) mode = PP_GRAD; /* Gradient mode */
7145 else if (mem_blend && blend_src) /* Source mode */
7146 {
7147 if ((blend_src == SRC_IMAGE) || // Same layer - use offset
7148 (blend_src == SRC_LAYER + layer_selected)) mode = PP_OFS;
7149 else // From other layer
7150 {
7151 layer_node *t = layer_table + blend_src - SRC_LAYER;
7152 int u, w;
7153
7154 img = &t->image->image_;
7155 if (!img->img[mem_channel]) return; // Nothing here
7156
7157 mode = PP_LR;
7158 if (mem_channel == CHN_IMAGE)
7159 {
7160 if (img->bpp > bpp) return; // Incompatible
7161 if (img->bpp < bpp) mode = PP_L2R; // Idx to RGB
7162 }
7163
7164 w = img->width;
7165 cx = floor_mod(x - t->x, w);
7166 d = floor_mod(y - t->y, img->height) * w;
7167 u = len;
7168
7169 if ((len > w) && (w <= ROW_BUFLEN / 2)) // Buffered repeat
7170 {
7171 u += cx;
7172 if (u > ROW_BUFLEN) u = ROW_BUFLEN;
7173
7174 if (mode == PP_LR) memcpy(tmp_image,
7175 img->img[mem_channel] + d * bpp, w * bpp);
7176 else do_convert_rgb(0, 1, w, tmp_image,
7177 img->img[CHN_IMAGE] + d, img->pal);
7178 pattern_rep(tmp_image + w * bpp, tmp_image,
7179 0, w, u - w, bpp);
7180
7181 if (source_alpha && img->img[CHN_ALPHA])
7182 pattern_rep(tmp_alpha, img->img[CHN_ALPHA] + d,
7183 0, w, u, 1);
7184
7185 mode = PP_LBUF;
7186 }
7187
7188 /* Fake alpha */
7189 if (source_alpha && !img->img[CHN_ALPHA])
7190 memset(tmp_alpha, channel_col_A[CHN_ALPHA],
7191 u > ROW_BUFLEN ? ROW_BUFLEN : u);
7192 }
7193 }
7194 /* Transform mode - use offset */
7195 else if (mem_blend && (blend_mode & BLEND_XFORM) && (bpp == 3)) mode = PP_OFS;
7196 // !!! This depends on buffer length being a multiple of pattern length
7197 else /* Default mode - init buffer(s) from pattern */
7198 {
7199 int i, dy = 8 * (y & 7), l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
7200
7201 srcp = mem_pattern + dy;
7202 if (source_alpha)
7203 {
7204 for (i = 0; i < 8; i++)
7205 src1[i] = channel_col_[srcp[i]][CHN_ALPHA];
7206 pattern_rep(tmp_alpha, src1, x & 7, 8, l, 1);
7207 }
7208 if (mem_channel != CHN_IMAGE)
7209 {
7210 for (i = 0; i < 8; i++)
7211 src1[i] = channel_col_[srcp[i]][mem_channel];
7212 srcp = src1;
7213 }
7214 else srcp = idx ? mem_col_pat + dy : mem_col_pat24 + dy * 3;
7215 pattern_rep(tmp_image, srcp, x & 7, 8, l, bpp);
7216 }
7217
7218 offset = x + mem_width * y;
7219 idx ^= 1; // 0 if indexed, now
7220 while (TRUE)
7221 {
7222 int l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
7223
7224 /* Offset mode */
7225 if (mode == PP_OFS)
7226 {
7227 source_image = old_image + (offset + d) * bpp;
7228 if (source_alpha) source_alpha = old_alpha + offset + d;
7229 }
7230 /* Buffered mode */
7231 if (mode == PP_BUF)
7232 {
7233 memcpy(tmp_image, old_image + (offset + d) * bpp, l * bpp);
7234 if (source_alpha)
7235 memcpy(tmp_alpha, old_alpha + offset + d, l);
7236 }
7237 /* Layer mode, direct */
7238 if ((mode == PP_LR) || (mode == PP_L2R))
7239 {
7240 int w = img->width;
7241 if (l + cx > w) l = w - cx;
7242 if (mode == PP_L2R) do_convert_rgb(0, 1, l, tmp_image,
7243 img->img[CHN_IMAGE] + d + cx, img->pal);
7244 else source_image = img->img[mem_channel] + (d + cx) * bpp;
7245 if (source_alpha && img->img[CHN_ALPHA])
7246 source_alpha = img->img[CHN_ALPHA] + d + cx;
7247 cx = (cx + l) % w;
7248 s = l;
7249 }
7250 /* Layer mode, buffered */
7251 if (mode == PP_LBUF)
7252 {
7253 if (l + cx > ROW_BUFLEN) l = ROW_BUFLEN - cx;
7254 source_image = tmp_image + cx * bpp;
7255 if (source_alpha) source_alpha = tmp_alpha + cx;
7256 cx = (cx + l) % img->width;
7257 s = l;
7258 }
7259 /* Buffers stay unchanged for default mode */
7260
7261 /* Mask */
7262 prep_mask(0, 1, l, mask,
7263 use_mask ? mem_img[CHN_MASK] + offset : NULL,
7264 mem_img[CHN_IMAGE] + offset * mem_img_bpp);
7265
7266 if (xsel)
7267 {
7268 mask_select(mask, xsel, l);
7269 xsel += l;
7270 }
7271
7272 /* Gradient mode */
7273 if (mode == PP_GRAD) grad_pixels(0, 1, l, x, y, mask,
7274 source_opacity = tmp_opacity, tmp_image, source_alpha);
7275
7276 process_mask(0, 1, l, mask,
7277 mem_img[CHN_ALPHA] + offset,
7278 old_alpha + offset, source_alpha, source_opacity,
7279 idx * tool_opacity, channel_dis[CHN_ALPHA]);
7280 process_img(0, 1, l, mask,
7281 mem_img[mem_channel] + offset * bpp,
7282 old_image + offset * bpp, source_image,
7283 tmp_image, bpp, 0);
7284
7285 if ((len -= l) <= 0) return;
7286 x += s;
7287 offset += s;
7288 }
7289 }
7290
process_mask(int start,int step,int cnt,unsigned char * mask,unsigned char * alphar,unsigned char * alpha0,unsigned char * alpha,unsigned char * trans,int opacity,int noalpha)7291 void process_mask(int start, int step, int cnt, unsigned char *mask,
7292 unsigned char *alphar, unsigned char *alpha0, unsigned char *alpha,
7293 unsigned char *trans, int opacity, int noalpha)
7294 {
7295 unsigned char *xalpha = NULL;
7296 int i, j, k;
7297
7298 /* Use alpha as selection when pasting RGBA to RGB */
7299 if (alpha && !alphar)
7300 {
7301 *(trans ? &xalpha : &trans) = alpha;
7302 alpha = NULL;
7303 }
7304
7305 i = start - step;
7306 /* Opacity mode */
7307 if (opacity)
7308 {
7309 while (cnt-- > 0)
7310 {
7311 unsigned char newc, oldc;
7312
7313 i += step;
7314 k = (255 - mask[i]) * opacity;
7315 if (!k)
7316 {
7317 mask[i] = 0;
7318 continue;
7319 }
7320 k = (k + (k >> 8) + 1) >> 8;
7321
7322 if (trans) /* Have transparency mask */
7323 {
7324 if (xalpha) /* Have two :-) */
7325 {
7326 k *= xalpha[i];
7327 k = (k + (k >> 8) + 1) >> 8;
7328 }
7329 k *= trans[i];
7330 k = (k + (k >> 8) + 1) >> 8;
7331 }
7332 mask[i] = k;
7333
7334 if (!alpha || !k) continue;
7335 /* Have coupled alpha channel - process it */
7336 newc = alpha[i];
7337 oldc = alpha0[i];
7338 j = oldc * 255 + (newc - oldc) * k;
7339 alphar[i] = (j + (j >> 8) + 1) >> 8;
7340 if (noalpha) continue;
7341 if (j) mask[i] = (255 * k * newc) / j;
7342 }
7343 }
7344
7345 /* Indexed mode - set mask to on-off */
7346 else
7347 {
7348 while (cnt-- > 0)
7349 {
7350 i += step;
7351 k = mask[i];
7352 if (trans)
7353 {
7354 unsigned char oldc = trans[i];
7355 if (xalpha) oldc &= xalpha[i];
7356 k |= oldc ^ 255;
7357 }
7358 mask[i] = k = k ? 0 : 255;
7359 if (!alpha || !k) continue;
7360 /* Have coupled alpha channel - process it */
7361 alphar[i] = alpha[i];
7362 }
7363 }
7364 }
7365
process_img(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0,unsigned char * img,unsigned char * xbuf,int bpp,int blend)7366 void process_img(int start, int step, int cnt, unsigned char *mask,
7367 unsigned char *imgr, unsigned char *img0, unsigned char *img,
7368 unsigned char *xbuf, int bpp, int blend)
7369 {
7370 int opm = 0;
7371
7372 /* Calculate drawing mode */
7373 if (!(blend & BLENDF_SET))
7374 {
7375 blend = mem_blend ? blend_mode : 0;
7376 if (tint_mode[0]) blend |= tint_mode[1] ^ (tint_mode[2] < 2) ?
7377 BLENDF_TINTM : BLENDF_TINT;
7378 if (IS_INDEXED) blend |= BLENDF_IDX;
7379 }
7380 if (blend & BLENDF_INVM) opm = 255;
7381
7382 /* Apply blend mode's transform parts */
7383 // !!! Both calls ignore BLENDF_INVM, as are never combined with it
7384 if ((blend & BLEND_XFORM) && (bpp == 3))
7385 {
7386 do_transform(start, step, cnt, mask, xbuf, img, 256);
7387 img = xbuf;
7388 }
7389 if (blend & BLEND_MMASK)
7390 {
7391 blend_pixels(start, step, cnt, mask, xbuf, img0, img, bpp, blend);
7392 img = xbuf;
7393 }
7394
7395 /* Indexed image or utility channel */
7396 if (bpp < 3)
7397 {
7398 unsigned char newc, oldc;
7399 int i, j, mx = blend & BLENDF_IDX ? mem_cols - 1 : 255;
7400
7401 for (i = start; cnt-- > 0; i += step)
7402 {
7403 j = mask[i] ^ opm;
7404 if (!j) continue;
7405 newc = img[i];
7406 oldc = img0[i];
7407
7408 if (!(blend & (BLENDF_TINTM | BLENDF_TINT))); // Do nothing
7409 else if (blend & BLENDF_TINTM) newc = oldc + newc < mx ?
7410 oldc + newc : mx;
7411 else newc = oldc > newc ? oldc - newc : 0;
7412
7413 if (j < 255)
7414 {
7415 j = oldc * 255 + (newc - oldc) * j;
7416 newc = (j + (j >> 8) + 1) >> 8;
7417 }
7418 imgr[i] = newc;
7419 }
7420 }
7421
7422 /* RGB image */
7423 else
7424 {
7425 int ops = (blend >> BLEND_RGBSHIFT) & 7;
7426 unsigned char r, g, b, nrgb[3];
7427 int j, opacity;
7428
7429 /* Make mask */
7430 ops = (ops + (ops >> 1) * 0xFE + (ops >> 2) * 0xFE00) * 0xFF;
7431
7432 img0 += (start - step) * 3;
7433 img += (start - step) * 3;
7434 imgr += (start - step) * 3;
7435 mask += start - step;
7436 while (cnt-- > 0)
7437 {
7438 img0 += step * 3; img += step * 3; imgr += step * 3;
7439 mask += step;
7440 opacity = *mask ^ opm;
7441 if (!opacity) continue;
7442 nrgb[0] = img[0];
7443 nrgb[1] = img[1];
7444 nrgb[2] = img[2];
7445
7446 /* !!! On x86, register pressure here is too large already, so rereading img0
7447 * is preferable to lengthening r/g/b's living ranges - WJ */
7448 if (blend & (BLENDF_TINTM | BLENDF_TINT))
7449 {
7450 r = img0[0];
7451 g = img0[1];
7452 b = img0[2];
7453 if (blend & BLENDF_TINTM)
7454 {
7455 nrgb[0] = r > 255 - nrgb[0] ? 255 : r + nrgb[0];
7456 nrgb[1] = g > 255 - nrgb[1] ? 255 : g + nrgb[1];
7457 nrgb[2] = b > 255 - nrgb[2] ? 255 : b + nrgb[2];
7458 }
7459 else
7460 {
7461 nrgb[0] = r > nrgb[0] ? r - nrgb[0] : 0;
7462 nrgb[1] = g > nrgb[1] ? g - nrgb[1] : 0;
7463 nrgb[2] = b > nrgb[2] ? b - nrgb[2] : 0;
7464 }
7465 }
7466
7467 if (opacity == 255);
7468 else if (paint_gamma)
7469 {
7470 double r, g, b, o = opacity / 255.0;
7471
7472 r = gamma256[img0[0]];
7473 r += (gamma256[nrgb[0]] - r) * o;
7474 g = gamma256[img0[1]];
7475 g += (gamma256[nrgb[1]] - g) * o;
7476 b = gamma256[img0[2]];
7477 b += (gamma256[nrgb[2]] - b) * o;
7478 nrgb[0] = UNGAMMA256(r);
7479 nrgb[1] = UNGAMMA256(g);
7480 nrgb[2] = UNGAMMA256(b);
7481 }
7482 else
7483 {
7484 r = img0[0];
7485 g = img0[1];
7486 b = img0[2];
7487 j = r * 255 + (nrgb[0] - r) * opacity;
7488 nrgb[0] = (j + (j >> 8) + 1) >> 8;
7489 j = g * 255 + (nrgb[1] - g) * opacity;
7490 nrgb[1] = (j + (j >> 8) + 1) >> 8;
7491 j = b * 255 + (nrgb[2] - b) * opacity;
7492 nrgb[2] = (j + (j >> 8) + 1) >> 8;
7493 }
7494
7495 if (ops)
7496 {
7497 nrgb[0] ^= (nrgb[0] ^ img0[0]) & ops;
7498 nrgb[1] ^= (nrgb[1] ^ img0[1]) & (ops >> 8);
7499 nrgb[2] ^= (nrgb[2] ^ img0[2]) & (ops >> 16);
7500 }
7501
7502 imgr[0] = nrgb[0];
7503 imgr[1] = nrgb[1];
7504 imgr[2] = nrgb[2];
7505 }
7506 }
7507 }
7508
7509 /* !!! This assumes dest area lies entirely within src, its bpp matches src's
7510 * current channel bpp, and it has alpha channel only if src has it too */
copy_area(image_info * dest,image_info * src,int x,int y)7511 void copy_area(image_info *dest, image_info *src, int x, int y)
7512 {
7513 int w = dest->width, h = dest->height, bpp = dest->bpp, ww = src->width;
7514 int i, ofs, delta, len;
7515
7516 /* Current channel */
7517 ofs = (y * ww + x) * bpp;
7518 delta = 0;
7519 len = w * bpp;
7520 for (i = 0; i < h; i++)
7521 {
7522 memcpy(dest->img[CHN_IMAGE] + delta, src->img[mem_channel] + ofs, len);
7523 ofs += ww * bpp;
7524 delta += len;
7525 }
7526
7527 /* Alpha channel */
7528 if (!dest->img[CHN_ALPHA]) return;
7529 ofs = y * ww + x;
7530 delta = 0;
7531 for (i = 0; i < h; i++)
7532 {
7533 memcpy(dest->img[CHN_ALPHA] + delta, src->img[CHN_ALPHA] + ofs, w);
7534 ofs += ww;
7535 delta += w;
7536 }
7537 }
7538
mem_count_all_cols()7539 int mem_count_all_cols() // Count all colours - Using main image
7540 {
7541 return mem_count_all_cols_real(mem_img[CHN_IMAGE], mem_width, mem_height);
7542 }
7543
mem_count_all_cols_real(unsigned char * im,int w,int h)7544 int mem_count_all_cols_real(unsigned char *im, int w, int h) // Count all colours - very memory greedy
7545 {
7546 guint32 *tab;
7547 int i, j, k, ix;
7548
7549 j = 0x80000;
7550 tab = calloc(j, sizeof(guint32)); // HUGE colour cube
7551 if (!tab) return -1; // Not enough memory Mr Greedy ;-)
7552
7553 k = w * h;
7554 for (i = 0; i < k; i++) // Scan each pixel
7555 {
7556 ix = (im[0] >> 5) + (im[1] << 3) + (im[2] << 11);
7557 tab[ix] |= 1U << (im[0] & 31);
7558 im += 3;
7559 }
7560
7561 // Count each colour
7562 for (i = k = 0; i < j; i++) k += bitcount(tab[i]);
7563
7564 free(tab);
7565
7566 return k;
7567 }
7568
mem_cols_used(png_color * pal)7569 int mem_cols_used(png_color *pal) // Count and collect colours used in main RGB image
7570 {
7571 if ( mem_img_bpp == 1 ) return -1; // RGB only
7572
7573 return (mem_cols_used_real(mem_img[CHN_IMAGE], mem_width, mem_height, pal));
7574 }
7575
mem_cols_used_real(unsigned char * im,int w,int h,png_color * pal)7576 int mem_cols_used_real(unsigned char *im, int w, int h, png_color *pal)
7577 // Count and collect up to 256 colours used in RGB chunk
7578 {
7579 rgb_256_map m;
7580 int i, j = w * h, k, l, n, v, vn, res, pix;
7581
7582 memset(&m, 0, sizeof(m));
7583 for (i = res = 0; i < j; i++ , im += 3) // Skim all pixels
7584 {
7585 pix = MEM_2_INT(im, 0);
7586 k = pix & 0xFF;
7587 n = (pix >> 8) & 0x1F;
7588 v = pix >> (8 + 5);
7589 /* Test presence on both tiers at once: if the 1st is unset,
7590 * the 2nd simply defaults to block #0 */
7591 vn = m.rgx[v] * 32 + n;
7592 l = m.vx[vn] * 8 + (k >> 5);
7593 if ((m.rg[v] >> n) & 1 & (m.b[l] >> (k & 0x1F)))
7594 continue;
7595 /* New color - stop if too many */
7596 if (++res > 256) break;
7597 /* Insert into tiers */
7598 if (!m.rg[v]) m.rgx[v] = m.nv++;
7599 vn = m.rgx[v] * 32 + n;
7600 if (!((m.rg[v] >> n) & 1))
7601 m.vx[vn] = m.nb++ , m.rg[v] |= 1U << n;
7602 l = m.vx[vn] * 8 + (k >> 5);
7603 m.b[l] |= 1U << (k & 0x1F);
7604 /* Add to palette */
7605 if (!pal) continue;
7606 pal->red = im[0];
7607 pal->green = im[1];
7608 pal->blue = im[2];
7609 pal++;
7610 }
7611 return (res);
7612 }
7613
7614
7615 //// EFFECTS
7616
dist(int n1,int n2)7617 static inline double dist(int n1, int n2)
7618 {
7619 return (sqrt(n1 * n1 + n2 * n2));
7620 }
7621
do_effect(int type,int param)7622 void do_effect(int type, int param)
7623 {
7624 unsigned char *src, *dest, *tmp, *mask, *buf;
7625 int i, j, uninit_(k), k1, k2, bpp, ll, dxp1, dxm1, dyp1, dym1;
7626 int op, md, ms;
7627 double blur = (double)param / 200.0;
7628
7629 bpp = MEM_BPP;
7630 ll = mem_width * bpp;
7631 ms = bpp == 3 ? 1 : 4;
7632
7633 src = mem_undo_previous(mem_channel);
7634 mask = malloc(mem_width * (bpp + 1));
7635 if (!mask)
7636 {
7637 memory_errors(1);
7638 return;
7639 }
7640 buf = mask + mem_width;
7641
7642 progress_init(_("Applying Effect"), 1);
7643
7644 for (i = 0; i < mem_height; i++)
7645 {
7646 row_protected(0, i, mem_width, tmp = mask);
7647 dyp1 = i < mem_height - 1 ? ll : -ll;
7648 dym1 = i ? -ll : ll;
7649 dest = buf;
7650 for (md = j = 0; j < ll; j++ , src++ , dest++)
7651 {
7652 op = *tmp;
7653 /* One step for 1 or 3 bytes */
7654 md += ms + (md >> 1);
7655 tmp += md >> 2;
7656 md &= 3;
7657 if (op == 255) continue;
7658 dxp1 = j < ll - bpp ? bpp : -bpp;
7659 dxm1 = j >= bpp ? -bpp : bpp;
7660 switch (type)
7661 {
7662 case FX_EDGE: /* Edge detect */
7663 k = *src;
7664 k = abs(k - src[dym1]) + abs(k - src[dyp1]) +
7665 abs(k - src[dxm1]) + abs(k - src[dxp1]);
7666 k += k >> 1;
7667 break;
7668 case FX_EMBOSS: /* Emboss */
7669 k = src[dym1] + src[dxm1] +
7670 src[dxm1 + dym1] + src[dxp1 + dym1];
7671 k = k / 4 - *src + 127;
7672 break;
7673 case FX_SHARPEN: /* Edge sharpen */
7674 k = src[dym1] + src[dyp1] +
7675 src[dxm1] + src[dxp1] - 4 * src[0];
7676 k = *src - blur * k;
7677 break;
7678 case FX_SOFTEN: /* Edge soften */
7679 k = src[dym1] + src[dyp1] +
7680 src[dxm1] + src[dxp1] - 4 * src[0];
7681 k = *src + (5 * k) / (125 - param);
7682 break;
7683 case FX_SOBEL: /* Another edge detector */
7684 k = dist((src[dxp1] - src[dxm1]) * 2 +
7685 src[dym1 + dxp1] - src[dym1 + dxm1] +
7686 src[dyp1 + dxp1] - src[dyp1 + dxm1],
7687 (src[dyp1] - src[dym1]) * 2 +
7688 src[dyp1 + dxm1] + src[dyp1 + dxp1] -
7689 src[dym1 + dxm1] - src[dym1 + dxp1]);
7690 break;
7691 case FX_PREWITT: /* Yet another edge detector */
7692 /* Actually, the filter kernel used is "Robinson"; what is attributable to
7693 * Prewitt is "compass filtering", which can be done with other filter
7694 * kernels too - WJ */
7695 case FX_KIRSCH: /* Compass detector with another kernel */
7696 /* Optimized compass detection algorithm: I calculate three values (compass,
7697 * plus and minus) and then mix them according to filter type - WJ */
7698 k = 0;
7699 k1 = src[dyp1 + dxm1] - src[dxp1];
7700 if (k < k1) k = k1;
7701 k1 += src[dyp1] - src[dym1 + dxp1];
7702 if (k < k1) k = k1;
7703 k1 += src[dyp1 + dxp1] - src[dym1];
7704 if (k < k1) k = k1;
7705 k1 += src[dxp1] - src[dym1 + dxm1];
7706 if (k < k1) k = k1;
7707 k1 += src[dym1 + dxp1] - src[dxm1];
7708 if (k < k1) k = k1;
7709 k1 += src[dym1] - src[dyp1 + dxm1];
7710 if (k < k1) k = k1;
7711 k1 += src[dym1 + dxm1] - src[dyp1];
7712 if (k < k1) k = k1;
7713 k1 = src[dym1 + dxm1] + src[dym1] + src[dym1 + dxp1] +
7714 src[dxm1] + src[dxp1];
7715 k2 = src[dyp1 + dxm1] + src[dyp1] + src[dyp1 + dxp1];
7716 if (type == FX_PREWITT)
7717 k = k * 2 + k1 - k2 - src[0] * 2;
7718 else /* if (type == FX_KIRSCH) */
7719 k = (k * 8 + k1 * 3 - k2 * 5) / 4;
7720 // Division is for equalizing weight of edge
7721 break;
7722 case FX_GRADIENT: /* Still another edge detector */
7723 k = 4.0 * dist(src[dxp1] - src[0],
7724 src[dyp1] - src[0]);
7725 break;
7726 case FX_ROBERTS: /* One more edge detector */
7727 k = 4.0 * dist(src[dyp1 + dxp1] - src[0],
7728 src[dxp1] - src[dyp1]);
7729 break;
7730 case FX_LAPLACE: /* The last edge detector... I hope */
7731 k = src[dym1 + dxm1] + src[dym1] + src[dym1 + dxp1] +
7732 src[dxm1] - 8 * src[0] + src[dxp1] +
7733 src[dyp1 + dxm1] + src[dyp1] + src[dyp1 + dxp1];
7734 break;
7735 case FX_MORPHEDGE: /* Morphological edge detection */
7736 case FX_ERODE: /* Greyscale erosion */
7737 k = src[0];
7738 if (k > src[dym1 + dxm1]) k = src[dym1 + dxm1];
7739 if (k > src[dym1]) k = src[dym1];
7740 if (k > src[dym1 + dxp1]) k = src[dym1 + dxp1];
7741 if (k > src[dxm1]) k = src[dxm1];
7742 if (k > src[dxp1]) k = src[dxp1];
7743 if (k > src[dyp1 + dxm1]) k = src[dyp1 + dxm1];
7744 if (k > src[dyp1]) k = src[dyp1];
7745 if (k > src[dyp1 + dxp1]) k = src[dyp1 + dxp1];
7746 if (type == FX_MORPHEDGE)
7747 k = (src[0] - k) * 2;
7748 break;
7749 case FX_DILATE: /* Greyscale dilation */
7750 k = src[0];
7751 if (k < src[dym1 + dxm1]) k = src[dym1 + dxm1];
7752 if (k < src[dym1]) k = src[dym1];
7753 if (k < src[dym1 + dxp1]) k = src[dym1 + dxp1];
7754 if (k < src[dxm1]) k = src[dxm1];
7755 if (k < src[dxp1]) k = src[dxp1];
7756 if (k < src[dyp1 + dxm1]) k = src[dyp1 + dxm1];
7757 if (k < src[dyp1]) k = src[dyp1];
7758 if (k < src[dyp1 + dxp1]) k = src[dyp1 + dxp1];
7759 break;
7760 }
7761 *dest = k < 0 ? 0 : k > 0xFF ? 0xFF : k;
7762 }
7763 dest = mem_img[mem_channel] + i * ll;
7764 process_img(0, 1, mem_width, mask, dest, dest, buf,
7765 NULL, bpp, BLENDF_SET | BLENDF_INVM);
7766 if ((i * 10) % mem_height >= mem_height - 10)
7767 if (progress_update((float)(i + 1) / mem_height)) break;
7768 }
7769 free(mask);
7770 progress_end();
7771 }
7772
7773 /* Apply vertical filter */
vert_gauss(unsigned char * chan,int w,int h,int y,double * temp,double * gaussY,int lenY,int gcor)7774 static void vert_gauss(unsigned char *chan, int w, int h, int y, double *temp,
7775 double *gaussY, int lenY, int gcor)
7776 {
7777 unsigned char *src0, *src1;
7778 double gv = gaussY[0];
7779 int j, k, mh2 = h > 1 ? h + h - 2 : 1;
7780
7781 src0 = chan + y * w;
7782 if (gcor) /* Gamma-correct RGB values */
7783 {
7784 for (j = 0; j < w; j++) temp[j] = gamma256[src0[j]] * gv;
7785 }
7786 else /* Leave RGB values as they were */
7787 {
7788 for (j = 0; j < w; j++) temp[j] = src0[j] * gv;
7789 }
7790 for (j = 1; j < lenY; j++)
7791 {
7792 double gv = gaussY[j];
7793
7794 k = (y + j) % mh2;
7795 if (k >= h) k = mh2 - k;
7796 src0 = chan + k * w;
7797 k = abs(y - j) % mh2;
7798 if (k >= h) k = mh2 - k;
7799 src1 = chan + k * w;
7800 if (gcor) /* Gamma-correct */
7801 {
7802 for (k = 0; k < w; k++)
7803 {
7804 temp[k] += (gamma256[src0[k]] +
7805 gamma256[src1[k]]) * gv;
7806 }
7807 }
7808 else /* Leave alone */
7809 {
7810 for (k = 0; k < w; k++)
7811 {
7812 temp[k] += (src0[k] + src1[k]) * gv;
7813 }
7814 }
7815 }
7816 }
7817
7818 typedef struct {
7819 double *gaussX, *gaussY, *temp;
7820 unsigned char *mask;
7821 int *idx;
7822 int lenX, lenY;
7823 int channel, gcor;
7824 // For unsharp mask
7825 int threshold;
7826 double amount;
7827 } gaussd;
7828
7829 /* Extend horizontal array, using precomputed indices */
gauss_extend(gaussd * gd,double * temp,int w,int bpp)7830 static void gauss_extend(gaussd *gd, double *temp, int w, int bpp)
7831 {
7832 double *dest, *src;
7833 int i, l = gd->lenX - 1, *tp = gd->idx;
7834
7835 dest = temp - l * bpp;
7836 while (TRUE)
7837 {
7838 for (i = 0; i < l; i++ , dest += bpp)
7839 {
7840 src = temp + *tp++ * bpp;
7841 dest[0] = src[0];
7842 if (bpp == 1) continue;
7843 dest[1] = src[1];
7844 dest[2] = src[2];
7845 }
7846 if (dest != temp) break; // "w * bpp" is definitely nonzero
7847 dest += w * bpp;
7848 }
7849 }
7850
7851 /* Apply RGB horizontal filter */
hor_gauss3(double * temp,int w,double * gaussX,int lenX,unsigned char * mask)7852 static void hor_gauss3(double *temp, int w, double *gaussX, int lenX,
7853 unsigned char *mask)
7854 {
7855 int j, jj, k, x1, x2;
7856 double sum0, sum1, sum2;
7857
7858 for (j = jj = 0; jj < w; jj++ , j += 3)
7859 {
7860 if (mask[jj] == 255) continue;
7861 sum0 = temp[j] * gaussX[0];
7862 sum1 = temp[j + 1] * gaussX[0];
7863 sum2 = temp[j + 2] * gaussX[0];
7864 x1 = x2 = j;
7865 for (k = 1; k < lenX; k++)
7866 {
7867 double gv = gaussX[k];
7868 x1 -= 3; x2 += 3;
7869 sum0 += (temp[x1] + temp[x2]) * gv;
7870 sum1 += (temp[x1 + 1] + temp[x2 + 1]) * gv;
7871 sum2 += (temp[x1 + 2] + temp[x2 + 2]) * gv;
7872 }
7873 temp[x1] = sum0;
7874 temp[x1 + 1] = sum1;
7875 temp[x1 + 2] = sum2;
7876 }
7877 }
7878
7879 // !!! Will need extra checks if used for out-of-range values
pack_row3(unsigned char * dest,const double * src,int w,int gcor,unsigned char * mask)7880 static void pack_row3(unsigned char *dest, const double *src, int w, int gcor,
7881 unsigned char *mask)
7882 {
7883 int j, jj, uninit_(k0), uninit_(k1), uninit_(k2), m;
7884 double sum0, sum1, sum2, mm;
7885
7886 for (j = jj = 0; jj < w; jj++ , j += 3)
7887 {
7888 if (mask[jj] == 255) continue;
7889 sum0 = src[j];
7890 sum1 = src[j + 1];
7891 sum2 = src[j + 2];
7892 if (!gcor) /* Simply round to nearest */
7893 {
7894 k0 = rint(sum0);
7895 k1 = rint(sum1);
7896 k2 = rint(sum2);
7897 }
7898 m = mask[jj];
7899 if (paint_gamma && m) /* Gamma corrected mask blend */
7900 {
7901 if (!gcor) // RGB to linear
7902 {
7903 sum0 = gamma256[k0];
7904 sum1 = gamma256[k1];
7905 sum2 = gamma256[k2];
7906 }
7907 mm = m / 255.0;
7908 sum0 += (gamma256[dest[j + 0]] - sum0) * mm;
7909 sum1 += (gamma256[dest[j + 1]] - sum1) * mm;
7910 sum2 += (gamma256[dest[j + 2]] - sum2) * mm;
7911 m = 0;
7912 goto ungamma;
7913 }
7914 if (gcor) /* Reverse gamma correction */
7915 {
7916 ungamma: k0 = UNGAMMA256(sum0);
7917 k1 = UNGAMMA256(sum1);
7918 k2 = UNGAMMA256(sum2);
7919 }
7920 k0 = k0 * 255 + (dest[j] - k0) * m;
7921 dest[j] = (k0 + (k0 >> 8) + 1) >> 8;
7922 k1 = k1 * 255 + (dest[j + 1] - k1) * m;
7923 dest[j + 1] = (k1 + (k1 >> 8) + 1) >> 8;
7924 k2 = k2 * 255 + (dest[j + 2] - k2) * m;
7925 dest[j + 2] = (k2 + (k2 >> 8) + 1) >> 8;
7926 }
7927 }
7928
7929 /* Most-used variables are local to inner blocks to shorten their live ranges -
7930 * otherwise stupid compilers might allocate them to memory */
gauss_filter(tcb * thread)7931 static void gauss_filter(tcb *thread)
7932 {
7933 gaussd *gd = thread->data;
7934 int lenX = gd->lenX, gcor = gd->gcor, channel = gd->channel;
7935 int i, ii, cnt, wid, bpp;
7936 double sum, *temp, *gaussX = gd->gaussX;
7937 unsigned char *chan, *dest, *mask = gd->mask;
7938
7939 cnt = thread->nsteps;
7940 bpp = BPP(channel);
7941 wid = mem_width * bpp;
7942 chan = mem_undo_previous(channel);
7943 temp = gd->temp + (lenX - 1) * bpp;
7944 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
7945 {
7946 vert_gauss(chan, wid, mem_height, i, temp, gd->gaussY, gd->lenY, gcor);
7947 gauss_extend(gd, temp, mem_width, bpp);
7948 row_protected(0, i, mem_width, mask);
7949 dest = mem_img[channel] + i * wid;
7950 if (bpp == 3) /* Run 3-bpp horizontal filter */
7951 {
7952 hor_gauss3(temp, mem_width, gaussX, lenX, mask);
7953 pack_row3(dest, gd->temp, mem_width, gcor, mask);
7954 }
7955 else /* Run 1-bpp horizontal filter - no gamma here */
7956 {
7957 int j, k, k0;
7958
7959 for (j = 0; j < mem_width; j++)
7960 {
7961 if (mask[j] == 255) continue;
7962 sum = temp[j] * gaussX[0];
7963 for (k = 1; k < lenX; k++)
7964 {
7965 sum += (temp[j - k] + temp[j + k]) * gaussX[k];
7966 }
7967 k0 = rint(sum);
7968 k0 = k0 * 255 + (dest[j] - k0) * mask[j];
7969 dest[j] = (k0 + (k0 >> 8) + 1) >> 8;
7970 }
7971 }
7972 if (thread_step(thread, ii + 1, cnt, 10)) break;
7973 }
7974 thread_done(thread);
7975 }
7976
7977 /* The inner loops are coded the way they are because one must spell everything
7978 * out for dumb compiler to get acceptable code out of it */
gauss_filter_rgba(tcb * thread)7979 static void gauss_filter_rgba(tcb *thread)
7980 {
7981 gaussd *gd = thread->data;
7982 int i, ii, cnt, mh2, lenX = gd->lenX, lenY = gd->lenY, gcor = gd->gcor;
7983 double sum, sum1, sum2, mult, *temp, *tmpa, *atmp, *src, *gaussX, *gaussY;
7984 unsigned char *chan, *dest, *alpha, *dsta, *mask = gd->mask;
7985
7986 cnt = thread->nsteps;
7987 chan = mem_undo_previous(CHN_IMAGE);
7988 alpha = mem_undo_previous(CHN_ALPHA);
7989 gaussX = gd->gaussX;
7990 gaussY = gd->gaussY;
7991 temp = gd->temp + (lenX - 1) * 3;
7992 mh2 = mem_height > 1 ? 2 * mem_height - 2 : 1;
7993
7994 /* Set up the main row buffer and process the image */
7995 tmpa = temp + mem_width * 3 + (lenX - 1) * (3 + 3);
7996 atmp = tmpa + mem_width * 3 + (lenX - 1) * (3 + 1);
7997 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
7998 {
7999 /* Apply vertical filter */
8000 {
8001 unsigned char *srcc, *src0, *src1;
8002 unsigned char *alff, *alf0, *alf1;
8003 int j, k;
8004
8005 alff = alpha + i * mem_width;
8006 srcc = chan + i * mem_width * 3;
8007 if (gcor) /* Gamma correct */
8008 {
8009 double gk = gaussY[0];
8010 int j, jj;
8011
8012 for (j = jj = 0; j < mem_width; j++)
8013 {
8014 double ak, tv;
8015
8016 atmp[j] = ak = alff[j] * gk;
8017 temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8018 tmpa[jj++] = tv * ak;
8019 temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8020 tmpa[jj++] = tv * ak;
8021 temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8022 tmpa[jj++] = tv * ak;
8023 }
8024 }
8025 else /* Use as is */
8026 {
8027 double gk = gaussY[0];
8028 int j, jj;
8029
8030 for (j = jj = 0; j < mem_width; j++)
8031 {
8032 double ak, tv;
8033
8034 atmp[j] = ak = alff[j] * gk;
8035 temp[jj] = (tv = srcc[jj]) * gk;
8036 tmpa[jj++] = tv * ak;
8037 temp[jj] = (tv = srcc[jj]) * gk;
8038 tmpa[jj++] = tv * ak;
8039 temp[jj] = (tv = srcc[jj]) * gk;
8040 tmpa[jj++] = tv * ak;
8041 }
8042 }
8043 for (j = 1; j < lenY; j++)
8044 {
8045 double gk = gaussY[j];
8046
8047 k = (i + j) % mh2;
8048 if (k >= mem_height) k = mh2 - k;
8049 alf0 = alpha + k * mem_width;
8050 src0 = chan + k * mem_width * 3;
8051 k = abs(i - j) % mh2;
8052 if (k >= mem_height) k = mh2 - k;
8053 alf1 = alpha + k * mem_width;
8054 src1 = chan + k * mem_width * 3;
8055 if (gcor) /* Gamma correct */
8056 {
8057 int k, kk;
8058
8059 for (k = kk = 0; k < mem_width; k++)
8060 {
8061 double ak0, ak1, tv0, tv1;
8062
8063 ak0 = alf0[k] * gk;
8064 ak1 = alf1[k] * gk;
8065 atmp[k] += ak0 + ak1;
8066 tv0 = gamma256[src0[kk]];
8067 tv1 = gamma256[src1[kk]];
8068 temp[kk] += (tv0 + tv1) * gk;
8069 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8070 tv0 = gamma256[src0[kk]];
8071 tv1 = gamma256[src1[kk]];
8072 temp[kk] += (tv0 + tv1) * gk;
8073 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8074 tv0 = gamma256[src0[kk]];
8075 tv1 = gamma256[src1[kk]];
8076 temp[kk] += (tv0 + tv1) * gk;
8077 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8078 }
8079 }
8080 else /* Use as is */
8081 {
8082 int k, kk;
8083
8084 for (k = kk = 0; k < mem_width; k++)
8085 {
8086 double ak0, ak1, tv0, tv1;
8087
8088 ak0 = alf0[k] * gk;
8089 ak1 = alf1[k] * gk;
8090 atmp[k] += ak0 + ak1;
8091 tv0 = src0[kk];
8092 tv1 = src1[kk];
8093 temp[kk] += (tv0 + tv1) * gk;
8094 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8095 tv0 = src0[kk];
8096 tv1 = src1[kk];
8097 temp[kk] += (tv0 + tv1) * gk;
8098 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8099 tv0 = src0[kk];
8100 tv1 = src1[kk];
8101 temp[kk] += (tv0 + tv1) * gk;
8102 tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8103 }
8104 }
8105 }
8106 }
8107 gauss_extend(gd, temp, mem_width, 3);
8108 gauss_extend(gd, tmpa, mem_width, 3);
8109 gauss_extend(gd, atmp, mem_width, 1);
8110 row_protected(0, i, mem_width, mask);
8111 dest = mem_img[CHN_IMAGE] + i * mem_width * 3;
8112 dsta = mem_img[CHN_ALPHA] + i * mem_width;
8113 /* Horizontal RGBA filter */
8114 {
8115 int j, jj, k, kk, x1, x2;
8116
8117 for (j = jj = 0; j < mem_width; j++ , jj += 3)
8118 {
8119 if (mask[j] == 255) continue;
8120
8121 sum = atmp[j] * gaussX[0];
8122 for (k = 1; k < lenX; k++)
8123 {
8124 sum += (atmp[j - k] + atmp[j + k]) * gaussX[k];
8125 }
8126 k = rint(sum);
8127 src = temp;
8128 mult = 1.0;
8129 if (k)
8130 {
8131 src = tmpa;
8132 mult /= sum;
8133 }
8134 kk = mask[j];
8135 k = k * 255 + (dsta[j] - k) * kk;
8136 if (k) mask[j] = (255 * kk * dsta[j]) / k;
8137 dsta[j] = (k + (k >> 8) + 1) >> 8;
8138
8139 sum = src[jj] * gaussX[0];
8140 sum1 = src[jj + 1] * gaussX[0];
8141 sum2 = src[jj + 2] * gaussX[0];
8142 x1 = x2 = jj;
8143 for (k = 1; k < lenX; k++)
8144 {
8145 double gv = gaussX[k];
8146 x1 -= 3; x2 += 3;
8147 sum += (src[x1] + src[x2]) * gv;
8148 sum1 += (src[x1 + 1] + src[x2 + 1]) * gv;
8149 sum2 += (src[x1 + 2] + src[x2 + 2]) * gv;
8150 }
8151 temp[x1] = sum * mult;
8152 temp[x1 + 1] = sum1 * mult;
8153 temp[x1 + 2] = sum2 * mult;
8154 }
8155 pack_row3(dest, gd->temp, mem_width, gcor, mask);
8156 }
8157 if (thread_step(thread, ii + 1, cnt, 10)) break;
8158 }
8159 thread_done(thread);
8160 }
8161
8162 /* Modes: 0 - normal, 1 - RGBA, 2 - DoG */
init_gauss(gaussd * gd,double radiusX,double radiusY,int mode)8163 static threaddata *init_gauss(gaussd *gd, double radiusX, double radiusY, int mode)
8164 {
8165 threaddata *tdata;
8166 int i, j, k, l, lenX, lenY, w, bpp = MEM_BPP;
8167 double sum, exkX, exkY, *gauss;
8168
8169
8170 /* Cutoff point is where gaussian becomes < 1/255 */
8171 gd->lenX = lenX = ceil(radiusX) + 2;
8172 gd->lenY = lenY = ceil(radiusY) + 2;
8173 exkX = -log(255.0) / ((radiusX + 1.0) * (radiusX + 1.0));
8174 exkY = -log(255.0) / ((radiusY + 1.0) * (radiusY + 1.0));
8175
8176 /* Allocate memory */
8177 if (mode == 1) i = 7; /* Extra linebuffer for RGBA */
8178 else if (mode == 2) i = bpp + bpp; /* Extra buffer in DoG mode */
8179 else i = bpp;
8180 l = 2 * (lenX - 1);
8181 w = mem_width + l;
8182
8183 tdata = talloc(MA_ALIGN_DOUBLE,
8184 image_threads(mem_width, mem_height),
8185 gd, sizeof(gaussd),
8186 &gd->gaussX, lenX * sizeof(double),
8187 &gd->gaussY, lenY * sizeof(double),
8188 &gd->idx, l * sizeof(int),
8189 NULL,
8190 &gd->temp, i * w * sizeof(double),
8191 &gd->mask, mem_width,
8192 NULL);
8193 if (!tdata) return (NULL);
8194
8195 /* Prepare filters */
8196 j = lenX; gauss = gd->gaussX;
8197 while (1)
8198 {
8199 sum = gauss[0] = 1.0;
8200 for (i = 1; i < j; i++)
8201 {
8202 sum += 2.0 * (gauss[i] = exp((double)(i * i) * exkX));
8203 }
8204 sum = 1.0 / sum;
8205 for (i = 0; i < j; i++)
8206 {
8207 gauss[i] *= sum;
8208 }
8209 if (gauss != gd->gaussX) break;
8210 exkX = exkY; j = lenY; gauss = gd->gaussY;
8211 }
8212
8213 /* Prepare horizontal indices, assuming mirror boundary */
8214 if (mem_width > 1) // Else, good already (zeroed out)
8215 {
8216 int *idx = gd->idx + lenX - 1; // To simplify indexing
8217
8218 k = 2 * mem_width - 2;
8219 for (i = 1; i < lenX; i++)
8220 {
8221 j = i % k;
8222 idx[-i] = j < mem_width ? j : k - j;
8223 j = (mem_width + i - 1) % k;
8224 idx[i - 1] = j < mem_width ? j : k - j;
8225
8226 }
8227 }
8228 return (tdata);
8229 }
8230
8231 /* Gaussian blur */
mem_gauss(double radiusX,double radiusY,int gcor)8232 void mem_gauss(double radiusX, double radiusY, int gcor)
8233 {
8234 gaussd gd;
8235 threaddata *tdata;
8236 int rgba, rgbb;
8237
8238 /* RGBA or not? */
8239 rgba = (mem_channel == CHN_IMAGE) && mem_img[CHN_ALPHA] && RGBA_mode;
8240 rgbb = rgba && !channel_dis[CHN_ALPHA];
8241
8242 /* Create arrays */
8243 if (mem_channel != CHN_IMAGE) gcor = FALSE;
8244 gd.gcor = gcor;
8245 gd.channel = mem_channel;
8246 tdata = init_gauss(&gd, radiusX, radiusY, rgbb);
8247 if (!tdata)
8248 {
8249 memory_errors(1);
8250 return;
8251 }
8252
8253 progress_init(_("Gaussian Blur"), 1);
8254 if (rgbb) /* Coupled RGBA */
8255 launch_threads(gauss_filter_rgba, tdata, NULL, mem_height);
8256 else /* One channel, or maybe two */
8257 {
8258 launch_threads(gauss_filter, tdata, NULL, mem_height);
8259 if (rgba) /* Need to process alpha too */
8260 {
8261 #ifdef U_THREADS
8262 int i, j = tdata->count;
8263
8264 for (i = 0; i < j; i++)
8265 {
8266 gaussd *gp = tdata->threads[i]->data;
8267 gp->channel = CHN_ALPHA;
8268 gp->gcor = FALSE;
8269 }
8270 #else
8271 gaussd *gp = tdata->threads[0]->data;
8272 gp->channel = CHN_ALPHA;
8273 gp->gcor = FALSE;
8274 #endif
8275 launch_threads(gauss_filter, tdata, NULL, mem_height);
8276 }
8277 }
8278 progress_end();
8279 free(tdata);
8280 }
8281
unsharp_filter(tcb * thread)8282 static void unsharp_filter(tcb *thread)
8283 {
8284 gaussd *gd = thread->data;
8285 int lenX = gd->lenX, threshold = gd->threshold, channel = gd->channel;
8286 int i, ii, cnt, wid, bpp, gcor = gd->gcor;
8287 double *temp, *gaussX = gd->gaussX, *gt = gd->temp;
8288 double sum, amount = gd->amount, u = gcor ? 1.0 : 255.0;
8289 unsigned char *chan, *dest, *mask = gd->mask;
8290
8291 cnt = thread->nsteps;
8292 bpp = BPP(channel);
8293 wid = mem_width * bpp;
8294 chan = mem_undo_previous(channel);
8295 temp = gd->temp + (lenX - 1) * bpp;
8296 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
8297 {
8298 vert_gauss(chan, wid, mem_height, i, temp, gd->gaussY, gd->lenY, gcor);
8299 gauss_extend(gd, temp, mem_width, bpp);
8300 row_protected(0, i, mem_width, mask);
8301 dest = mem_img[channel] + i * wid;
8302 if (bpp == 3) /* Run 3-bpp horizontal filter */
8303 {
8304 int j, jj, k, k1, k2;
8305
8306 hor_gauss3(temp, mem_width, gaussX, lenX, mask);
8307 /* Threshold to mask */
8308 if (threshold) for (j = jj = 0; jj < mem_width; jj++ , j += 3)
8309 {
8310 if (mask[jj] == 255) continue;
8311 if (gcor) /* Reverse gamma correction */
8312 {
8313 k = UNGAMMA256(gt[j]);
8314 k1 = UNGAMMA256(gt[j + 1]);
8315 k2 = UNGAMMA256(gt[j + 2]);
8316 }
8317 else /* Simply round to nearest */
8318 {
8319 k = rint(gt[j]);
8320 k1 = rint(gt[j + 1]);
8321 k2 = rint(gt[j + 2]);
8322 }
8323 /* !!! GIMP has an apparent bug which I won't reproduce - so mtPaint's
8324 * threshold value means _actual_ difference, not half of it - WJ */
8325 if ((abs(k - dest[j]) < threshold) &&
8326 (abs(k1 - dest[j + 1]) < threshold) &&
8327 (abs(k2 - dest[j + 2]) < threshold))
8328 mask[jj] = 255;
8329 }
8330
8331 /* !!! Mask is ignored here - but this pass takes about
8332 * 25% time at worst, and masking adds 5% time at best;
8333 * so the common case of no mask is optimized for - WJ */
8334 k = mem_width * 3;
8335 for (j = 0; j < k; j++)
8336 {
8337 sum = gcor ? gamma256[dest[j]] : dest[j];
8338 sum += amount * (sum - gt[j]);
8339 /* Limit values, for pack_row3() cannot */
8340 gt[j] = sum < 0.0 ? 0.0 : sum > u ? u : sum;
8341 }
8342
8343 pack_row3(dest, gt, mem_width, gcor, mask);
8344 }
8345 else /* Run 1-bpp horizontal filter - no gamma here */
8346 {
8347 int j, k;
8348
8349 for (j = 0; j < mem_width; j++)
8350 {
8351 if (mask[j] == 255) continue;
8352 sum = temp[j] * gaussX[0];
8353 for (k = 1; k < lenX; k++)
8354 {
8355 sum += (temp[j - k] + temp[j + k]) * gaussX[k];
8356 }
8357 k = rint(sum);
8358 /* Threshold */
8359 /* !!! Same non-bug as above */
8360 if (abs(k - dest[j]) < threshold) continue;
8361 /* Combine values */
8362 k = rint(dest[j] + amount * (dest[j] - sum));
8363 k = k < 0 ? 0 : k > 255 ? 255 : k;
8364 /* Store the result */
8365 k = k * 255 + (dest[j] - k) * mask[j];
8366 dest[j] = (k + (k >> 8) + 1) >> 8;
8367 }
8368 }
8369 if (thread_step(thread, ii + 1, cnt, 10)) break;
8370 }
8371 thread_done(thread);
8372 }
8373
8374 /* Unsharp mask */
mem_unsharp(double radius,double amount,int threshold,int gcor)8375 void mem_unsharp(double radius, double amount, int threshold, int gcor)
8376 {
8377 gaussd gd;
8378 threaddata *tdata;
8379
8380 /* Create arrays */
8381 if (mem_channel != CHN_IMAGE) gcor = 0;
8382 gd.gcor = gcor;
8383 gd.channel = mem_channel;
8384 gd.amount = amount;
8385 gd.threshold = threshold;
8386 // !!! No RGBA mode for now
8387 tdata = init_gauss(&gd, radius, radius, 0);
8388 if (!tdata)
8389 {
8390 memory_errors(1);
8391 return;
8392 }
8393 /* Run filter */
8394 launch_threads(unsharp_filter, tdata, _("Unsharp Mask"), mem_height);
8395 free(tdata);
8396 }
8397
8398 /* Retroactive masking - by blending with undo frame */
mask_merge(unsigned char * old,int channel,unsigned char * mask)8399 void mask_merge(unsigned char *old, int channel, unsigned char *mask)
8400 {
8401 chanlist tlist;
8402 unsigned char *dest, *mask0 = NULL;
8403 int i, ofs, bpp = BPP(channel);
8404
8405 memcpy(tlist, mem_img, sizeof(chanlist));
8406 tlist[channel] = old;
8407
8408 /* Clear mask or copy mask channel into it */
8409 if ((channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
8410 mask0 = tlist[CHN_MASK];
8411
8412 for (i = 0; i < mem_height; i++)
8413 {
8414 ofs = i * mem_width;
8415 prep_mask(0, 1, mem_width, mask, mask0 ? mask0 + ofs : NULL,
8416 tlist[CHN_IMAGE] + ofs * mem_img_bpp);
8417 dest = mem_img[channel] + ofs * bpp;
8418 process_img(0, 1, mem_width, mask, dest, dest, old + ofs * bpp,
8419 NULL, bpp, BLENDF_SET);
8420 }
8421 }
8422
dog_filter(tcb * thread)8423 static void dog_filter(tcb *thread)
8424 {
8425 gaussd *gd = thread->data;
8426 int channel = gd->channel, bpp = BPP(channel), wid = mem_width * bpp;
8427 int i, ii, cnt, gcor = gd->gcor;
8428 int lenW = gd->lenX, lenN = gd->lenY;
8429 double sum, sum1, sum2, *tmp1, *tmp2;
8430 double *gaussW = gd->gaussX, *gaussN = gd->gaussY;
8431 unsigned char *chan, *dest;
8432
8433 cnt = thread->nsteps;
8434 chan = mem_undo_previous(channel);
8435 tmp1 = gd->temp + (lenW - 1) * bpp;
8436 tmp2 = tmp1 + wid + (lenW - 1) * bpp * 2;
8437 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
8438 {
8439 vert_gauss(chan, wid, mem_height, i, tmp1, gaussW, lenW, gcor);
8440 vert_gauss(chan, wid, mem_height, i, tmp2, gaussN, lenN, gcor);
8441 gauss_extend(gd, tmp1, mem_width, bpp);
8442 gauss_extend(gd, tmp2, mem_width, bpp);
8443 dest = mem_img[channel] + i * wid;
8444 if (bpp == 3) /* Run 3-bpp horizontal filter */
8445 {
8446 int j, jj, k, k1, k2;
8447
8448 for (j = jj = 0; jj < mem_width; jj++ , j += 3)
8449 {
8450 int x1, x2, x3, x4;
8451
8452 sum = tmp1[j] * gaussW[0] - tmp2[j] * gaussN[0];
8453 sum1 = tmp1[j + 1] * gaussW[0] - tmp2[j + 1] * gaussN[0];
8454 sum2 = tmp1[j + 2] * gaussW[0] - tmp2[j + 2] * gaussN[0];
8455 x1 = x2 = j;
8456 for (k = 1; k < lenW; k++)
8457 {
8458 double gv = gaussW[k];
8459 x1 -= 3; x2 += 3;
8460 sum += (tmp1[x1] + tmp1[x2]) * gv;
8461 sum1 += (tmp1[x1 + 1] + tmp1[x2 + 1]) * gv;
8462 sum2 += (tmp1[x1 + 2] + tmp1[x2 + 2]) * gv;
8463 }
8464 x3 = x4 = j;
8465 for (k = 1; k < lenN; k++)
8466 {
8467 double gv = gaussN[k];
8468 x3 -= 3; x4 += 3;
8469 sum -= (tmp2[x3] + tmp2[x4]) * gv;
8470 sum1 -= (tmp2[x3 + 1] + tmp2[x4 + 1]) * gv;
8471 sum2 -= (tmp2[x3 + 2] + tmp2[x4 + 2]) * gv;
8472 }
8473 if (gcor)
8474 {
8475 #if 1 /* Reverse gamma - but does it make sense? */
8476 k = UNGAMMA256X(sum);
8477 k1 = UNGAMMA256X(sum1);
8478 k2 = UNGAMMA256X(sum2);
8479 #else /* Let values remain linear */
8480 k = rint(sum * 255.0);
8481 k = k < 0 ? 0 : k;
8482 k1 = rint(sum1 * 255.0);
8483 k1 = k1 < 0 ? 0 : k1;
8484 k2 = rint(sum2 * 255.0);
8485 k2 = k2 < 0 ? 0 : k2;
8486 #endif
8487 }
8488 else
8489 {
8490 k = rint(sum);
8491 k = k < 0 ? 0 : k;
8492 k1 = rint(sum1);
8493 k1 = k1 < 0 ? 0 : k1;
8494 k2 = rint(sum2);
8495 k2 = k2 < 0 ? 0 : k2;
8496 }
8497 /* Store the result */
8498 dest[j] = k;
8499 dest[j + 1] = k1;
8500 dest[j + 2] = k2;
8501 }
8502 }
8503 else /* Run 1-bpp horizontal filter - no gamma here */
8504 {
8505 int j, k;
8506
8507 for (j = 0; j < mem_width; j++)
8508 {
8509 sum = tmp1[j] * gaussW[0] - tmp2[j] * gaussN[0];
8510 for (k = 1; k < lenW; k++)
8511 {
8512 sum += (tmp1[j - k] + tmp1[j + k]) * gaussW[k];
8513 }
8514 for (k = 1; k < lenN; k++)
8515 {
8516 sum -= (tmp2[j - k] + tmp2[j + k]) * gaussN[k];
8517 }
8518 k = rint(sum);
8519 dest[j] = k < 0 ? 0 : k;
8520 }
8521 }
8522 if (thread_step(thread, ii + 1, cnt, 10)) break;
8523 }
8524 thread_done(thread);
8525 }
8526
8527 /* Difference of Gaussians */
mem_dog(double radiusW,double radiusN,int norm,int gcor)8528 void mem_dog(double radiusW, double radiusN, int norm, int gcor)
8529 {
8530 gaussd gd;
8531 threaddata *tdata;
8532
8533 /* Create arrays */
8534 if (mem_channel != CHN_IMAGE) gcor = 0;
8535 gd.gcor = gcor;
8536 gd.channel = mem_channel;
8537 // !!! No RGBA mode for ever - DoG mode instead
8538 tdata = init_gauss(&gd, radiusW, radiusN, 2);
8539 if (!tdata)
8540 {
8541 memory_errors(1);
8542 return;
8543 }
8544
8545 /* Run filter */
8546 progress_init(_("Difference of Gaussians"), 1);
8547 launch_threads(dog_filter, tdata, NULL, mem_height);
8548
8549 /* Normalize values (expand to full 0..255) */
8550 while (norm)
8551 {
8552 unsigned char *tmp, xtb[256];
8553 double d;
8554 int i, l, mx = 0;
8555
8556 l = mem_height * mem_width * BPP(mem_channel);
8557 tmp = mem_img[mem_channel];
8558 for (i = l; i; i-- , tmp++)
8559 if (*tmp > mx) mx = *tmp;
8560
8561 if (!mx) break;
8562 d = 255.0 / (double)mx;
8563 for (i = 0; i <= mx; i++) xtb[i] = rint(i * d);
8564
8565 tmp = mem_img[mem_channel];
8566 for (i = l; i; i-- , tmp++) *tmp = xtb[*tmp];
8567
8568 break;
8569 }
8570
8571 /* Mask-merge with prior picture */
8572 mask_merge(mem_undo_previous(mem_channel), mem_channel, gd.mask);
8573
8574 progress_end();
8575 free(tdata);
8576 }
8577
8578
8579 /* !!! Kuwahara-Nagao filter's radius is limited to 255, to use byte offsets */
8580 typedef struct {
8581 int *idx; // Index array
8582 double *rs; // Sum of gamma-corrected RGB if using gamma
8583 int *avg; // Sum of pixel values (for average)
8584 int *dis; // Sum of pixel values squared (for variance)
8585 unsigned char *min; // Offset to minimum-variance square
8586 double r2i; // 1/r^2 to multiply things with
8587 int w, r; // Row width & filter radius
8588 int gcor; // Gamma correction toggle
8589 int l, rl; // Row array lengths
8590 } kuwahara_info;
8591
8592 /* This function uses running sums, which gives x87 FPU's "precision jitter"
8593 * a chance to accumulate; to avoid, reduced-precision gamma is used - WJ */
kuwahara_row(unsigned char * src,int base,int add,kuwahara_info * info)8594 static void kuwahara_row(unsigned char *src, int base, int add, kuwahara_info *info)
8595 {
8596 double rs0 = 0.0, rs1 = 0.0, rs2 = 0.0;
8597 int avg[3] = { 0, 0, 0 }, dis[3] = { 0, 0, 0 };
8598 int i, w, r = info->r, gc = info->gcor, *idx = info->idx;
8599
8600 w = info->w + r++;
8601 for (i = -r; i < w; i++)
8602 {
8603 unsigned char *tvv;
8604 int tv, i3, *iavg, *idis;
8605
8606 tvv = src + idx[i];
8607 avg[0] += (tv = tvv[0]);
8608 dis[0] += tv * tv;
8609 avg[1] += (tv = tvv[1]);
8610 dis[1] += tv * tv;
8611 avg[2] += (tv = tvv[2]);
8612 dis[2] += tv * tv;
8613 if (gc)
8614 {
8615 rs0 += Fgamma256[tvv[0]];
8616 rs1 += Fgamma256[tvv[1]];
8617 rs2 += Fgamma256[tvv[2]];
8618 }
8619 if (i < 0) continue;
8620
8621 tvv = src + idx[i - r];
8622 avg[0] -= (tv = tvv[0]);
8623 dis[0] -= tv * tv;
8624 avg[1] -= (tv = tvv[1]);
8625 dis[1] -= tv * tv;
8626 avg[2] -= (tv = tvv[2]);
8627 dis[2] -= tv * tv;
8628 i3 = (base + i) * 3;
8629 iavg = info->avg + i3;
8630 idis = info->dis + i3;
8631 if (add)
8632 {
8633 iavg[0] += avg[0];
8634 iavg[1] += avg[1];
8635 iavg[2] += avg[2];
8636 idis[0] += dis[0];
8637 idis[1] += dis[1];
8638 idis[2] += dis[2];
8639 }
8640 else
8641 {
8642 iavg[0] -= avg[0];
8643 iavg[1] -= avg[1];
8644 iavg[2] -= avg[2];
8645 idis[0] -= dis[0];
8646 idis[1] -= dis[1];
8647 idis[2] -= dis[2];
8648 }
8649 if (gc)
8650 {
8651 double *irs = info->rs + i3;
8652
8653 rs0 -= Fgamma256[tvv[0]];
8654 rs1 -= Fgamma256[tvv[1]];
8655 rs2 -= Fgamma256[tvv[2]];
8656 if (add)
8657 {
8658 irs[0] += rs0;
8659 irs[1] += rs1;
8660 irs[2] += rs2;
8661 }
8662 else
8663 {
8664 irs[0] -= rs0;
8665 irs[1] -= rs1;
8666 irs[2] -= rs2;
8667 }
8668 }
8669 }
8670 }
8671
kuwahara_copy(int dest,int src,kuwahara_info * info)8672 static void kuwahara_copy(int dest, int src, kuwahara_info *info)
8673 {
8674 src *= 3; dest *= 3;
8675 memcpy(info->rs + dest, info->rs + src, info->rl * 3 * sizeof(double));
8676 memcpy(info->avg + dest, info->avg + src, info->l * 3 * sizeof(int));
8677 memcpy(info->dis + dest, info->dis + src, info->l * 3 * sizeof(int));
8678 }
8679
kuwahara_square(int idx,kuwahara_info * info)8680 static double kuwahara_square(int idx, kuwahara_info *info)
8681 {
8682 double r2i = info->r2i;
8683 int *dp = info->dis + idx * 3, *ap = info->avg + idx * 3;
8684 // !!! Multiplication is done this way to avoid integer overflow
8685 return (dp[0] + dp[1] + dp[2] - ((r2i * ap[0]) * ap[0] +
8686 (r2i * ap[1]) * ap[1] + (r2i * ap[2]) * ap[2]));
8687 }
8688
8689 /* For each X, locate the square with minimum variance & store its offset */
kuwahara_min(int base,kuwahara_info * info)8690 static void kuwahara_min(int base, kuwahara_info *info)
8691 {
8692 double da[256];
8693 int i, j, j1, w = info->w, r = info->r, min = -1;
8694
8695 for (i = 0; i < r; i++) da[i] = kuwahara_square(base + i, info);
8696 for (i = 0; i < w; i++)
8697 {
8698 j1 = (i + r) & 255;
8699 da[j1] = kuwahara_square(base + (i + r), info);
8700 if (min > i) // Old minimum still valid
8701 {
8702 if (da[j1] <= da[min & 255]) min = i + r;
8703 }
8704 else // Forced to find a new one
8705 {
8706 min = i;
8707 for (j = 1; j <= r; j++)
8708 if (da[(i + j) & 255] <= da[min & 255])
8709 min = i + j;
8710 }
8711 info->min[base + i] = min - i;
8712 }
8713 }
8714
8715 /* Replace each pixel in image row by nearest color in 3x3 Kuwahara'ed region */
kuwahara_detailed(unsigned char * buf,unsigned char * mask,unsigned char * dest,int y,int gcor)8716 static void kuwahara_detailed(unsigned char *buf, unsigned char *mask,
8717 unsigned char *dest, int y, int gcor)
8718 {
8719 unsigned char *tmp;
8720 int l, w = mem_width * 3;
8721 #define REGION_SIZE 9
8722 int steps[REGION_SIZE] = { 3, 3, w, 3, 3, w, 3, 3, w };
8723
8724 #if 0 /* Make scanning order the same as with flat image */
8725 l = (y + 2) % 3;
8726 buf += (w + 6) * l;
8727 steps [8 - 3 * l] -= (w + 6) * 3;
8728 #endif
8729
8730 row_protected(0, y, mem_width, mask);
8731 tmp = mem_img[CHN_IMAGE] + y * w;
8732 for (l = 0; l < mem_width; l++ , tmp += 3 , dest += 3)
8733 {
8734 unsigned char *tb, *found;
8735 int rr, gg, bb, op = *mask++;
8736
8737 if (op == 255) continue;
8738 /* Find the nearest color pixel */
8739 rr = tmp[0]; gg = tmp[1]; bb = tmp[2];
8740 found = tb = buf + l * 3;
8741 if (gcor) // Gamma corrected
8742 {
8743 double d, r2, g2, b2;
8744 int i;
8745
8746 d = 100.0; // More than 3*1.0^2
8747 r2 = gamma256[rr];
8748 g2 = gamma256[gg];
8749 b2 = gamma256[bb];
8750 for (i = 0; i < REGION_SIZE; tb += steps[i++])
8751 {
8752 double d2, dr, dg, db;
8753
8754 dr = gamma256[tb[0]] - r2;
8755 dg = gamma256[tb[1]] - g2;
8756 db = gamma256[tb[2]] - b2;
8757 d2 = dr * dr + dg * dg + db * db;
8758 if (d2 >= d) continue;
8759 found = tb; d = d2;
8760 }
8761 }
8762 else // Raw RGB
8763 {
8764 int i, d, d2;
8765
8766 d = 1000000; // More than 3*255^2
8767 for (i = 0; i < REGION_SIZE; tb += steps[i++])
8768 {
8769 d2 = (rr - tb[0]) * (rr - tb[0]) +
8770 (gg - tb[1]) * (gg - tb[1]) +
8771 (bb - tb[2]) * (bb - tb[2]);
8772 if (d2 >= d) continue;
8773 found = tb; d = d2;
8774 }
8775 }
8776 dest[0] = found[0];
8777 dest[1] = found[1];
8778 dest[2] = found[2];
8779 }
8780 #undef REGION_SIZE
8781 }
8782
8783 /* Convert virtual row to row index (mirror boundary) */
idx2row(int idx)8784 static int idx2row(int idx)
8785 {
8786 int j, k;
8787
8788 if (mem_height == 1) return (0);
8789 k = mem_height + mem_height - 2;
8790 j = abs(idx) % k;
8791 if (j >= mem_height) j = k - j;
8792 return (j);
8793 }
8794
8795 /* RGB only - cannot be generalized without speed loss */
mem_kuwahara(int r,int gcor,int detail)8796 void mem_kuwahara(int r, int gcor, int detail)
8797 {
8798 kuwahara_info info;
8799 unsigned char *mem, *src, *buf, *mask, *tmp, *timg, *tx;
8800 int i, j, k, l, ir, len, rl, r1 = r + 1;
8801 int w = mem_width * 3, wbuf = w + 3 * 2, ch = mem_channel;
8802 double r2i = 1.0 / (double)(r1 * r1);
8803
8804
8805 if (mem_img_bpp != 3) return; // Sanity check
8806
8807 len = mem_width + r + r + 1;
8808 info.l = l = mem_width + r;
8809 info.rl = rl = gcor ? l : 0;
8810 mem = multialloc(MA_ALIGN_DOUBLE,
8811 &info.rs, rl * r1 * 3 * sizeof(double),
8812 &info.avg, l * r1 * 3 * sizeof(int),
8813 &info.dis, l * r1 * 3 * sizeof(int),
8814 &info.idx, len * sizeof(int),
8815 &info.min, l * r1,
8816 &mask, mem_width,
8817 &timg, wbuf * 3,
8818 NULL);
8819 if (!mem)
8820 {
8821 memory_errors(1);
8822 return;
8823 }
8824 info.r2i = r2i; info.w = mem_width; info.r = r; info.gcor = gcor;
8825
8826 progress_init(_("Kuwahara-Nagao Filter"), 1);
8827 info.idx += r1;
8828 if (mem_width > 1) // All indices remain zero otherwise
8829 {
8830 k = mem_width + mem_width - 2;
8831 for (i = -(r + 1); i < mem_width + r; i++)
8832 {
8833 j = abs(i) % k;
8834 if (j >= mem_width) j = k - j;
8835 info.idx[i] = j * 3;
8836 }
8837 }
8838
8839 mem_channel = CHN_IMAGE; // For row_protected()
8840 src = mem_undo_previous(CHN_IMAGE);
8841 /* Initialize the bottom sum */
8842 for (i = -r; i <= 0; i++)
8843 kuwahara_row(src + idx2row(i) * w, 0, TRUE, &info);
8844 kuwahara_min(0, &info);
8845 /* Initialize the rest of sums */
8846 for (i = 1; i <= r; i++)
8847 {
8848 int j = l * i;
8849 kuwahara_copy(j, j - l, &info);
8850 kuwahara_row(src + idx2row(i - r1) * w, j, FALSE, &info);
8851 kuwahara_row(src + idx2row(i) * w, j, TRUE, &info);
8852 kuwahara_min(j, &info);
8853 }
8854 /* Actually process image */
8855 ir = i = 0;
8856 while (TRUE)
8857 {
8858 int j, k, jp;
8859
8860 if ((i * 10) % mem_height >= mem_height - 10)
8861 if (progress_update((float)(i + 1) / mem_height)) break;
8862
8863 /* Process a pixel row */
8864 if (!detail) row_protected(0, i, mem_width, mask);
8865 tmp = buf = timg + wbuf * (i % 3);
8866 for (j = 0; j < mem_width; j++)
8867 {
8868 double dis;
8869 int jj, jk;
8870
8871 tmp += 3;
8872 if (!detail && (mask[j] == 255)) continue;
8873 /* Select minimum variance square from covered rows */
8874 jj = j + l;
8875 jk = j + info.min[j];
8876 dis = kuwahara_square(jk, &info);
8877 // !!! Only the all-or-nothing mode for now - weighted mode not implemented yet
8878 for (k = 1; k < r1; k++ , jj += l)
8879 {
8880 int jv = jj + info.min[jj];
8881 double dv = kuwahara_square(jv, &info);
8882 if (dv < dis) jk = jv , dis = dv;
8883 }
8884 /* Calculate & store new RGB */
8885 jk *= 3;
8886 if (gcor)
8887 {
8888 double *wr = info.rs + jk;
8889 tmp[0] = UNGAMMA256(wr[0] * r2i);
8890 tmp[1] = UNGAMMA256(wr[1] * r2i);
8891 tmp[2] = UNGAMMA256(wr[2] * r2i);
8892 }
8893 else
8894 {
8895 int *ar = info.avg + jk;
8896 tmp[0] = rint(*ar++ * r2i);
8897 tmp[1] = rint(*ar++ * r2i);
8898 tmp[2] = rint(*ar * r2i);
8899 }
8900 }
8901
8902 if (detail)
8903 {
8904 /* Copy-extend the row on both ends */
8905 memcpy(buf, buf + 3, 3);
8906 memcpy(tmp + 3, tmp, 3);
8907 /* Copy-extend the top row */
8908 if (!i) memcpy(timg + wbuf * 2, buf, wbuf);
8909 else /* Build and mask-merge the previous row */
8910 {
8911 // Overwrite outgoing pixels of outgoing row
8912 tx = timg + wbuf * ((i + 1) % 3);
8913 kuwahara_detailed(timg, mask, tx, i - 1, gcor);
8914 tmp = mem_img[CHN_IMAGE] + (i - 1) * w;
8915 process_img(0, 1, mem_width, mask, tmp, tmp, tx,
8916 NULL, 3, BLENDF_SET | BLENDF_INVM);
8917 }
8918 }
8919 else
8920 {
8921 /* Mask-merge current row */
8922 tmp = mem_img[CHN_IMAGE] + i * w;
8923 process_img(0, 1, mem_width, mask, tmp, tmp, buf + 3,
8924 NULL, 3, BLENDF_SET | BLENDF_INVM);
8925 }
8926
8927 if (++i < mem_height)
8928 {
8929 /* Update sums for a new row */
8930 jp = ir * l;
8931 kuwahara_copy(jp, ((ir + r) % r1) * l, &info);
8932 kuwahara_row(src + idx2row(i - 1) * w, jp, FALSE, &info);
8933 kuwahara_row(src + idx2row(i + r) * w, jp, TRUE, &info);
8934 kuwahara_min(jp, &info);
8935 ir = (ir + 1) % r1;
8936 continue;
8937 }
8938
8939 if (detail)
8940 {
8941 /* Copy-extend the bottom row */
8942 memcpy(timg + wbuf * (i % 3), buf, wbuf);
8943 /* Build and mask-merge it */
8944 kuwahara_detailed(timg, mask, timg, i - 1, gcor);
8945 tmp = mem_img[CHN_IMAGE] + (i - 1) * w;
8946 process_img(0, 1, mem_width, mask, tmp, tmp, timg,
8947 NULL, 3, BLENDF_SET | BLENDF_INVM);
8948 }
8949 break;
8950 }
8951
8952 mem_channel = ch;
8953
8954 progress_end();
8955 free(mem);
8956 }
8957
8958 /// CLIPBOARD MASK
8959
mem_clip_mask_init(unsigned char val)8960 int mem_clip_mask_init(unsigned char val) // Initialise the clipboard mask
8961 {
8962 int j = mem_clip_w*mem_clip_h;
8963
8964 if (mem_clipboard) mem_clip_mask_clear(); // Remove old mask
8965
8966 mem_clip_mask = malloc(j);
8967 if (!mem_clip_mask) return 1; // Not able to allocate memory
8968
8969 memset(mem_clip_mask, val, j); // Start with fully opaque/clear mask
8970
8971 return 0;
8972 }
8973
mem_mask_colors(unsigned char * mask,unsigned char * img,unsigned char v,int width,int height,int bpp,int col0,int col1)8974 void mem_mask_colors(unsigned char *mask, unsigned char *img, unsigned char v,
8975 int width, int height, int bpp, int col0, int col1)
8976 {
8977 int i, j = width * height, k;
8978
8979 if (bpp == 1)
8980 {
8981 for (i = 0; i < j; i++)
8982 {
8983 if ((img[i] == col0) || (img[i] == col1)) mask[i] = v;
8984 }
8985 }
8986 else
8987 {
8988 for (i = 0; i < j; i++ , img += 3)
8989 {
8990 k = MEM_2_INT(img, 0);
8991 if ((k == col0) || (k == col1)) mask[i] = v;
8992 }
8993 }
8994 }
8995
mem_clip_mask_set(unsigned char val)8996 void mem_clip_mask_set(unsigned char val) // (un)Mask colours A and B on the clipboard
8997 {
8998 int aa, bb;
8999
9000 if (mem_clip_bpp == 1) /* Indexed/utility */
9001 {
9002 if (mem_channel == CHN_IMAGE)
9003 {
9004 aa = mem_col_A;
9005 bb = mem_col_B;
9006 }
9007 else
9008 {
9009 aa = channel_col_A[mem_channel];
9010 bb = channel_col_B[mem_channel];
9011 }
9012 }
9013 else /* RGB */
9014 {
9015 aa = PNG_2_INT(mem_col_A24);
9016 bb = PNG_2_INT(mem_col_B24);
9017 }
9018 mem_mask_colors(mem_clip_mask, mem_clipboard, val,
9019 mem_clip_w, mem_clip_h, mem_clip_bpp, aa, bb);
9020 }
9021
mem_clip_mask_clear()9022 void mem_clip_mask_clear() // Clear/remove the clipboard mask
9023 {
9024 free(mem_clip_mask);
9025 mem_clip_mask = NULL;
9026 }
9027
9028 /*
9029 * Extract alpha information from RGB image - alpha if pixel is in colour
9030 * scale of A->B. Return 0 if OK, 1 otherwise
9031 */
mem_scale_alpha(unsigned char * img,unsigned char * alpha,int width,int height,int mode)9032 int mem_scale_alpha(unsigned char *img, unsigned char *alpha,
9033 int width, int height, int mode)
9034 {
9035 int i, j = width * height, AA[3], BB[3], DD[6], chan, c1, c2, dc1, dc2;
9036 double p0, p1, p2, dchan, KK[6];
9037
9038 if (!img || !alpha) return (1);
9039
9040 AA[0] = mem_col_A24.red;
9041 AA[1] = mem_col_A24.green;
9042 AA[2] = mem_col_A24.blue;
9043 BB[0] = mem_col_B24.red;
9044 BB[1] = mem_col_B24.green;
9045 BB[2] = mem_col_B24.blue;
9046 for (i = 0; i < 3; i++)
9047 {
9048 if (AA[i] < BB[i])
9049 {
9050 DD[i] = AA[i];
9051 DD[i + 3] = BB[i];
9052 }
9053 else
9054 {
9055 DD[i] = BB[i];
9056 DD[i + 3] = AA[i];
9057 }
9058 }
9059
9060 chan = 0; // Find the channel with the widest range - gives most accurate result later
9061 if (DD[4] - DD[1] > DD[3] - DD[0]) chan = 1;
9062 if (DD[5] - DD[2] > DD[chan + 3] - DD[chan]) chan = 2;
9063
9064 if (AA[chan] == BB[chan]) /* if A == B then work GIMP-like way */
9065 {
9066 for (i = 0; i < 3; i++)
9067 {
9068 KK[i] = AA[i] ? 255.0 / AA[i] : 1.0;
9069 KK[i + 3] = AA[i] < 255 ? -255.0 / (255 - AA[i]) : 0.0;
9070 }
9071
9072 for (i = 0; i < j; i++ , alpha++ , img += 3)
9073 {
9074 /* Already semi-opaque so don't touch */
9075 if (*alpha != 255) continue;
9076
9077 /* Evaluate the three possible alphas */
9078 p0 = (AA[0] - img[0]) * (img[0] <= AA[0] ? KK[0] : KK[3]);
9079 p1 = (AA[1] - img[1]) * (img[1] <= AA[1] ? KK[1] : KK[4]);
9080 p2 = (AA[2] - img[2]) * (img[2] <= AA[2] ? KK[2] : KK[5]);
9081 if (p0 < p1) p0 = p1;
9082 if (p0 < p2) p0 = p2;
9083
9084 /* Set alpha */
9085 *alpha = rint(p0);
9086
9087 /* Demultiply image if this is alpha and nonzero */
9088 if (!mode) continue;
9089 dchan = p0 ? 255.0 / p0 : 0.0;
9090 img[0] = rint((img[0] - AA[0]) * dchan) + AA[0];
9091 img[1] = rint((img[1] - AA[1]) * dchan) + AA[1];
9092 img[2] = rint((img[2] - AA[2]) * dchan) + AA[2];
9093 }
9094 }
9095 else /* Limit processing to A->B scale */
9096 {
9097 dchan = 1.0 / (BB[chan] - AA[chan]);
9098 c1 = 1 ^ (chan & 1);
9099 c2 = 2 ^ (chan & 2);
9100 dc1 = BB[c1] - AA[c1];
9101 dc2 = BB[c2] - AA[c2];
9102
9103 for (i = 0; i < j; i++ , alpha++ , img += 3)
9104 {
9105 /* Already semi-opaque so don't touch */
9106 if (*alpha != 255) continue;
9107 /* Ensure pixel lies between A and B for each channel */
9108 if ((img[0] < DD[0]) || (img[0] > DD[3])) continue;
9109 if ((img[1] < DD[1]) || (img[1] > DD[4])) continue;
9110 if ((img[2] < DD[2]) || (img[2] > DD[5])) continue;
9111
9112 p0 = (img[chan] - AA[chan]) * dchan;
9113
9114 /* Check delta for all channels is roughly the same ...
9115 * ... if it isn't, ignore this pixel as its not in A->B scale
9116 */
9117 if (abs(AA[c1] + (int)rint(p0 * dc1) - img[c1]) > 2) continue;
9118 if (abs(AA[c2] + (int)rint(p0 * dc2) - img[c2]) > 2) continue;
9119
9120 /* Pixel is a shade of A/B so set alpha */
9121 *alpha = (int)rint(p0 * 255) ^ 255;
9122
9123 /* Demultiply image if this is alpha */
9124 if (!mode) continue;
9125 img[0] = AA[0];
9126 img[1] = AA[1];
9127 img[2] = AA[2];
9128 }
9129 }
9130
9131 return 0;
9132 }
9133
mem_smudge(int ox,int oy,int nx,int ny)9134 void mem_smudge(int ox, int oy, int nx, int ny)
9135 {
9136 unsigned char mask[256], img[256 * 2 * 3], alf[256 * 2];
9137 unsigned char *src, *dest, *srca = NULL, *dsta = NULL;
9138 int ax, ay, bx, by, w, h;
9139 int xv = nx - ox, yv = ny - oy; // Vector
9140 int i, j, delta, delta1, bpp;
9141 int y0, y1, dy, opw, op2, cpf, mode;
9142
9143
9144 if (tool_opacity < 2) return;
9145
9146 /* Clip source and dest areas to image bounds */
9147 ax = ox - tool_size / 2;
9148 bx = ax + tool_size;
9149 if (ax < 0) ax = 0;
9150 if (ax + xv < 0) ax = -xv;
9151 if (bx > mem_width) bx = mem_width;
9152 if (bx + xv > mem_width) bx = mem_width - xv;
9153 w = bx - ax;
9154
9155 ay = oy - tool_size / 2;
9156 by = ay + tool_size;
9157 if (ay < 0) ay = 0;
9158 if (ay + yv < 0) ay = -yv;
9159 if (by > mem_height) by = mem_height;
9160 if (by + yv > mem_height) by = mem_height - yv;
9161 h = by - ay;
9162
9163 if ((w < 1) || (h < 1)) return;
9164
9165 /* !!! I modified this tool action somewhat - White Jaguar */
9166 mode = smudge_mode && mem_undo_opacity;
9167 if (mode) src = mem_undo_previous(mem_channel);
9168 else src = mem_img[mem_channel];
9169 dest = mem_img[mem_channel];
9170 if ((mem_channel == CHN_IMAGE) && RGBA_mode && mem_img[CHN_ALPHA])
9171 {
9172 if (mode) srca = mem_undo_previous(CHN_ALPHA);
9173 else srca = mem_img[CHN_ALPHA];
9174 dsta = mem_img[CHN_ALPHA];
9175 }
9176 bpp = MEM_BPP;
9177 delta1 = yv * mem_width + xv;
9178 delta = delta1 * bpp;
9179
9180 /* Copy source if destination overwrites it */
9181 cpf = (src == dest) && !yv && (xv > 0) && (w > xv);
9182 /* Set up Y pass to prevent overwriting source */
9183 if ((src == dest) && (yv > 0) && (h > yv))
9184 y0 = ay + h - 1 , y1 = ay - 1 , dy = -1; // Bottom to top
9185 else y0 = ay , y1 = ay + h , dy = 1; // Top to bottom
9186
9187 for (j = y0; j != y1; j += dy) // Blend old area with new area
9188 {
9189 unsigned char *ts, *td, *tsa = NULL, *tda = NULL;
9190 int offs = j * mem_width + ax;
9191
9192 row_protected(ax + xv, j + yv, w, mask);
9193 ts = src + offs * bpp;
9194 td = dest + offs * bpp + delta;
9195 if (cpf)
9196 {
9197 memcpy(img, ts, w * bpp + delta);
9198 ts = img;
9199 }
9200 if (dsta)
9201 {
9202 tsa = srca + offs;
9203 tda = dsta + offs + delta1;
9204 if (cpf)
9205 {
9206 memcpy(alf, tsa, w + delta1);
9207 tsa = alf;
9208 }
9209 }
9210
9211 for (i = 0; i < w; i++ , ts += bpp , td += bpp)
9212 {
9213 int k = mask[i], k0, k1, k2;
9214
9215 opw = (255 - k) * (tool_opacity >> 1);
9216 opw = (opw + (opw >> 8) + 1) >> 8;
9217 if (!opw) continue;
9218 if (tda)
9219 {
9220 int k = tsa[i + delta1];
9221 k = k * 255 + (tsa[i] - k) * opw + 127;
9222 tda[i] = (k + (k >> 8) + 1) >> 8;
9223 if (k && !channel_dis[CHN_ALPHA])
9224 opw = (255 * opw * tsa[i]) / k;
9225 }
9226 op2 = 255 - opw;
9227 k0 = ts[0] * opw + ts[delta] * op2 + 127;
9228 td[0] = (k0 + (k0 >> 8) + 1) >> 8;
9229 if (bpp == 1) continue;
9230 k1 = ts[1] * opw + ts[delta + 1] * op2 + 127;
9231 td[1] = (k1 + (k1 >> 8) + 1) >> 8;
9232 k2 = ts[2] * opw + ts[delta + 2] * op2 + 127;
9233 td[2] = (k2 + (k2 >> 8) + 1) >> 8;
9234 }
9235 }
9236 }
9237
9238 /// GRADIENTS
9239
9240 /* Evaluate channel gradient at coordinate, return opacity
9241 * Coordinate 0 is center of 1st pixel, 1 center of last
9242 * Scale of return values is 0x0000..0xFF00 (NOT 0xFFFF) */
grad_value(int * dest,int slot,double x)9243 int grad_value(int *dest, int slot, double x)
9244 {
9245 int i, k, len, op;
9246 unsigned char *gdata, *gmap;
9247 grad_map *gradmap;
9248 double xx, hsv[6];
9249
9250 /* Gradient slot (first RGB, then 1-bpp channels) */
9251 gradmap = graddata + slot;
9252
9253 /* Get opacity */
9254 gdata = gradmap->op; gmap = gradmap->opmap; len = gradmap->oplen;
9255 xx = (gradmap->orev ? 1.0 - x : x) * (len - 1);
9256 i = xx;
9257 if (i > len - 2) i = len - 2;
9258 k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9259 op = (gdata[i] << 8) + ((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9260 if (!op) return (0); /* Stop if zero opacity */
9261
9262 /* Get channel value */
9263 gdata = gradmap->vs; gmap = gradmap->vsmap; len = gradmap->vslen;
9264 xx = (gradmap->grev ? 1.0 - x : x) * (len - 1);
9265 i = xx;
9266 if (i > len - 2) i = len - 2;
9267 k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9268 if (!slot) /* RGB */
9269 {
9270 unsigned char *gslot = gdata + i * 3;
9271 int j3 = 0;
9272
9273 switch (gmap[i])
9274 {
9275 case GRAD_TYPE_BK_HSV: /* Backward HSV interpolation */
9276 j3 = 3;
9277 case GRAD_TYPE_HSV: /* HSV interpolation */
9278 /* Convert */
9279 rgb2hsv(gslot + 0, hsv + 0);
9280 rgb2hsv(gslot + 3, hsv + 3);
9281 /* Grey has no hue */
9282 if (hsv[1] == 0.0) hsv[0] = hsv[3];
9283 if (hsv[4] == 0.0) hsv[3] = hsv[0];
9284 /* Prevent wraparound */
9285 if (hsv[j3] > hsv[j3 ^ 3]) hsv[j3] -= 6.0;
9286 /* Interpolate */
9287 hsv[0] += (xx - i) * (hsv[3] - hsv[0]);
9288 hsv[1] += (xx - i) * (hsv[4] - hsv[1]);
9289 hsv[2] += (xx - i) * (hsv[5] - hsv[2]);
9290 /* Convert back */
9291 hsv[2] *= 512;
9292 hsv[1] = hsv[2] * (1.0 - hsv[1]);
9293 if (hsv[0] < 0.0) hsv[0] += 6.0;
9294 j3 = hsv[0];
9295 hsv[0] = (hsv[0] - j3) * (hsv[2] - hsv[1]);
9296 if (j3 & 1) { hsv[2] -= hsv[0]; hsv[0] += hsv[2]; }
9297 else hsv[0] += hsv[1];
9298 j3 >>= 1;
9299 dest[j3] = ((int)hsv[2] + 1) >> 1;
9300 dest[MOD3(j3 + 1)] = ((int)hsv[0] + 1) >> 1;
9301 dest[MOD3(j3 + 2)] = ((int)hsv[1] + 1) >> 1;
9302 break;
9303 case GRAD_TYPE_SRGB: /* sRGB interpolation */
9304 dest[0] = ungamma65281(gamma256[gslot[0]] + (xx - i) *
9305 (gamma256[gslot[3]] - gamma256[gslot[0]]));
9306 dest[1] = ungamma65281(gamma256[gslot[1]] + (xx - i) *
9307 (gamma256[gslot[4]] - gamma256[gslot[1]]));
9308 dest[2] = ungamma65281(gamma256[gslot[2]] + (xx - i) *
9309 (gamma256[gslot[5]] - gamma256[gslot[2]]));
9310 break;
9311 default: /* RGB interpolation */
9312 dest[0] = (gslot[0] << 8) +
9313 ((k * (gslot[3] - gslot[0]) + 127) >> 8);
9314 dest[1] = (gslot[1] << 8) +
9315 ((k * (gslot[4] - gslot[1]) + 127) >> 8);
9316 dest[2] = (gslot[2] << 8) +
9317 ((k * (gslot[5] - gslot[2]) + 127) >> 8);
9318 break;
9319 }
9320 }
9321 else if (slot == CHN_IMAGE + 1) /* Indexed */
9322 {
9323 dest[0] = gdata[i];
9324 dest[1] = gdata[i + ((k + 0xFFFF) >> 16)];
9325 dest[CHN_IMAGE + 3] = (k + 127) >> 8;
9326 }
9327 else /* Utility */
9328 {
9329 dest[slot + 2] = (gdata[i] << 8) +
9330 ((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9331 }
9332
9333 return (op);
9334 }
9335
9336 /* Evaluate (coupled) alpha gradient at coordinate */
grad_alpha(int * dest,double x)9337 static void grad_alpha(int *dest, double x)
9338 {
9339 int i, k, len;
9340 unsigned char *gdata, *gmap;
9341 grad_map *gradmap;
9342 double xx;
9343
9344 /* Get coupled alpha */
9345 gradmap = graddata + CHN_ALPHA + 1;
9346 gdata = gradmap->vs; gmap = gradmap->vsmap; len = gradmap->vslen;
9347 xx = (gradmap->grev ? 1.0 - x : x) * (len - 1);
9348 i = xx;
9349 if (i > len - 2) i = len - 2;
9350 k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9351 dest[CHN_ALPHA + 3] = (gdata[i] << 8) +
9352 ((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9353 }
9354
9355 /* Evaluate gradient at a sequence of points */
9356 /* !!! For now, works only in (slower) exact mode */
grad_pixels(int start,int step,int cnt,int x,int y,unsigned char * mask,unsigned char * op0,unsigned char * img0,unsigned char * alpha0)9357 void grad_pixels(int start, int step, int cnt, int x, int y, unsigned char *mask,
9358 unsigned char *op0, unsigned char *img0, unsigned char *alpha0)
9359 {
9360 grad_info *grad = gradient + mem_channel;
9361 unsigned char *dest;
9362 int i, mmask, dither, op, slot, wrk[NUM_CHANNELS + 3];
9363 double dist, len1, l2;
9364
9365
9366 if (!RGBA_mode) alpha0 = NULL;
9367 mmask = IS_INDEXED ? 1 : 255; /* On/off opacity */
9368 slot = mem_channel + ((0x81 + mem_channel + mem_channel - mem_img_bpp) >> 7);
9369
9370 cnt = start + step * cnt; x += start;
9371 for (i = start; i < cnt; op0[i] = op , x += step , i += step)
9372 {
9373 op = 0;
9374 if (mask[i] >= mmask) continue;
9375
9376 /* Disabled because of unusable settings? */
9377 if (grad->wmode == GRAD_MODE_NONE) continue;
9378
9379 /* Distance for gradient mode */
9380 if (grad->status == GRAD_NONE)
9381 {
9382 /* Stroke gradient */
9383 if (grad->wmode != GRAD_MODE_BURST) dist = grad_path +
9384 (x - grad_x0) * grad->xv + (y - grad_y0) * grad->yv;
9385 /* Shapeburst gradient */
9386 else if (!sb_buf2)
9387 {
9388 int n = sb_buf[(y - sb_rect[1]) * sb_rect[2] +
9389 (x - sb_rect[0])] - 1;
9390 if (n < 0) continue;
9391 dist = n;
9392 }
9393 else
9394 {
9395 int n = sb_buf2[(y - sb_rect[1]) * sb_rect[2] +
9396 (x - sb_rect[0])];
9397 if (!n) continue;
9398 dist = sqrt(n) - 1.0;
9399 }
9400 }
9401 else
9402 {
9403 int dx = x - grad->xy[0], dy = y - grad->xy[1];
9404
9405 switch (grad->wmode)
9406 {
9407 default:
9408 case GRAD_MODE_LINEAR: /* Linear/bilinear gradient */
9409 case GRAD_MODE_BILINEAR:
9410 dist = dx * grad->xv + dy * grad->yv;
9411 if (grad->wmode == GRAD_MODE_LINEAR) break;
9412 dist = fabs(dist); /* Bilinear */
9413 break;
9414 case GRAD_MODE_RADIAL: /* Radial gradient */
9415 dist = sqrt(dx * dx + dy * dy);
9416 break;
9417 case GRAD_MODE_SQUARE: /* Square gradient */
9418 /* !!! Here is code duplication with linear/
9419 * bilinear path - but merged paths actually
9420 * LOSE in both time and space, at least
9421 * with GCC - WJ */
9422 dist = fabs(dx * grad->xv + dy * grad->yv) +
9423 fabs(dx * grad->yv - dy * grad->xv);
9424 break;
9425 case GRAD_MODE_ANGULAR: /* Angular/conical gradient */
9426 case GRAD_MODE_CONICAL:
9427 dist = atan360(dx, dy) - grad->wa;
9428 if (dist < 0.0) dist += 360.0;
9429 if (grad->wmode == GRAD_MODE_ANGULAR) break;
9430 if (dist >= 180.0) dist = 360.0 - dist;
9431 break;
9432 }
9433 }
9434 dist -= grad->ofs;
9435
9436 /* Apply repeat mode */
9437 len1 = grad->wrep;
9438 switch (grad->wrmode)
9439 {
9440 case GRAD_BOUND_MIRROR: /* Mirror repeat */
9441 l2 = len1 + len1;
9442 dist -= l2 * (int)(dist * grad->wil2);
9443 if (dist < 0.0) dist += l2;
9444 if (dist > len1) dist = l2 - dist;
9445 break;
9446 case GRAD_BOUND_REPEAT: /* Repeat */
9447 l2 = len1 + 1.0; /* Repeat period is 1 pixel longer */
9448 dist -= l2 * (int)((dist + 0.5) * grad->wil2);
9449 if (dist < -0.5) dist += l2;
9450 break;
9451 case GRAD_BOUND_REP_A: /* Angular repeat */
9452 dist -= len1 * (int)(dist * grad->wil2);
9453 if (dist < 0.0) dist += len1;
9454 break;
9455 case GRAD_BOUND_STOP: /* Nothing is outside bounds */
9456 if ((dist < -0.5) || (dist >= len1 + 0.5)) continue;
9457 break;
9458 case GRAD_BOUND_STOP_A: /* Nothing is outside angle */
9459 if ((dist < 0.0) || (dist > len1)) continue;
9460 break;
9461 case GRAD_BOUND_LEVEL: /* Constant extension */
9462 default:
9463 break;
9464 }
9465
9466 /* Rescale to 0..1, enforce boundaries */
9467 dist = dist <= 0.0 ? 0.0 : dist >= len1 ? 1.0 : dist * grad->wil1;
9468
9469 /* Value from Bayer dither matrix */
9470 dither = BAYER(x, y);
9471
9472 /* Get gradient */
9473 wrk[CHN_IMAGE + 3] = 0;
9474 op = (grad_value(wrk, slot, dist) + dither) >> 8;
9475 if (!op) continue;
9476
9477 if (mem_channel == CHN_IMAGE)
9478 {
9479 if (alpha0)
9480 {
9481 grad_alpha(wrk, dist);
9482 alpha0[i] = (wrk[CHN_ALPHA + 3] + dither) >> 8;
9483 }
9484 if (mem_img_bpp == 3)
9485 {
9486 dest = img0 + i * 3;
9487 dest[0] = (wrk[0] + dither) >> 8;
9488 dest[1] = (wrk[1] + dither) >> 8;
9489 dest[2] = (wrk[2] + dither) >> 8;
9490 }
9491 else
9492 {
9493 img0[i] = (unsigned char)wrk[(wrk[CHN_IMAGE + 3] +
9494 dither) >> 8];
9495 op = 255;
9496 }
9497 }
9498 else img0[i] = (wrk[mem_channel + 3] + dither) >> 8;
9499 }
9500 }
9501
9502 /* Reevaluate gradient placement functions */
grad_update(grad_info * grad)9503 void grad_update(grad_info *grad)
9504 {
9505 double len, len1, l2;
9506 int dx = grad->xy[2] - grad->xy[0], dy = grad->xy[3] - grad->xy[1];
9507
9508 /* Distance for gradient mode */
9509 grad->wmode = grad->gmode;
9510 len = grad->len;
9511 while (1)
9512 {
9513 /* Stroke gradient */
9514 if (grad->status == GRAD_NONE)
9515 {
9516 if (!len) len = grad->rep + grad->ofs;
9517 if (len <= 0.0) grad->wmode = GRAD_MODE_NONE;
9518 break;
9519 }
9520
9521 /* Placement length */
9522 l2 = sqrt(dx * dx + dy * dy);
9523 if (l2 == 0.0)
9524 {
9525 grad->wmode = GRAD_MODE_RADIAL;
9526 break;
9527 }
9528 grad->xv = dx / l2;
9529 grad->yv = dy / l2;
9530 grad->wa = atan360(dx, dy);
9531 if (!len) len = grad->wmode == GRAD_MODE_ANGULAR ? 360.0 :
9532 grad->wmode == GRAD_MODE_CONICAL ? 180.0 : l2;
9533 break;
9534 }
9535
9536 /* Base length (one repeat) */
9537 len1 = grad->rep > 0 ? grad->rep : len - grad->ofs;
9538 if (len1 < 1.0) len1 = 1.0;
9539 grad->wrep = len1;
9540 grad->wil1 = 1.0 / len1;
9541
9542 /* Inverse period */
9543 l2 = 1.0;
9544 grad->wrmode = grad->rmode;
9545 if (grad->rmode == GRAD_BOUND_MIRROR) /* Mirror repeat */
9546 l2 = len1 + len1;
9547 else if (grad->rmode == GRAD_BOUND_REPEAT) /* Repeat */
9548 l2 = len1 + 1.0;
9549 /* Angular distance is in degrees, not pixels */
9550 if ((grad->wmode == GRAD_MODE_ANGULAR) ||
9551 (grad->wmode == GRAD_MODE_CONICAL))
9552 {
9553 if (grad->rmode == GRAD_BOUND_REPEAT)
9554 grad->wrmode = GRAD_BOUND_REP_A , l2 = len1;
9555 else if (grad->rmode == GRAD_BOUND_STOP)
9556 grad->wrmode = GRAD_BOUND_STOP_A;
9557 }
9558 grad->wil2 = 1.0 / l2;
9559 }
9560
9561 static unsigned char grad_def[4 + 8 + NUM_CHANNELS * 4];
9562
9563 /* Setup gradient mapping */
gmap_setup(grad_map * gmap,grad_store gstore,int slot)9564 void gmap_setup(grad_map *gmap, grad_store gstore, int slot)
9565 {
9566 unsigned char *data, *map;
9567
9568 data = grad_def + (slot ? 8 + slot * 4 : 4);
9569 map = grad_def + 10 + slot * 4;
9570 gmap->vslen = 2;
9571 if (gmap->gtype == GRAD_TYPE_CUSTOM)
9572 {
9573 gmap->vs = gstore + GRAD_CUSTOM_DATA(slot);
9574 gmap->vsmap = gstore + GRAD_CUSTOM_DMAP(slot);
9575 if (gmap->cvslen > 1) gmap->vslen = gmap->cvslen;
9576 else
9577 {
9578 memcpy(gmap->vs, data, slot ? 2 : 6);
9579 gmap->vsmap[0] = map[0];
9580 }
9581 }
9582 else
9583 {
9584 gmap->vs = data;
9585 gmap->vsmap = map;
9586 grad_def[10 + slot * 4] = (unsigned char)gmap->gtype;
9587 }
9588
9589 gmap->oplen = 2;
9590 if (gmap->otype == GRAD_TYPE_CUSTOM)
9591 {
9592 gmap->op = gstore + GRAD_CUSTOM_OPAC(slot);
9593 gmap->opmap = gstore + GRAD_CUSTOM_OMAP(slot);
9594 if (gmap->coplen > 1) gmap->oplen = gmap->coplen;
9595 else
9596 {
9597 gmap->op[0] = grad_def[0];
9598 gmap->op[1] = grad_def[1];
9599 gmap->opmap[0] = grad_def[2];
9600 }
9601 }
9602 else
9603 {
9604 gmap->op = grad_def;
9605 gmap->opmap = grad_def + 2;
9606 grad_def[2] = gmap->otype;
9607 }
9608 }
9609
9610 /* Store default gradient */
grad_def_update(int slot)9611 void grad_def_update(int slot)
9612 {
9613 grad_map *gradmap;
9614
9615 /* Gradient slot (first RGB, then 1-bpp channels) */
9616 if (slot < 0) slot = mem_channel + ((0x81 + mem_channel + mem_channel -
9617 mem_img_bpp) >> 7);
9618 gradmap = graddata + slot;
9619
9620 grad_def[0] = tool_opacity;
9621 /* !!! As there's only 1 tool_opacity, use 0 for 2nd point */
9622 grad_def[1] = 0;
9623 grad_def[2] = gradmap->otype;
9624
9625 grad_def[10 + slot * 4] = gradmap->gtype;
9626 if (slot)
9627 {
9628 grad_def[8 + slot * 4] = channel_col_A[slot - 1];
9629 grad_def[9 + slot * 4] = channel_col_B[slot - 1];
9630 grad_def[12] = mem_col_A;
9631 grad_def[13] = mem_col_B;
9632 }
9633 else
9634 {
9635 grad_def[4] = mem_col_A24.red;
9636 grad_def[5] = mem_col_A24.green;
9637 grad_def[6] = mem_col_A24.blue;
9638 grad_def[7] = mem_col_B24.red;
9639 grad_def[8] = mem_col_B24.green;
9640 grad_def[9] = mem_col_B24.blue;
9641 }
9642
9643 gradmap = graddata + CHN_ALPHA + 1;
9644 grad_def[12 + CHN_ALPHA * 4] = channel_col_A[CHN_ALPHA];
9645 grad_def[13 + CHN_ALPHA * 4] = channel_col_B[CHN_ALPHA];
9646 grad_def[14 + CHN_ALPHA * 4] = gradmap->gtype;
9647 }
9648
9649 /* Convert to RGB & blend indexed/indexed+alpha for preview */
blend_indexed(int start,int step,int cnt,unsigned char * rgb,unsigned char * img0,unsigned char * img,unsigned char * alpha0,unsigned char * alpha,int opacity)9650 void blend_indexed(int start, int step, int cnt, unsigned char *rgb,
9651 unsigned char *img0, unsigned char *img,
9652 unsigned char *alpha0, unsigned char *alpha, int opacity)
9653 {
9654 png_color *col, *col0;
9655 int i, j, k, i3;
9656
9657 for (i = start; cnt-- > 0; i += step)
9658 {
9659 j = opacity;
9660 if (alpha)
9661 {
9662 if (alpha[i])
9663 {
9664 if (alpha0[i]) /* Opaque both */
9665 alpha[i] = 255;
9666 else /* Opaque new */
9667 {
9668 alpha[i] = opacity;
9669 j = 255;
9670 }
9671 }
9672 else if (alpha0[i]) /* Opaque old */
9673 {
9674 alpha[i] = opacity ^ 255;
9675 j = 0;
9676 }
9677 else /* Transparent both */
9678 {
9679 alpha[i] = 0;
9680 continue;
9681 }
9682 }
9683 col = mem_pal + img[i];
9684 col0 = mem_pal + img0[i];
9685 i3 = i * 3;
9686 k = col0->red * 255 + j * (col->red - col0->red);
9687 rgb[i3 + 0] = (k + (k >> 8) + 1) >> 8;
9688 k = col0->green * 255 + j * (col->green - col0->green);
9689 rgb[i3 + 1] = (k + (k >> 8) + 1) >> 8;
9690 k = col0->blue * 255 + j * (col->blue - col0->blue);
9691 rgb[i3 + 2] = (k + (k >> 8) + 1) >> 8;
9692 }
9693 }
9694
grad_point(double * xyz,int cspace,int idx)9695 static void grad_point(double *xyz, int cspace, int idx)
9696 {
9697 int wrk[NUM_CHANNELS + 3];
9698
9699 grad_value(wrk, 0, idx * (1.0 / 4096.0));
9700 switch (cspace)
9701 {
9702 default:
9703 case CSPACE_RGB:
9704 xyz[0] = wrk[0] * (1.0 / 256.0);
9705 xyz[1] = wrk[1] * (1.0 / 256.0);
9706 xyz[2] = wrk[2] * (1.0 / 256.0);
9707 break;
9708 case CSPACE_LXN:
9709 case CSPACE_SRGB:
9710 xyz[0] = gamma65281(wrk[0]);
9711 xyz[1] = gamma65281(wrk[1]);
9712 xyz[2] = gamma65281(wrk[2]);
9713 if (cspace == CSPACE_LXN) rgb2LXN(xyz, xyz[0], xyz[1], xyz[2]);
9714 break;
9715 }
9716 }
9717
mem_pick_gradient(unsigned char * buf,int cspace,int mode)9718 int mem_pick_gradient(unsigned char *buf, int cspace, int mode)
9719 {
9720 grad_map oldgr;
9721 double pal[256 * 3], near[256 * 3], dist[256], len[256], lastc[3];
9722 unsigned char *tb = buf;
9723 int i, j, k, l;
9724
9725 /* Set up new RGB gradient */
9726 oldgr = graddata[0];
9727 memset(graddata, 0, sizeof(grad_map));
9728 graddata[0].gtype = mode;
9729 graddata[0].otype = GRAD_TYPE_CONST;
9730 graddata[0].grev = graddata[0].orev = FALSE;
9731 grad_def_update(0);
9732 gmap_setup(graddata, gradbytes, 0);
9733
9734 /* Map palette to colorspace, and init point/distance/position */
9735 grad_point(lastc, cspace, 0);
9736 for (i = 0; i < mem_cols; i++)
9737 {
9738 double *tmp = pal + i * 3;
9739
9740 switch (cspace)
9741 {
9742 default:
9743 case CSPACE_RGB:
9744 tmp[0] = mem_pal[i].red;
9745 tmp[1] = mem_pal[i].green;
9746 tmp[2] = mem_pal[i].blue;
9747 break;
9748 case CSPACE_SRGB:
9749 tmp[0] = gamma256[mem_pal[i].red];
9750 tmp[1] = gamma256[mem_pal[i].green];
9751 tmp[2] = gamma256[mem_pal[i].blue];
9752 break;
9753 case CSPACE_LXN:
9754 get_lxn(tmp, PNG_2_INT(mem_pal[i]));
9755 break;
9756 }
9757 dist[i] = (tmp[0] - lastc[0]) * (tmp[0] - lastc[0]) +
9758 (tmp[1] - lastc[1]) * (tmp[1] - lastc[1]) +
9759 (tmp[2] - lastc[2]) * (tmp[2] - lastc[2]);
9760 memcpy(near + i * 3, lastc, sizeof(lastc));
9761 }
9762 memset(len, 0, sizeof(len));
9763
9764 /* Find nearest point on gradient curve for each palette color */
9765 for (i = 1; i < 4096; i++)
9766 {
9767 double thisc[3], dx, dy, dz, l2;
9768
9769 grad_point(thisc, cspace, i);
9770 dx = thisc[0] - lastc[0];
9771 dy = thisc[1] - lastc[1];
9772 dz = thisc[2] - lastc[2];
9773 l2 = dx * dx + dy * dy + dz * dz;
9774 if (l2 == 0.0) continue;
9775 for (j = 0; j < mem_cols; j++)
9776 {
9777 double a, d, newc[3], *tmp = pal + j * 3;
9778 a = ((tmp[0] - lastc[0]) * dx + (tmp[1] - lastc[1]) * dy +
9779 (tmp[2] - lastc[2]) * dz) / l2;
9780 a = a < 0.0 ? 0.0 : a > 1.0 ? 1.0 : a;
9781 newc[0] = lastc[0] + a * dx;
9782 newc[1] = lastc[1] + a * dy;
9783 newc[2] = lastc[2] + a * dz;
9784 d = (tmp[0] - newc[0]) * (tmp[0] - newc[0]) +
9785 (tmp[1] - newc[1]) * (tmp[1] - newc[1]) +
9786 (tmp[2] - newc[2]) * (tmp[2] - newc[2]);
9787 if (d >= dist[j]) continue;
9788 dist[j] = d; // Distance from the curve
9789 len[j] = a + i; // Position along the curve
9790 memcpy(near + j * 3, newc, sizeof(newc)); // Point
9791 }
9792 memcpy(lastc, thisc, sizeof(thisc));
9793 }
9794
9795 /* Include gradient's second end */
9796 grad_point(lastc, cspace, 4096);
9797 for (i = 0; i < mem_cols; i++)
9798 {
9799 double d, *tmp = pal + i * 3;
9800 d = (tmp[0] - lastc[0]) * (tmp[0] - lastc[0]) +
9801 (tmp[1] - lastc[1]) * (tmp[1] - lastc[1]) +
9802 (tmp[2] - lastc[2]) * (tmp[2] - lastc[2]);
9803 if (d >= dist[i]) continue;
9804 dist[i] = d;
9805 len[i] = 4096.0;
9806 memcpy(near + i * 3, lastc, sizeof(lastc));
9807 }
9808
9809 /* Restore old RGB gradient */
9810 graddata[0] = oldgr;
9811 grad_def_update(-1);
9812 gmap_setup(graddata, gradbytes, 0);
9813
9814 /* Pick colors with *uncontested* nearest points */
9815 scan_duplicates(); // Need to avoid duplicated colors
9816 for (i = 0; i < mem_cols; i++)
9817 {
9818 double d, d0, *tmp, *xyz;
9819
9820 if (pal_dupes[i] != i) continue;
9821 *tb++ = i; // Add to result set by default
9822 d0 = dist[i];
9823 xyz = near + i * 3;
9824 for (j = 0 , tmp = pal; j < mem_cols; j++ , tmp += 3)
9825 {
9826 if (pal_dupes[j] == i) continue;
9827 tmp = pal + j * 3;
9828 d = (tmp[0] - xyz[0]) * (tmp[0] - xyz[0]) +
9829 (tmp[1] - xyz[1]) * (tmp[1] - xyz[1]) +
9830 (tmp[2] - xyz[2]) * (tmp[2] - xyz[2]);
9831 if (d <= d0)
9832 {
9833 tb--; // Fail - remove this color
9834 break;
9835 }
9836 }
9837 }
9838
9839 /* Bubble-sort the result set by position */
9840 l = tb - buf;
9841 for (i = l - 1; i > 0; i--)
9842 for (j = 0; j < i; j++)
9843 {
9844 k = buf[j + 1];
9845 if (len[buf[j]] > len[k])
9846 {
9847 buf[j + 1] = buf[j];
9848 buf[j] = k;
9849 }
9850 }
9851
9852 /* Return number of colors in result set */
9853 return (l);
9854 }
9855
9856 /// SKEW ENGINE
9857
9858 #define FILT_MAX 6 /* Must be no less than largest filter width */
9859
make_skew_filter(double ** filt,int ** dcc,int * fw,int len,double shift,double skew,int type)9860 static void *make_skew_filter(double **filt, int **dcc, int *fw,
9861 int len, double shift, double skew, int type)
9862 {
9863 void *tmp;
9864 double x, y, x0, dy, fw2, sum, A = 0.0, *fdata;
9865 int i, j, k, y0, fwidth = 0, *ofdata;
9866
9867 // Use NN "filter" for integer shifts
9868 if ((fabs(skew - rint(skew)) < 1e-10) &&
9869 (fabs(shift - rint(shift)) < 1e-10)) type = 0;
9870
9871 switch (type)
9872 {
9873 case 0: fwidth = 1; /* Nearest neighbor */
9874 break;
9875 case 1: fwidth = 2; /* Bilinear */
9876 break;
9877 case 2: case 3: case 4: case 5: /* Bicubic, all flavors */
9878 fwidth = 4;
9879 A = Aarray[type - 2];
9880 break;
9881 case 6: fwidth = 6; /* Blackman-Harris windowed sinc */
9882 break;
9883 }
9884
9885 *filt = NULL; *dcc = NULL; *fw = fwidth;
9886 tmp = multialloc(MA_ALIGN_DOUBLE, filt, len * fwidth * sizeof(double),
9887 dcc, len * sizeof(int), NULL);
9888 if (!tmp) return (NULL);
9889 fdata = *filt; ofdata = *dcc;
9890
9891 /* Generate filter */
9892 fw2 = fwidth >> 1;
9893 x0 = 0.5 * (len - 1);
9894 for (i = 0; i < len; i++)
9895 {
9896 /* As mapping is dest-to-src, shifts are negative */
9897 dy = (x0 - i) * skew - shift;
9898 /* Specialcase NN filter, for simplicity */
9899 if (!type)
9900 {
9901 WJ_FLOOR(*ofdata++, dy + 0.5);
9902 *fdata++ = 1.0;
9903 continue;
9904 }
9905 /* Build regular filters*/
9906 dy -= (*ofdata++ = y0 = ceil(dy - fw2)); // Mirrored offset
9907 sum = 0.0;
9908 for (j = 0; j < fwidth; j++ , dy -= 1.0)
9909 {
9910 x = fabs(dy);
9911 y = 0;
9912 switch (type)
9913 {
9914 case 1: /* Bilinear */
9915 y = 1.0 - x;
9916 break;
9917 case 2: case 3: case 4: case 5: /* Bicubic */
9918 if (x < 1.0) y = ((A + 2.0) * x - (A + 3)) * x * x + 1.0;
9919 else y = A * (((x - 5.0) * x + 8.0) * x - 4.0);
9920 break;
9921 case 6: /* Blackman-Harris */
9922 y = BH1(x);
9923 break;
9924 }
9925 sum += (fdata[j] = y);
9926 }
9927 /* Normalization pass */
9928 sum = 1.0 / sum;
9929 for (k = 0; k < fwidth; k++) *fdata++ *= sum;
9930 }
9931 return (tmp);
9932 }
9933
skew_fill_rgba(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)9934 static void skew_fill_rgba(double *buf, double *filler,
9935 unsigned char *src, unsigned char *srca,
9936 int y0, int ow, int xl, int xr, int x0l, int x0r,
9937 int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
9938 {
9939 double *dest, *tmp;
9940 int j, k, l;
9941
9942 /* Initialize dest buffer */
9943 k = x0l < xl ? x0l : xl;
9944 l = (x0r > xr ? x0r : xr) - k - 1;
9945 if (l < 0) return; // Nothing to do
9946 tmp = buf + k * 7;
9947 memcpy(tmp, filler, sizeof(double) * 7);
9948 for (tmp += 7 , l *= 7; l > 0; tmp++ , l--) *tmp = *(tmp - 7);
9949
9950 /* Collect pixels */
9951 dest = buf + xl * 7;
9952 for (j = xl; j < xr; j++ , dest += 7)
9953 {
9954 unsigned char *img, *alpha;
9955 double *filt, acc = 0.0;
9956 int x, y, x1, ofs;
9957
9958 /* Get location */
9959 y = y0 + dyy[j];
9960 x = j + dxx[y];
9961 x1 = x + xfsz;
9962 filt = xfilt - x + y * xfsz;
9963
9964 /* Accumulate empty space */
9965 while (x1 > ow) acc += filt[--x1];
9966 while (x < 0) acc += filt[x++];
9967
9968 /* Setup source & dest */
9969 ofs = y * ow + x;
9970 img = src + ofs * 3;
9971 alpha = srca + ofs;
9972 // !!! Maybe use temp vars for accumulators - but will it make a difference?
9973 dest[0] *= acc;
9974 dest[1] *= acc;
9975 dest[2] *= acc;
9976
9977 /* Accumulate image data */
9978 filt += x;
9979 for (; x < x1; x++ , img += 3)
9980 {
9981 double rr, gg, bb, aa, fv;
9982
9983 fv = *filt++;
9984 if (gcor)
9985 {
9986 rr = gamma256[img[0]] * fv;
9987 gg = gamma256[img[1]] * fv;
9988 bb = gamma256[img[2]] * fv;
9989 }
9990 else
9991 {
9992 rr = img[0] * fv;
9993 gg = img[1] * fv;
9994 bb = img[2] * fv;
9995 }
9996 dest[6] += (aa = *alpha++) * fv;
9997 dest[0] += rr;
9998 dest[1] += gg;
9999 dest[2] += bb;
10000 dest[3] += rr * aa;
10001 dest[4] += gg * aa;
10002 dest[5] += bb * aa;
10003 }
10004 }
10005 }
10006
skew_fill_rgb(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)10007 static void skew_fill_rgb(double *buf, double *filler,
10008 unsigned char *src, unsigned char *srca,
10009 int y0, int ow, int xl, int xr, int x0l, int x0r,
10010 int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
10011 {
10012 double *dest, *tmp;
10013 int j, k, l;
10014
10015 /* Initialize dest buffer */
10016 k = x0l < xl ? x0l : xl;
10017 l = (x0r > xr ? x0r : xr) - k - 1;
10018 if (l < 0) return; // Nothing to do
10019 tmp = buf + k * 3;
10020 memcpy(tmp, filler, sizeof(double) * 3);
10021 for (tmp += 3 , l *= 3; l > 0; tmp++ , l--) *tmp = *(tmp - 3);
10022
10023 /* Collect pixels */
10024 dest = buf + xl * 3;
10025 for (j = xl; j < xr; j++ , dest += 3)
10026 {
10027 unsigned char *img;
10028 double *filt, acc = 0.0;
10029 double rv, gv, bv;
10030 int x, y, x1;
10031
10032 /* Get location */
10033 y = y0 + dyy[j];
10034 x = j + dxx[y];
10035 x1 = x + xfsz;
10036 filt = xfilt - x + y * xfsz;
10037
10038 /* Accumulate empty space */
10039 while (x1 > ow) acc += filt[--x1];
10040 while (x < 0) acc += filt[x++];
10041
10042 /* Setup source & dest */
10043 img = src + (y * ow + x) * 3;
10044 rv = dest[0] * acc;
10045 gv = dest[1] * acc;
10046 bv = dest[2] * acc;
10047
10048 /* Accumulate image data */
10049 filt += x;
10050 for (; x < x1; x++ , img += 3)
10051 {
10052 double fv = *filt++;
10053 if (gcor)
10054 {
10055 rv += gamma256[img[0]] * fv;
10056 gv += gamma256[img[1]] * fv;
10057 bv += gamma256[img[2]] * fv;
10058 }
10059 else
10060 {
10061 rv += img[0] * fv;
10062 gv += img[1] * fv;
10063 bv += img[2] * fv;
10064 }
10065 }
10066 dest[0] = rv;
10067 dest[1] = gv;
10068 dest[2] = bv;
10069 }
10070 }
10071
skew_fill_util(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)10072 static void skew_fill_util(double *buf, double *filler,
10073 unsigned char *src, unsigned char *srca,
10074 int y0, int ow, int xl, int xr, int x0l, int x0r,
10075 int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
10076 {
10077 double *dest;
10078 int j, k, l;
10079
10080 /* Initialize dest buffer */
10081 k = x0l < xl ? x0l : xl;
10082 l = (x0r > xr ? x0r : xr) - k;
10083 if (l <= 0) return; // Nothing to do
10084 memset(buf + k, 0, l * sizeof(double));
10085
10086 /* Collect pixels */
10087 dest = buf + xl * 3;
10088 for (j = xl; j < xr; j++)
10089 {
10090 unsigned char *img;
10091 double *filt, sum;
10092 int x, y, x1;
10093
10094 /* Get location */
10095 y = y0 + dyy[j];
10096 x = j + dxx[y];
10097 x1 = x + xfsz;
10098 filt = xfilt - x + y * xfsz;
10099
10100 /* Skip empty space */
10101 while (x1 > ow) x1--;
10102 while (x < 0) x++;
10103
10104 /* Setup source */
10105 img = src + y * ow + x;
10106
10107 /* Accumulate image data */
10108 filt += x; sum = 0.0;
10109 for (; x < x1; x++) sum += *img++ * *filt++;
10110 *dest++ = sum;
10111 }
10112 }
10113
10114 /* !!! This works, after a fashion - but remains 2.5 times slower than a smooth
10115 * free-rotate if using 6-tap filter, or 1.5 times if using 2-tap one. Which,
10116 * while still being several times faster than anything else, is rather bad
10117 * for a high-quality tool like mtPaint. Needs improvement. - WJ */
mem_skew_filt(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,double xskew,double yskew,int mode,int gcor,int dis_a,int silent)10118 static void mem_skew_filt(chanlist old_img, chanlist new_img, int ow, int oh,
10119 int nw, int nh, double xskew, double yskew, int mode, int gcor,
10120 int dis_a, int silent)
10121 {
10122 void *xmem, *ymem, *tmem;
10123 double *xfilt, *yfilt, *wbuf, *rbuf;
10124 int *dxx, *dyy;
10125 double x0, y0, d, Kh, Kv, XX[4], YY[4], filler[7];
10126 int i, cc, /*fw2, fh2,*/ xfsz, yfsz, wbsz, rgba, step, ny, nr;
10127
10128
10129 /* Create temp data */
10130 step = (rgba = new_img[CHN_ALPHA] && !dis_a) ? 7 : 3;
10131 xmem = make_skew_filter(&xfilt, &dxx, &xfsz, oh, (nw - ow) * 0.5, xskew, mode);
10132 ymem = make_skew_filter(&yfilt, &dyy, &yfsz, nw, (nh - oh) * 0.5, yskew, mode);
10133 // fw2 = xfsz >> 1; fh2 = yfsz >> 1;
10134
10135 wbsz = nw * step;
10136 tmem = multialloc(MA_ALIGN_DOUBLE, &wbuf, wbsz * yfsz * sizeof(double),
10137 &rbuf, wbsz * sizeof(double), NULL);
10138 if (!xmem || !ymem || !tmem) goto fail;
10139 x0 = 0.5 * (nw - 1); y0 = 0.5 * (nh - 1);
10140
10141 /* Calculate clipping parallelogram's corners */
10142 // To avoid corner cases, we add an extra pixel to original dimensions
10143 XX[1] = XX[3] = (XX[0] = XX[2] = 0.5 * (nw - ow) - 1) + ow + 1;
10144 YY[2] = YY[3] = (YY[0] = YY[1] = 0.5 * (nh - oh) - 1) + oh + 1;
10145 for (i = 0; i < 4; i++)
10146 {
10147 XX[i] += (YY[i] - y0) * xskew;
10148 YY[i] += (XX[i] - x0) * yskew;
10149 }
10150 d = 1.0 + xskew * yskew;
10151 Kv = d ? xskew / d : 0.0; // for left & right
10152 Kh = yskew ? 1.0 / yskew : 0.0; // for top & bottom
10153
10154 /* Init filler */
10155 memset(filler, 0, sizeof(filler));
10156 if (gcor)
10157 {
10158 filler[0] = gamma256[mem_col_A24.red];
10159 filler[1] = gamma256[mem_col_A24.green];
10160 filler[2] = gamma256[mem_col_A24.blue];
10161 }
10162 else
10163 {
10164 filler[0] = mem_col_A24.red;
10165 filler[1] = mem_col_A24.green;
10166 filler[2] = mem_col_A24.blue;
10167 }
10168
10169 /* Process image channels */
10170 for (nr = cc = 0; cc < NUM_CHANNELS; cc++) nr += !!new_img[cc];
10171 nr = (nr - rgba) * (nh + yfsz - 1);
10172 for (ny = cc = 0; cc < NUM_CHANNELS; cc++)
10173 {
10174 int ring_l[FILT_MAX], ring_r[FILT_MAX];
10175 int i, idx, bpp = cc == CHN_IMAGE ? step : 1;
10176
10177 if (!new_img[cc]) continue;
10178 /* Alpha already processed for RGBA */
10179 if ((cc == CHN_ALPHA) && rgba) continue;
10180
10181 /* Init border rings to all-filled */
10182 for (i = 0; i < yfsz; i++) ring_l[i] = 0 , ring_r[i] = nw;
10183
10184 /* Row loop */
10185 for (i = 1 - yfsz , idx = 0; i < nh; i++ , ++idx >= yfsz ? idx = 0 : 0)
10186 {
10187 double *filt0, *thatbuf, *thisbuf = wbuf + idx * wbsz;
10188 int j, k, y0, xl, xr, len, ofs, lfx = -xfsz;
10189
10190 if (!silent && ((++ny * 10) % nr >= nr - 10))
10191 progress_update((float)ny / nr);
10192
10193 /* Locate source row */
10194 y0 = i + yfsz - 1; // Effective Y offset
10195
10196 /* !!! A reliable equation for pixel-precise clipping
10197 * of source rows stubbornly refuses to be found, so
10198 * a brute-force approach is used instead - WJ */
10199 xl = 0; xr = nw;
10200 for (; xl < xr; xl++) // Skip empty pixels on the left
10201 {
10202 int j = y0 + dyy[xl];
10203 if ((j < 0) || (j >= oh)) continue;
10204 j = xl + dxx[j];
10205 if ((j <= lfx) || (j >= ow)) continue;
10206 break;
10207 }
10208 for (; xl < xr; xr--) // Same on the right
10209 {
10210 int j = y0 + dyy[xr - 1];
10211 if ((j < 0) || (j >= oh)) continue;
10212 j = xr - 1 + dxx[j];
10213 if ((j <= lfx) || (j >= ow)) continue;
10214 break;
10215 }
10216 if (xl >= xr) xl = xr = ring_r[idx];
10217
10218 /* Read in a new row */
10219 (cc != CHN_IMAGE ? skew_fill_util : rgba ?
10220 skew_fill_rgba : skew_fill_rgb)(thisbuf,
10221 filler, old_img[cc], old_img[CHN_ALPHA],
10222 y0, ow, xl, xr, ring_l[idx], ring_r[idx],
10223 xfsz, xfilt, dxx, dyy, gcor);
10224
10225 if (xl >= xr) xl = nw , xr = 0;
10226 ring_l[idx] = xl;
10227 ring_r[idx] = xr;
10228
10229 if (i < 0) continue; // Initialization phase
10230
10231 /* Clip target row */
10232 if (i <= YY[0]) xl = ceil(XX[0] + (i - YY[0]) * Kh);
10233 else if (i <= YY[2]) xl = ceil(XX[2] + (i - YY[2]) * Kv);
10234 else /* if (i <= YY[3]) */ xl = ceil(XX[2] + (i - YY[2]) * Kh);
10235 if (i <= YY[1]) xr = ceil(XX[1] + (i - YY[1]) * Kh);
10236 else if (i <= YY[3]) xr = ceil(XX[3] + (i - YY[3]) * Kv);
10237 else /* if (i <= YY[2]) */ xr = ceil(XX[3] + (i - YY[3]) * Kh);
10238 if (xl < 0) xl = 0;
10239 if (xr > nw) xr = nw; // Right boundary is exclusive
10240
10241 /* Run vertical filter over the row buffers */
10242 thisbuf = rbuf + xl * bpp;
10243 thatbuf = wbuf + xl * bpp;
10244 len = xr - xl;
10245 if (len <= 0); // Do nothing
10246 else if (yfsz == 1) // Just copy
10247 memcpy(thisbuf, thatbuf, len * bpp * sizeof(double));
10248 else // Apply filter
10249 {
10250 memset(thisbuf, 0, len * bpp * sizeof(double));
10251 filt0 = yfilt + xl * yfsz;
10252 for (j = 0 , k = idx; j < yfsz; j++)
10253 {
10254 double *dsrc, *ddest = thisbuf, *filt = filt0++;
10255 int l = len;
10256
10257 if (++k >= yfsz) k = 0;
10258 dsrc = thatbuf + k * wbsz;
10259 while (l-- > 0)
10260 {
10261 double kk = *filt;
10262 filt += yfsz;
10263 *ddest++ += *dsrc++ * kk;
10264 if (bpp < 3) continue;
10265 *ddest++ += *dsrc++ * kk;
10266 *ddest++ += *dsrc++ * kk;
10267 if (bpp == 3) continue;
10268 *ddest++ += *dsrc++ * kk;
10269 *ddest++ += *dsrc++ * kk;
10270 *ddest++ += *dsrc++ * kk;
10271 *ddest++ += *dsrc++ * kk;
10272 }
10273 }
10274 }
10275
10276 /* Write out results */
10277 ofs = i * nw + xl;
10278 if (cc == CHN_IMAGE) // RGB and RGBA
10279 {
10280 double *dsrc = thisbuf;
10281 unsigned char *dest, *dsta;
10282 int l = len, n = step;
10283
10284 dest = new_img[CHN_IMAGE] + ofs * 3;
10285 dsta = rgba ? new_img[CHN_ALPHA] + ofs : NULL;
10286 while (l-- > 0)
10287 {
10288 double rr, gg, bb, aa;
10289 int a;
10290
10291 if (dsta && (a = rint(aa = dsrc[6]) ,
10292 *dsta++ = a < 0 ? 0 :
10293 a > 0xFF ? 0xFF : a))
10294 {
10295 aa = 1.0 / aa;
10296 rr = dsrc[3] * aa;
10297 gg = dsrc[4] * aa;
10298 bb = dsrc[5] * aa;
10299 }
10300 else
10301 {
10302 rr = dsrc[0];
10303 gg = dsrc[1];
10304 bb = dsrc[2];
10305 }
10306 if (gcor)
10307 {
10308 dest[0] = UNGAMMA256X(rr);
10309 dest[1] = UNGAMMA256X(gg);
10310 dest[2] = UNGAMMA256X(bb);
10311 }
10312 else
10313 {
10314 int r, g, b;
10315 r = rint(rr);
10316 dest[0] = r < 0 ? 0 : r > 0xFF ? 0xFF : r;
10317 g = rint(gg);
10318 dest[1] = g < 0 ? 0 : g > 0xFF ? 0xFF : g;
10319 b = rint(bb);
10320 dest[2] = b < 0 ? 0 : b > 0xFF ? 0xFF : b;
10321 }
10322 dsrc += n; dest += 3;
10323 }
10324 }
10325 else // Utility channel
10326 {
10327 double *dsrc = thisbuf;
10328 unsigned char *dest = new_img[cc] + ofs;
10329 int l = len, n;
10330
10331 while (l-- > 0)
10332 {
10333 n = rint(*dsrc++);
10334 *dest++ = n < 0 ? 0 : n > 0xFF ? 0xFF : n;
10335 }
10336 }
10337 }
10338 }
10339
10340 fail: free(xmem);
10341 free(ymem);
10342 free(tmem);
10343 }
10344
mem_skew_nn(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,int bpp,double xskew,double yskew,int silent)10345 static void mem_skew_nn(chanlist old_img, chanlist new_img, int ow, int oh,
10346 int nw, int nh, int bpp, double xskew, double yskew, int silent)
10347 {
10348 double x0, y0, d, Kh, Kv, XX[4], YY[4];
10349 int i, ny;
10350
10351 /* Calculate clipping parallelogram's corners */
10352 x0 = 0.5 * (nw - 1); y0 = 0.5 * (nh - 1);
10353 XX[1] = XX[3] = (XX[0] = XX[2] = 0.5 * (nw - ow - 1)) + ow;
10354 YY[2] = YY[3] = (YY[0] = YY[1] = 0.5 * (nh - oh - 1)) + oh;
10355 for (i = 0; i < 4; i++)
10356 {
10357 XX[i] += (YY[i] - y0) * xskew;
10358 YY[i] += (XX[i] - x0) * yskew;
10359 }
10360 d = 1.0 + xskew * yskew;
10361 Kv = d ? xskew / d : 0.0; // for left & right
10362 Kh = yskew ? 1.0 / yskew : 0.0; // for top & bottom
10363
10364 /* Process image row by row */
10365 for (ny = 0; ny < nh; ny++)
10366 {
10367 int cc, xl, xr;
10368
10369 if (!silent && ((ny * 10) % nh >= nh - 10))
10370 progress_update((float)ny / nh);
10371
10372 /* Clip row */
10373 if (ny <= YY[0]) xl = ceil(XX[0] + (ny - YY[0]) * Kh);
10374 else if (ny <= YY[2]) xl = ceil(XX[2] + (ny - YY[2]) * Kv);
10375 else /* if (ny <= YY[3]) */ xl = ceil(XX[2] + (ny - YY[2]) * Kh);
10376 if (ny <= YY[1]) xr = ceil(XX[1] + (ny - YY[1]) * Kh);
10377 else if (ny <= YY[3]) xr = ceil(XX[3] + (ny - YY[3]) * Kv);
10378 else /* if (ny <= YY[2]) */ xr = ceil(XX[3] + (ny - YY[3]) * Kh);
10379 if (xl < 0) xl = 0;
10380 if (xr > nw) xr = nw; // Right boundary is exclusive
10381
10382 for (cc = 0; cc < NUM_CHANNELS; cc++)
10383 {
10384 unsigned char *src, *dest;
10385 double x0y, y0y;
10386 int nx, ox, oy;
10387
10388 if (!new_img[cc]) continue;
10389
10390 x0y = 0.5 * (ow - 1) - x0 * d + (y0 - ny) * xskew;
10391 y0y = x0 * yskew - 0.5 * (nh - oh) + ny;
10392
10393 /* RGB nearest neighbour */
10394 if ((cc == CHN_IMAGE) && (bpp == 3))
10395 {
10396 dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
10397 for (nx = xl; nx < xr; nx++ , dest += 3)
10398 {
10399 // !!! Later, try reimplementing these calculations in row-then-column way -
10400 // !!! while less theoretically precise, it might cause less jitter, and better
10401 // !!! match what other skew-transform code does - WJ
10402 WJ_ROUND(ox, x0y + nx * d);
10403 WJ_ROUND(oy, y0y - nx * yskew);
10404 src = old_img[CHN_IMAGE] +
10405 (oy * ow + ox) * 3;
10406 dest[0] = src[0];
10407 dest[1] = src[1];
10408 dest[2] = src[2];
10409 }
10410 }
10411 /* One-bpp nearest neighbour */
10412 else
10413 {
10414 dest = new_img[cc] + ny * nw + xl;
10415 for (nx = xl; nx < xr; nx++)
10416 {
10417 WJ_ROUND(ox, x0y + nx * d);
10418 WJ_ROUND(oy, y0y - nx * yskew);
10419 *dest++ = old_img[cc][oy * ow + ox];
10420 }
10421 }
10422 }
10423 }
10424 }
10425
10426 /* Skew geometry calculation is far nastier than same for rotation, and worse,
10427 * the approaches don't quite match in case of 3-skew rotation - WJ */
mem_skew_geometry(int ow,int oh,double xskew,double yskew,int rotation,int * nw,int * nh)10428 static void mem_skew_geometry(int ow, int oh, double xskew, double yskew,
10429 int rotation, int *nw, int *nh)
10430 {
10431 double nww, nhh, ax, ay;
10432 int dx, dy, dx0, dy0;
10433
10434
10435 /* Select new centering */
10436 dx0 = ow & 1; dy0 = oh & 1;
10437 /* Pure skew */
10438 if (!rotation)
10439 {
10440 /* For certain skew factors, when the other dimension is even,
10441 * rows/columns nearest to axis fit the pixel grid better if
10442 * skew dimension is realigned to offset them half a pixel */
10443 dx = dy0 ? dx0 : dx0 ^ ((int)(fabs(xskew) + 0.5) & 1);
10444 dy = dx ? dy0 : dy0 ^ ((int)(fabs(yskew) + 0.5) & 1);
10445 }
10446 /* Rotation for 45 degrees or less */
10447 else if (fabs(yskew) <= M_SQRT1_2) dx = dx0 , dy = dy0;
10448 /* Rotation for more than 45 degrees */
10449 else
10450 {
10451 // Height gets to be odd - do width realign now
10452 if (dx0) dx = dy0;
10453 // Leave width realign till 3rd pass
10454 else if (dy0) dx = 0;
10455 // Let double realign happen when possible & useful
10456 else dx = (int)(fabs(xskew) + 0.5) & 1;
10457 dy = dx0;
10458 }
10459
10460 /* Calculate theoretical dimensions */
10461 ax = fabs(xskew); ay = fabs(yskew);
10462 nww = ow + oh * ax;
10463 if (xskew * yskew >= 0) nhh = nww * ay + oh;
10464 else if (ax * ay > 1) nhh = nww * ay - oh;
10465 else nhh = (ow - oh * ax) * ay + oh;
10466 /* Convert to actual pixel dimensions */
10467 *nw = 2 * (int)(0.5 * (nww - dx) + PIX_ADD) + dx;
10468 *nh = 2 * (int)(0.5 * (nhh - dy) + PIX_ADD) + dy;
10469 }
10470
10471 // Skew canvas in one or two directions (X then Y)
10472 // !!! Later, extend to handle skew+shift in both directions, too
mem_skew(double xskew,double yskew,int type,int gcor)10473 int mem_skew(double xskew, double yskew, int type, int gcor)
10474 {
10475 chanlist old_img, new_img;
10476 int ow, oh, nw, nh, res, bpp;
10477
10478 ow = mem_width;
10479 oh = mem_height;
10480 bpp = mem_img_bpp;
10481
10482 mem_skew_geometry(ow, oh, xskew, yskew, FALSE, &nw, &nh);
10483
10484 if ((nw > MAX_WIDTH) || (nh > MAX_HEIGHT)) return (-5);
10485
10486 memcpy(old_img, mem_img, sizeof(chanlist));
10487 res = undo_next_core(UC_NOCOPY, nw, nh, bpp, CMASK_ALL);
10488 if (res) return (res); // No undo space
10489 memcpy(new_img, mem_img, sizeof(chanlist));
10490 progress_init(_("Skew"), 0);
10491
10492 mem_clear_img(new_img, nw, nh, bpp);
10493 if (!type || (mem_img_bpp == 1)) mem_skew_nn(old_img, new_img,
10494 ow, oh, nw, nh, bpp, xskew, yskew, FALSE);
10495 else mem_skew_filt(old_img, new_img, ow, oh, nw, nh, xskew, yskew,
10496 type, gcor, channel_dis[CHN_ALPHA], FALSE);
10497
10498 progress_end();
10499
10500 return (0);
10501 }
10502
10503 // Get average of utility channel pixels in an area
average_channel(unsigned char * src,int iw,int * vxy)10504 int average_channel(unsigned char *src, int iw, int *vxy)
10505 {
10506 unsigned char *tmp;
10507 unsigned int nn, wh;
10508 int i, j, x, y, w, h;
10509
10510 w = vxy[2] - (x = vxy[0]);
10511 h = vxy[3] - (y = vxy[1]);
10512 src += y * iw + x;
10513
10514 /* Average area */
10515 for (nn = i = 0; i < h; i++)
10516 {
10517 tmp = src + i * iw;
10518 for (j = w; j--; nn += *tmp++);
10519 }
10520 wh = w * h;
10521 return ((nn + (wh >> 1)) / wh);
10522 }
10523
10524 // Get gamma-corrected average of RGB/RGBA pixels in an area
average_pixels(unsigned char * rgb,unsigned char * alpha,int iw,int * vxy)10525 int average_pixels(unsigned char *rgb, unsigned char *alpha, int iw, int *vxy)
10526 {
10527 unsigned char *tmp, *tma;
10528 double rr, gg, bb, dd;
10529 int i, j, k, x, y, w, h;
10530
10531 w = vxy[2] - (x = vxy[0]);
10532 h = vxy[3] - (y = vxy[1]);
10533 rgb += (y * iw + x) * 3;
10534 if (alpha) alpha += y * iw + x;
10535
10536 /* Average (gamma corrected) area */
10537 rr = gg = bb = dd = 0.0;
10538 for (i = 0; i < h; i++)
10539 {
10540 tmp = rgb + i * iw * 3;
10541 if (alpha)
10542 {
10543 tma = alpha + i * iw;
10544 for (j = 0; j < w; j++ , tmp += 3)
10545 {
10546 dd += k = *tma++;
10547 rr += k * gamma256[tmp[0]];
10548 gg += k * gamma256[tmp[1]];
10549 bb += k * gamma256[tmp[2]];
10550 }
10551 }
10552 else
10553 {
10554 dd += w;
10555 for (j = 0; j < w; j++ , tmp += 3)
10556 {
10557 rr += gamma256[tmp[0]];
10558 gg += gamma256[tmp[1]];
10559 bb += gamma256[tmp[2]];
10560 }
10561 }
10562 }
10563 dd = 1.0 / dd;
10564 rr *= dd; gg *= dd; bb *= dd;
10565 return (RGB_2_INT(UNGAMMA256(rr), UNGAMMA256(gg), UNGAMMA256(bb)));
10566 }
10567
10568 // Convert a row of pixels to any of 3 colorspaces
mem_convert_row(double * dest,unsigned char * src,int l,int cspace)10569 static void mem_convert_row(double *dest, unsigned char *src, int l, int cspace)
10570 {
10571 if (cspace == CSPACE_LXN)
10572 {
10573 while (l-- > 0)
10574 {
10575 get_lxn(dest, MEM_2_INT(src, 0));
10576 dest += 3; src += 3;
10577 }
10578 }
10579 else if (cspace == CSPACE_SRGB)
10580 {
10581 l *= 3;
10582 while (l-- > 0) *dest++ = gamma256[*src++];
10583 }
10584 else /* if (cspace == CSPACE_RGB) */
10585 {
10586 l *= 3;
10587 while (l-- > 0) *dest++ = *src++;
10588 }
10589 }
10590
10591 /// SEGMENTATION
10592
10593 /*
10594 * This code implements a 4-way variation of the segmentation algorithm
10595 * described in:
10596 * Pedro F. Felzenszwalb, "Efficient Graph-Based Image Segmentation"
10597 */
10598
cmp_edge(const void * v1,const void * v2)10599 static int cmp_edge(const void *v1, const void *v2)
10600 {
10601 float f1 = ((seg_edge *)v1)->diff, f2 = ((seg_edge *)v2)->diff;
10602 return (f1 < f2 ? -1 : f1 != f2 ? f1 > f2 :
10603 ((seg_edge *)v1)->which - ((seg_edge *)v2)->which);
10604 }
10605
seg_find(seg_pixel * pix,int n)10606 static inline int seg_find(seg_pixel *pix, int n)
10607 {
10608 unsigned int i, j;
10609
10610 for (i = n; i != (j = pix[i].group); i = j);
10611 return (pix[n].group = i);
10612 }
10613
seg_join(seg_pixel * pix,int a,int b)10614 static inline int seg_join(seg_pixel *pix, int a, int b)
10615 {
10616 seg_pixel *ca = pix + a, *cb = pix + b;
10617
10618 if (ca->rank > cb->rank)
10619 {
10620 ca->cnt += cb->cnt;
10621 return (cb->group = a);
10622 }
10623 cb->cnt += ca->cnt;
10624 cb->rank += (ca->rank == cb->rank);
10625 return (ca->group = b);
10626 }
10627
mem_seg_prepare(seg_state * s,unsigned char * img,int w,int h,int flags,int cspace,int dist)10628 seg_state *mem_seg_prepare(seg_state *s, unsigned char *img, int w, int h,
10629 int flags, int cspace, int dist)
10630 {
10631 static const unsigned char dist_scales[NUM_CSPACES] = { 1, 255, 1 };
10632 seg_edge *e;
10633 double mult, *row0, *row1, *rows[2];
10634 int i, j, k, l, bsz, sz = w * h;
10635
10636
10637 // !!! Will need a longer int type (and twice the memory) otherwise
10638 if (sz > (INT_MAX >> 1) + 1) return (NULL);
10639
10640 /* 3 buffers will be sharing space */
10641 bsz = w * 3 * 2 * sizeof(double);
10642 l = sz * sizeof(seg_pixel);
10643 if (l > bsz) bsz = l;
10644
10645 if (!s) // Reuse existing allocation if possible
10646 { /* Allocation is HUGE, but no way to make do with smaller one - WJ */
10647 void *v[3];
10648
10649 s = multialloc(MA_ALIGN_DOUBLE,
10650 v, sizeof(seg_state), // Dummy pointer (header struct)
10651 v + 1, bsz, // Row buffers/pixel nodes
10652 v + 2, sz * 2 * sizeof(seg_edge), // Pixel connections
10653 NULL);
10654 if (!s) return (NULL);
10655 s->pix = v[1];
10656 s->edges = v[2];
10657 s->w = w;
10658 s->h = h;
10659 }
10660 rows[0] = (void *)s->pix; // 1st row buffer
10661 rows[1] = rows[0] + w * 3; // 2nd row buffer
10662 s->phase = 0; // Struct is to be refilled
10663
10664 if (flags & SEG_PROGRESS) progress_init(_("Segmentation Pass 1"), 1);
10665
10666 /* Compute color distances, fill connections buffer */
10667 l = w * 3;
10668 mult = dist_scales[cspace]; // Make all colorspaces use similar scale
10669 for (i = 0 , e = s->edges; i < h; i++)
10670 {
10671 k = i * w;
10672 mem_convert_row(row1 = rows[i & 1], img + k * 3, w, cspace);
10673 /* Right vertices for this row */
10674 for (j = 3 , k *= 2; j < l; j += 3 , k += 2 , e++)
10675 {
10676 e->which = k;
10677 e->diff = mult * distance_3d[dist](row1 + j - 3, row1 + j);
10678 }
10679 if (!i) continue;
10680 /* Bottom vertices for previous row */
10681 k = (i - 1) * w * 2 + 1;
10682 row0 = rows[~i & 1];
10683 for (j = 0; j < l; j += 3 , k += 2 , e++)
10684 {
10685 e->which = k;
10686 e->diff = mult * distance_3d[dist](row0 + j, row1 + j);
10687 }
10688 if ((flags & SEG_PROGRESS) && ((i * 20) % h >= h - 20))
10689 if (progress_update((0.9 * i) / h)) goto quit;
10690 }
10691
10692 /* Sort connections, smallest distances first */
10693 s->cnt = e - s->edges;
10694 qsort(s->edges, s->cnt, sizeof(seg_edge), cmp_edge);
10695
10696 s->phase = 1;
10697
10698 quit: if (flags & SEG_PROGRESS) progress_end();
10699
10700 return (s);
10701 }
10702
mem_seg_process_chunk(int start,int cnt,seg_state * s)10703 int mem_seg_process_chunk(int start, int cnt, seg_state *s)
10704 {
10705 seg_edge *edge;
10706 seg_pixel *cp, *pix = s->pix;
10707 double threshold = s->threshold;
10708 int minrank = s->minrank, minsize = s->minsize;
10709 int sz = s->w * s->h, w1[2] = { 1, s->w };
10710 int i, ix, pass;
10711
10712 /* Initialize pixel nodes */
10713 if (!start)
10714 {
10715 for (i = 0 , cp = pix; i < sz; i++ , cp++)
10716 {
10717 cp->group = i;
10718 cp->cnt = 1;
10719 cp->rank = 0;
10720 cp->threshold = threshold;
10721 }
10722 }
10723
10724 /* Setup loop range */
10725 pass = start / s->cnt;
10726 i = start % s->cnt;
10727 cnt += i;
10728
10729 for (; pass < 3; pass++)
10730 {
10731 ix = cnt < s->cnt ? cnt : s->cnt;
10732 edge = s->edges + i;
10733 for (; i < ix; i++ , edge++)
10734 {
10735 float dist;
10736 int j, k, idx;
10737
10738 /* Get the original pixel */
10739 dist = edge->diff;
10740 idx = edge->which;
10741 j = idx >> 1;
10742 /* Get the neighboring pixel's index */
10743 k = j + w1[idx & 1];
10744 /* Get segment anchors */
10745 j = seg_find(pix, j);
10746 k = seg_find(pix, k);
10747 if (j == k) continue;
10748 /* Merge segments if difference is small enough in pass 0,
10749 * one of segments is too low rank in pass 1, or is too
10750 * small in pass 2 */
10751 if (!pass ? ((dist <= pix[j].threshold) &&
10752 (dist <= pix[k].threshold)) :
10753 pass == 1 ? ((pix[j].rank < minrank) ||
10754 (pix[k].rank < minrank)) :
10755 ((pix[j].cnt < minsize) || (pix[k].cnt < minsize)))
10756 {
10757 seg_pixel *cp = pix + seg_join(pix, j, k);
10758 cp->threshold = dist + threshold / cp->cnt;
10759 }
10760 }
10761 /* Pass not yet completed - return progress */
10762 if (cnt < s->cnt) return (pass * s->cnt + cnt);
10763 cnt -= s->cnt;
10764 i = 0;
10765 pass += !pass && !minrank; // Maybe skip pass 1
10766 pass += pass && (minsize <= (1 << minrank)); // Maybe skip pass 2
10767 }
10768
10769 /* Normalize groups */
10770 for (i = 0; i < sz; i++) seg_find(pix, i);
10771
10772 /* All done */
10773 s->phase |= 2;
10774 return (s->cnt * 3);
10775 }
10776
mem_seg_process(seg_state * s)10777 int mem_seg_process(seg_state *s)
10778 {
10779 int i, n, cnt = s->cnt * 3;
10780
10781
10782 if (s->w * s->h < 1024 * 1024)
10783 {
10784 /* Run silently */
10785 mem_seg_process_chunk(0, cnt, s);
10786 return (TRUE);
10787 }
10788
10789 /* Show progress */
10790 n = (cnt + 19) / 20;
10791 progress_init(_("Segmentation Pass 2"), 1);
10792 for (i = 0; s->phase < 2; i = mem_seg_process_chunk(i, n, s))
10793 if (progress_update((float)i / cnt)) break;
10794 progress_end();
10795 return (s->phase >= 2);
10796 }
10797
10798 /* This produces for one row 2 difference bits per pixel: left & up; if called
10799 * with segmentation still in progress, will show oversegmentation */
mem_seg_scan(unsigned char * dest,int y,int x,int w,int zoom,const seg_state * s)10800 void mem_seg_scan(unsigned char *dest, int y, int x, int w, int zoom,
10801 const seg_state *s)
10802 {
10803 int i, j, k, l, ofs, dy;
10804 seg_pixel *pix = s->pix;
10805
10806 memset(dest, 0, (w + 3) >> 2);
10807 ofs = (y * s->w + x) * zoom;
10808 dy = y ? s->w * zoom : 0; // No up neighbors for Y=0
10809 j = pix[ofs + (!x - 1) * zoom].group; // No left neighbor for X=0
10810 for (i = 0; i < w; i++ , j = k , ofs += zoom)
10811 {
10812 k = pix[ofs].group , l = pix[ofs - dy].group;
10813 dest[i >> 2] |= ((j != k) * 2 + (k != l)) << ((i + i) & 6);
10814 }
10815 }
10816
10817 /* Draw segments in unique colors */
mem_seg_render(unsigned char * img,const seg_state * s)10818 void mem_seg_render(unsigned char *img, const seg_state *s)
10819 {
10820 int i, k, l, sz = s->w * s->h;
10821 seg_pixel *pix = s->pix;
10822
10823 for (i = l = 0; i < sz; i++)
10824 {
10825 int j, k, r, g, b;
10826
10827 if (pix[i].group != i) continue; // Only new groups
10828 k = l++;
10829 /* Transform index to most distinct RGB color */
10830 for (j = r = g = b = 0; j < 8; j++)
10831 {
10832 r += r + (k & 1); k >>= 1;
10833 g += g + (k & 1); k >>= 1;
10834 b += b + (k & 1); k >>= 1;
10835 }
10836 pix[i].cnt = RGB_2_INT(r, g, b);
10837 }
10838
10839 for (i = 0; i < sz; i++ , img += 3)
10840 {
10841 k = pix[pix[i].group].cnt;
10842 img[0] = INT_2_R(k);
10843 img[1] = INT_2_G(k);
10844 img[2] = INT_2_B(k);
10845 }
10846 }
10847
10848 #define FRACTAL_DIM 1.25
10849 //#define FRACTAL_THR 20 /* dragban2.jpg */
10850 #define FRACTAL_THR 15 /* dragban2.jpg after K-N */
10851 #define THRESHOLD_MULT 20.0
10852
10853 /* Estimate contour length by fractal dimension, use the difference value found
10854 * this way as threshold's base value */
mem_seg_threshold(seg_state * s)10855 double mem_seg_threshold(seg_state *s)
10856 {
10857 int k = s->cnt - FRACTAL_THR * pow(s->cnt, 0.5 * FRACTAL_DIM);
10858 while (!s->edges[k].diff && (k < s->cnt - 1)) k++;
10859 return (s->edges[k].diff ? s->edges[k].diff * THRESHOLD_MULT : 1.0);
10860 }
10861
10862 #undef FRACTAL_DIM
10863 #undef FRACTAL_THR
10864 #undef THRESHOLD_MULT
10865
10866 /// NOISE
10867
10868 /*
10869 * This code implements classical Perlin noise, with the added tweak that nodes
10870 * of every octave are offset against all the others, so that you won't observe
10871 * N successively smaller copies of same thing over one another at the upper left
10872 */
10873
10874 static uint32_t ran_seed[2];
10875
ran_init(uint32_t seed)10876 void ran_init(uint32_t seed)
10877 {
10878 ran_seed[1] = (ran_seed[0] = seed ^ 0xC0FFEE) * 0x10450405 + 1;
10879 }
10880
10881 #define ROL(V,N) (((V) << (N)) | (V) >> (32 - (N)))
10882
10883 /* xoroshiro64** 1.0 PRNG */
ran()10884 uint32_t ran()
10885 {
10886 uint32_t r, s0 = ran_seed[0], s1 = ran_seed[1];
10887
10888 r = s0 * 0x9E3779BB;
10889 r = ROL(r, 5) * 5;
10890 s1 ^= s0;
10891 ran_seed[0] = ROL(s0, 26) ^ s1 ^ (s1 << 9);
10892 ran_seed[1] = ROL(s1, 13);
10893 return (r);
10894 }
10895
10896 static struct {
10897 int xstep, ystep, lvl;
10898 float grad[256 * 2];
10899 unsigned char p[256], map[768];
10900 } perlin_info;
10901
init_perlin(int seed,int xstep,int ystep,int lvl,int maptype)10902 void init_perlin(int seed, int xstep, int ystep, int lvl, int maptype)
10903 {
10904 float *fp = perlin_info.grad;
10905 int i, j;
10906
10907 mem_prepare_map(perlin_info.map, maptype);
10908
10909 perlin_info.xstep = xstep;
10910 perlin_info.ystep = ystep;
10911
10912 /* Limit lvl to max of log2(xstep,ystep) */
10913 i = nlog2(xstep);
10914 j = nlog2(ystep);
10915 if (i < j) i = j;
10916 i += !i; // Allow for useless setup of 1/1
10917 if (lvl > i) lvl = i;
10918 perlin_info.lvl = lvl;
10919
10920 ran_init(seed);
10921
10922 /* Random gradient vectors, equidistributed on unit circle */
10923 for (i = 0; i < 256; i++)
10924 {
10925 double a = (2 * M_PI / 0x1000000) * (int)(ran() >> 8); // 24 random bits
10926 *fp++ = sin(a);
10927 *fp++ = cos(a);
10928 }
10929 /* Permutation table */
10930 for (i = 0; i < 256; i++) perlin_info.p[i] = i;
10931 for (i = 0; i < 255; i++)
10932 {
10933 unsigned char v = perlin_info.p[i];
10934 int n = ran() % (256 - i) + i;
10935 perlin_info.p[i] = perlin_info.p[n];
10936 perlin_info.p[n] = v;
10937 }
10938 }
10939
do_perlin(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,int x,int y)10940 void do_perlin(int start, int step, int cnt, unsigned char *mask,
10941 unsigned char *imgr, int x, int y)
10942 {
10943 double sum, tx, ty, yb, d, dx, dy, sc, wyy[8], ybb[8];
10944 int i, k, lvl, a, b, yp0[8], yp1[8], mstep = step, bpp = MEM_BPP;
10945
10946 /* Y-dependent values stay same for whole row */
10947 dy = 0;
10948 ty = (double)y / perlin_info.ystep;
10949 for (lvl = 0; lvl < perlin_info.lvl; lvl++)
10950 {
10951 yb = ty + dy;
10952 ybb[lvl] = yb -= (b = (int)yb);
10953 wyy[lvl] = ((yb * 6.0 - 15.0) * yb + 10.0) * yb * yb * yb;
10954 k = perlin_info.p[lvl] * lvl;
10955 yp0[lvl] = perlin_info.p[(b + k) & 255];
10956 yp1[lvl] = perlin_info.p[(b + 1 + k) & 255];
10957 ty *= 2;
10958 dy = 0.5; // Dealign levels' anchor grid
10959 }
10960
10961 /* Normalization factor */
10962 i = 1 << perlin_info.lvl;
10963 sc = 255 * i / (M_SQRT2 * 2 * (i - 1));
10964
10965 x += start - step;
10966 start *= bpp; step *= bpp;
10967 imgr += start - step;
10968
10969 while (cnt-- > 0)
10970 {
10971 imgr += step; x += mstep;
10972 if (mask[x] == 255) continue;
10973 sum = dx = 0;
10974 tx = (double)x / perlin_info.xstep;
10975 d = 1;
10976 for (lvl = 0; lvl < perlin_info.lvl; lvl++)
10977 {
10978 float *xp0, *xp1, *xp2, *xp3;
10979 double xa, yb, wx, wy, dd, dd1;
10980
10981 xa = tx + dx;
10982 xa -= (a = (int)xa);
10983 wx = ((xa * 6.0 - 15.0) * xa + 10.0) * xa * xa * xa;
10984 yb = ybb[lvl];
10985 wy = wyy[lvl];
10986 a += perlin_info.p[lvl] * lvl;
10987 b = a + yp0[lvl];
10988 xp0 = perlin_info.grad + perlin_info.p[b & 255] * 2;
10989 dd = xp0[0] * xa + xp0[1] * yb;
10990 xp1 = perlin_info.grad + perlin_info.p[(b + 1) & 255] * 2;
10991 dd += wx * (xp1[0] * (xa - 1) + xp1[1] * yb - dd);
10992 b = a + yp1[lvl];
10993 xp2 = perlin_info.grad + perlin_info.p[b & 255] * 2;
10994 dd1 = xp2[0] * xa + xp2[1] * (yb - 1);
10995 xp3 = perlin_info.grad + perlin_info.p[(b + 1) & 255] * 2;
10996 dd1 += wx * (xp3[0] * (xa - 1) + xp3[1] * (yb - 1) - dd1);
10997 sum += (dd + (dd1 - dd) * wy) * d;
10998 tx += tx;
10999 d *= 0.5;
11000 dx = 0.5; // Dealign levels' anchor grid
11001 }
11002 k = rint(sum * sc + 0.5 * 255.0);
11003 if (bpp == 1) *imgr = k;
11004 else
11005 {
11006 k *= 3;
11007 imgr[0] = perlin_info.map[k + 0];
11008 imgr[1] = perlin_info.map[k + 1];
11009 imgr[2] = perlin_info.map[k + 2];
11010 }
11011 }
11012 }
11013
11014 typedef struct {
11015 unsigned char *buf, *mask;
11016 } noised;
11017
perlin_noise(tcb * thread)11018 static void perlin_noise(tcb *thread)
11019 {
11020 noised *nd = thread->data;
11021 unsigned char *dest, *buf = nd->buf, *mask = nd->mask;
11022 int i, ii, cnt = thread->nsteps, bpp = MEM_BPP;
11023
11024 for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
11025 {
11026 row_protected(0, i, mem_width, mask);
11027 do_perlin(0, 1, mem_width, mask, buf, 0, i);
11028 dest = mem_img[mem_channel] + i * mem_width * bpp;
11029 process_img(0, 1, mem_width, mask, dest, dest, buf,
11030 NULL, bpp, BLENDF_SET | BLENDF_INVM);
11031 if (thread_step(thread, ii + 1, cnt, 10)) break;
11032 }
11033 thread_done(thread);
11034 }
11035
mem_perlin()11036 void mem_perlin()
11037 {
11038 noised nd;
11039 threaddata *tdata;
11040
11041 tdata = talloc(MA_ALIGN_DEFAULT,
11042 image_threads(mem_width, mem_height),
11043 &nd, sizeof(nd),
11044 NULL,
11045 &nd.buf, mem_width * MEM_BPP,
11046 &nd.mask, mem_width,
11047 NULL);
11048 if (!tdata)
11049 {
11050 memory_errors(1);
11051 return;
11052 }
11053 launch_threads(perlin_noise, tdata, _("Solid Noise"), mem_height);
11054 free(tdata);
11055 }
11056