Krita Source Code Documentation
Loading...
Searching...
No Matches
flatten.c
Go to the documentation of this file.
1/* Flattning functions for xcftools
2 *
3 * This file was written by Henning Makholm <henning@makholm.net>
4 * It is hereby in the public domain.
5 *
6 * In jurisdictions that do not recognise grants of copyright to the
7 * public domain: I, the author and (presumably, in those jurisdictions)
8 * copyright holder, hereby permit anyone to distribute and use this code,
9 * in source code or binary form, with or without modifications. This
10 * permission is world-wide and irrevocable.
11 *
12 * Of course, I will not be liable for any errors or shortcomings in the
13 * code, since I give it away without asking any compenstations.
14 *
15 * If you use or distribute this code, I would appreciate receiving
16 * credit for writing it, in whichever way you find proper and customary.
17 */
18
19#include "xcftools.h"
20#include "flatten.h"
21#include "pixels.h"
22#include <string.h>
23#include <stdlib.h>
24#include <assert.h>
25
26static rgba __ATTRIBUTE__((noinline,const))
27composite_one(rgba bot,rgba top)
28{
29 unsigned tfrac, alpha ;
30
31 tfrac = ALPHA(top) ;
32 alpha = 255 ;
33 if( !FULLALPHA(bot) ) {
34 alpha = 255 ^ scaletable[255-ALPHA(bot)][255-ALPHA(top)] ;
35 /* This peculiar combination of ^ and - makes the GCC code
36 * generator for i386 particularly happy.
37 */
38 tfrac = (256*ALPHA(top) - 1) / alpha ;
39 /* Tfrac is the fraction of the coposited pixel's covered area
40 * that comes from the top pixel.
41 * For mathematical accuracy we ought to scale by 255 and
42 * subtract alpha/2, but this is faster, and never misses the
43 * true value by more than one 1/255. This effect is completely
44 * overshadowed by the linear interpolation in the first place.
45 * (I.e. gamma is ignored when combining intensities).
46 * [In any case, complete fairness is not possible: if the
47 * bottom pixel had alpha=170 and the top has alpha=102,
48 * each should contribute equally to the color of the
49 * resulting alpha=204 pixel, which is not possible in general]
50 * Subtracting one helps the topfrac never be 256, which would
51 * be bad.
52 * On the other hand it means that we would get tfrac=-1 if the
53 * top pixel is completely transparent, and we get a division
54 * by zero if _both_ pixels are fully transparent. These cases
55 * must be handled by all callers.
56 * More snooping in the Gimp sources reveal that it uses
57 * floating-point for its equivalent of tfrac when the
58 * bottom layer has an alpha channel. (alphify() macro
59 * in paint-funcs.c). What gives?
60 */
61 }
62 return (alpha << ALPHA_SHIFT)
63 + ((uint32_t)scaletable[ tfrac ][255&(top>>RED_SHIFT )] << RED_SHIFT )
64 + ((uint32_t)scaletable[ tfrac ][255&(top>>GREEN_SHIFT)] << GREEN_SHIFT )
65 + ((uint32_t)scaletable[ tfrac ][255&(top>>BLUE_SHIFT )] << BLUE_SHIFT )
66 + ((uint32_t)scaletable[255^tfrac][255&(bot>>RED_SHIFT )] << RED_SHIFT )
67 + ((uint32_t)scaletable[255^tfrac][255&(bot>>GREEN_SHIFT)] << GREEN_SHIFT )
68 + ((uint32_t)scaletable[255^tfrac][255&(bot>>BLUE_SHIFT )] << BLUE_SHIFT )
69 ;
70}
71
72/* merge_normal() takes ownership of bot.
73 * merge_normal() will share ownership of top.
74 * Return: may be shared.
75 */
76static struct Tile * __ATTRIBUTE__((noinline))
77merge_normal(struct Tile *bot, struct Tile *top)
78{
79 unsigned i ;
81
82 /* See if there is an easy winner */
83 if( (bot->summary & TILESUMMARY_ALLNULL) ||
84 (top->summary & TILESUMMARY_ALLFULL) ) {
85 freeTile(bot);
86 return top ;
87 }
88 if( top->summary & TILESUMMARY_ALLNULL ) {
89 freeTile(top);
90 return bot ;
91 }
92
93 /* Try hard to make top win */
94 for( i=0; ; i++ ) {
95 if( i == top->count ) {
96 freeTile(bot);
97 return top ;
98 }
99 if( !(NULLALPHA(bot->pixels[i]) || FULLALPHA(top->pixels[i])) )
100 break ;
101 }
102
104
105 /* Otherwise bot wins, but is forever changed ... */
106 if( (top->summary & TILESUMMARY_ALLNULL) == 0 ) {
107 unsigned i ;
108 invalidateSummary(bot,0);
109 for( i=0 ; i < top->count ; i++ ) {
110 if( !NULLALPHA(top->pixels[i]) ) {
111 if( FULLALPHA(top->pixels[i]) || NULLALPHA(bot->pixels[i]) )
112 bot->pixels[i] = top->pixels[i] ;
113 else
114 bot->pixels[i] = composite_one(bot->pixels[i],top->pixels[i]);
115 }
116 }
117 }
118 freeTile(top);
119 return bot ;
120}
121
122#define exotic_combinator static inline unsigned __ATTRIBUTE__((const))
123
124
125
127ucombine_ADDITION(uint8_t bot,uint8_t top)
128{
129 return bot+top > 255 ? 255 : bot+top ;
130}
131
133ucombine_SUBTRACT(uint8_t bot,uint8_t top)
134{
135 return top>bot ? 0 : bot-top ;
136}
137
139ucombine_LIGHTEN_ONLY(uint8_t bot,uint8_t top)
140{
141 return top > bot ? top : bot ;
142}
143
145ucombine_DARKEN_ONLY(uint8_t bot,uint8_t top)
146{
147 return top < bot ? top : bot ;
148}
149
151ucombine_DIFFERENCE(uint8_t bot,uint8_t top)
152{
153 return top > bot ? top-bot : bot-top ;
154}
155
157ucombine_MULTIPLY(uint8_t bot,uint8_t top)
158{
159 return scaletable[bot][top] ;
160}
161
163ucombine_DIVIDE(uint8_t bot,uint8_t top)
164{
165 int result = (int)bot*256 / (1+top) ;
166 return result >= 256 ? 255 : result ;
167}
168
170ucombine_SCREEN(uint8_t bot,uint8_t top)
171{
172 /* An inverted version of "multiply" */
173 return 255 ^ scaletable[255-bot][255-top] ;
174}
175
177ucombine_OVERLAY(uint8_t bot,uint8_t top)
178{
179 return scaletable[bot][bot] +
180 2*scaletable[top][scaletable[bot][255-bot]] ;
181 /* This strange formula is equivalent to
182 * (1-top)*(bot^2) + top*(1-(1-top)^2)
183 * that is, the top value is used to interpolate between
184 * the self-multiply and the self-screen of the bottom.
185 */
186 /* Note: This is exactly what the "Soft light" effect also
187 * does, though with different code in the Gimp.
188 */
189}
190
192ucombine_DODGE(uint8_t bot,uint8_t top)
193{
194 return ucombine_DIVIDE(bot,255-top);
195}
196
198ucombine_BURN(uint8_t bot,uint8_t top)
199{
200 return 255 - ucombine_DIVIDE(255-bot,top);
201}
202
204ucombine_HARDLIGHT(uint8_t bot,uint8_t top)
205{
206 if( top >= 128 )
207 return 255 ^ scaletable[255-bot][2*(255-top)] ;
208 else
209 return scaletable[bot][2*top];
210 /* The code that implements "hardlight" in Gimp 2.2.10 has some
211 * rounding errors, but this is undoubtedly what is meant.
212 */
213}
214
216ucombine_GRAIN_EXTRACT(uint8_t bot,uint8_t top)
217{
218 int temp = (int)bot - (int)top + 128 ;
219 return temp < 0 ? 0 : temp >= 256 ? 255 : temp ;
220}
221
223ucombine_GRAIN_MERGE(uint8_t bot,uint8_t top)
224{
225 int temp = (int)bot + (int)top - 128 ;
226 return temp < 0 ? 0 : temp >= 256 ? 255 : temp ;
227}
228
234
235static void
236RGBtoHSV(rgba rgb,struct HSV *hsv)
237{
238 unsigned RED = (uint8_t)(rgb >> RED_SHIFT);
239 unsigned GREEN = (uint8_t)(rgb >> GREEN_SHIFT);
240 unsigned BLUE = (uint8_t)(rgb >> BLUE_SHIFT) ;
241#define HEXTANT(b,m,t) hsv->ch1 = b, hsv->ch2 = m, hsv->ch3 = t, \
242 hsv->hue = HUE_ ## b ## _ ## m ## _ ## t
243 if( GREEN <= RED )
244 if( BLUE <= RED )
245 if( GREEN <= BLUE )
246 HEXTANT(GREEN,BLUE,RED);
247 else
248 HEXTANT(BLUE,GREEN,RED);
249 else
250 HEXTANT(GREEN,RED,BLUE);
251 else if( BLUE <= RED )
252 HEXTANT(BLUE,RED,GREEN);
253 else if( BLUE <= GREEN )
254 HEXTANT(RED,BLUE,GREEN);
255 else
256 HEXTANT(RED,GREEN,BLUE);
257#undef HEXTANT
258}
259
260/* merge_exotic() destructively updates bot.
261 * merge_exotic() reads but does not free top.
262 */
263static int __ATTRIBUTE__((noinline))
264merge_exotic(struct Tile *bot, const struct Tile *top,
266{
267 unsigned i ;
269 if( (bot->summary & TILESUMMARY_ALLNULL) != 0 ) return XCF_OK;
270 if( (top->summary & TILESUMMARY_ALLNULL) != 0 ) return XCF_OK;
271 assert( bot->refcount == 1 );
272 /* The transparency status of bot never changes */
273
275
276 for( i=0; i < top->count ; i++ ) {
277 uint32_t RED, GREEN, BLUE ;
278 if( NULLALPHA(bot->pixels[i]) || NULLALPHA(top->pixels[i]) )
279 continue ;
280#define UNIFORM(mode) case GIMP_ ## mode ## _MODE: \
281 RED = ucombine_ ## mode (bot->pixels[i]>>RED_SHIFT , \
282 top->pixels[i]>>RED_SHIFT ); \
283 GREEN = ucombine_ ## mode (bot->pixels[i]>>GREEN_SHIFT, \
284 top->pixels[i]>>GREEN_SHIFT); \
285 BLUE = ucombine_ ## mode (bot->pixels[i]>>BLUE_SHIFT , \
286 top->pixels[i]>>BLUE_SHIFT ); \
287 break ;
288 switch( mode ) {
289 case GIMP_NORMAL_MODE:
291 {
292 FatalUnexpected("Normal and Dissolve mode can't happen here!");
293 return XCF_ERROR;
294 }
295 UNIFORM(ADDITION);
296 UNIFORM(SUBTRACT);
297 UNIFORM(LIGHTEN_ONLY);
298 UNIFORM(DARKEN_ONLY);
299 UNIFORM(DIFFERENCE);
300 UNIFORM(MULTIPLY);
301 UNIFORM(DIVIDE);
302 UNIFORM(SCREEN);
303 case GIMP_SOFTLIGHT_MODE: /* A synonym for "overlay"! */
304 UNIFORM(OVERLAY);
305 UNIFORM(DODGE);
306 UNIFORM(BURN);
307 UNIFORM(HARDLIGHT);
308 UNIFORM(GRAIN_EXTRACT);
309 UNIFORM(GRAIN_MERGE);
310 case GIMP_HUE_MODE:
312 case GIMP_VALUE_MODE:
313 case GIMP_COLOR_MODE:
314 {
315 static struct HSV hsvTop, hsvBot ;
316 RGBtoHSV(top->pixels[i],&hsvTop);
317 if( mode == GIMP_HUE_MODE && hsvTop.ch1 == hsvTop.ch3 )
318 continue ;
319 RGBtoHSV(bot->pixels[i],&hsvBot);
320 if( mode == GIMP_VALUE_MODE ) {
321 if( hsvBot.ch3 ) {
322 hsvBot.ch1 = (hsvBot.ch1*hsvTop.ch3 + hsvBot.ch3/2) / hsvBot.ch3;
323 hsvBot.ch2 = (hsvBot.ch2*hsvTop.ch3 + hsvBot.ch3/2) / hsvBot.ch3;
324 hsvBot.ch3 = hsvTop.ch3 ;
325 } else {
326 hsvBot.ch1 = hsvBot.ch2 = hsvBot.ch3 = hsvTop.ch3 ;
327 }
328 } else {
329 unsigned mfNum, mfDenom ;
330 if( mode == GIMP_HUE_MODE || mode == GIMP_COLOR_MODE ) {
331 mfNum = hsvTop.ch2-hsvTop.ch1 ;
332 mfDenom = hsvTop.ch3-hsvTop.ch1 ;
333 hsvBot.hue = hsvTop.hue ;
334 } else {
335 mfNum = hsvBot.ch2-hsvBot.ch1 ;
336 mfDenom = hsvBot.ch3-hsvBot.ch1 ;
337 }
338 if( mode == GIMP_SATURATION_MODE ) {
339 if( hsvTop.ch3 == 0 )
340 hsvBot.ch1 = hsvBot.ch3 ; /* Black has no saturation */
341 else
342 hsvBot.ch1 = (hsvTop.ch1*hsvBot.ch3 + hsvTop.ch3/2) / hsvTop.ch3;
343 } else if( mode == GIMP_COLOR_MODE ) {
344 /* GIMP_COLOR_MODE works in HSL space instead of HSV. We must
345 * transfer H and S, keeping the L = ch1+ch3 of the bottom pixel,
346 * but the S we transfer works differently from the S in HSV.
347 */
348 unsigned L = hsvTop.ch1 + hsvTop.ch3 ;
349 unsigned sNum = hsvTop.ch3 - hsvTop.ch1 ;
350 unsigned sDenom = L < 256 ? L : 510-L ;
351 if( sDenom == 0 ) sDenom = 1 ; /* sNum will be 0 */
352 L = hsvBot.ch1 + hsvBot.ch3 ;
353 if( L < 256 ) {
354 /* Ideally we want to compute L/2 * (1-sNum/sDenom)
355 * But shuffle this a bit so we can use integer arithmetic.
356 * The "-1" in the rounding prevents us from ending up with
357 * ch1 > ch3.
358 */
359 hsvBot.ch1 = (L*(sDenom-sNum)+sDenom-1)/(2*sDenom);
360 hsvBot.ch3 = L - hsvBot.ch1 ;
361 } else {
362 /* Here our goal is 255 - (510-L)/2 * (1-sNum/sDenom) */
363 hsvBot.ch3 = 255 - ((510-L)*(sDenom-sNum)+sDenom-1)/(2*sDenom);
364 hsvBot.ch1 = L - hsvBot.ch3 ;
365 }
366 assert(hsvBot.ch3 <= 255);
367 assert(hsvBot.ch3 >= hsvBot.ch1);
368 }
369 if( mfDenom == 0 )
370 hsvBot.ch2 = hsvBot.ch1 ;
371 else
372 hsvBot.ch2 = hsvBot.ch1 +
373 (mfNum*(hsvBot.ch3-hsvBot.ch1) + mfDenom/2) / mfDenom ;
374 }
375 switch( hsvBot.hue ) {
376#define HEXTANT(b,m,t) case HUE_ ## b ## _ ## m ## _ ## t : \
377 b = hsvBot.ch1; m = hsvBot.ch2; t = hsvBot.ch3; break;
378 HEXTANT(RED,GREEN,BLUE);
379 HEXTANT(RED,BLUE,GREEN);
380 HEXTANT(BLUE,RED,GREEN);
381 HEXTANT(BLUE,GREEN,RED);
382 HEXTANT(GREEN,BLUE,RED);
383 HEXTANT(GREEN,RED,BLUE);
384#undef HEXTANT
385 default: {
386
387 FatalUnexpected("Hue hextant is %d", hsvBot.hue);
388 return XCF_ERROR;
389 }
390 }
391 break ;
392 }
393 default:
394 {
395 FatalUnsupportedXCF(_("'%s' layer mode"),
397 return XCF_ERROR;
398 }
399 }
400 if( FULLALPHA(bot->pixels[i] & top->pixels[i]) )
401 bot->pixels[i] = (bot->pixels[i] & (255 << ALPHA_SHIFT)) +
402 (RED << RED_SHIFT) +
403 (GREEN << GREEN_SHIFT) +
404 (BLUE << BLUE_SHIFT) ;
405 else {
406 rgba bp = bot->pixels[i] ;
407 /* In a sane world, the alpha of the top pixel would simply be
408 * used to interpolate linearly between the bottom pixel's base
409 * color and the effect-computed color.
410 * But no! What the Gimp actually does is empirically
411 * described by the following (which borrows code from
412 * composite_one() that makes no theoretical sense here):
413 */
414 unsigned tfrac = ALPHA(top->pixels[i]) ;
415 if( !FULLALPHA(bp) ) {
416 unsigned pseudotop = (tfrac < ALPHA(bp) ? tfrac : ALPHA(bp));
417 unsigned alpha = 255 ^ scaletable[255-ALPHA(bp)][255-pseudotop] ;
418 tfrac = (256*pseudotop - 1) / alpha ;
419 }
420 bot->pixels[i] = (bp & (255 << ALPHA_SHIFT)) +
421 ((rgba)scaletable[ tfrac ][ RED ] << RED_SHIFT ) +
422 ((rgba)scaletable[ tfrac ][ GREEN ] << GREEN_SHIFT) +
423 ((rgba)scaletable[ tfrac ][ BLUE ] << BLUE_SHIFT ) +
424 ((rgba)scaletable[255^tfrac][255&(bp>>RED_SHIFT )] << RED_SHIFT ) +
425 ((rgba)scaletable[255^tfrac][255&(bp>>GREEN_SHIFT)] << GREEN_SHIFT) +
426 ((rgba)scaletable[255^tfrac][255&(bp>>BLUE_SHIFT )] << BLUE_SHIFT ) ;
427 }
428 }
429 return XCF_OK;
430}
431
432static void
433dissolveTile(struct Tile *tile)
434{
435 unsigned i ;
436 summary_t summary ;
437 assert( tile->refcount == 1 );
438 if( (tile->summary & TILESUMMARY_CRISP) )
439 return ;
442 for( i = 0 ; i < tile->count ; i++ ) {
443 if( FULLALPHA(tile->pixels[i]) )
444 summary &= ~TILESUMMARY_ALLNULL ;
445 else if ( NULLALPHA(tile->pixels[i]) )
446 summary &= ~TILESUMMARY_ALLFULL ;
447 else if( ALPHA(tile->pixels[i]) > rand() % 0xFF ) {
448 tile->pixels[i] |= 255 << ALPHA_SHIFT ;
449 summary &= ~TILESUMMARY_ALLNULL ;
450 } else {
451 tile->pixels[i] = 0 ;
452 summary &= ~TILESUMMARY_ALLFULL ;
453 }
454 }
455 tile->summary = summary ;
456}
457
458static void
459roundAlpha(struct Tile *tile)
460{
461 unsigned i ;
462 summary_t summary ;
463 assert( tile->refcount == 1 );
464 if( (tile->summary & TILESUMMARY_CRISP) )
465 return ;
468 for( i = 0 ; i < tile->count ; i++ ) {
469 if( ALPHA(tile->pixels[i]) >= 128 ) {
470 tile->pixels[i] |= 255 << ALPHA_SHIFT ;
471 summary &= ~TILESUMMARY_ALLNULL ;
472 } else {
473 tile->pixels[i] = 0 ;
474 summary &= ~TILESUMMARY_ALLFULL ;
475 }
476 }
477 tile->summary = summary ;
478}
479
480/* flattenTopdown() shares ownership of top.
481 * The return value may be a shared tile.
482 */
483static struct Tile *
484flattenTopdown(struct FlattenSpec *spec, struct Tile *top,
485 unsigned nlayers, const struct rect *where)
486{
487 struct Tile *tile = 0;
488
489 while( nlayers-- ) {
490 if( tileSummary(top) & TILESUMMARY_ALLFULL ) {
491 if (tile) {
492 /* it should always be not null here though */
493 freeTile(tile);
494 }
495 return top ;
496 }
497 if( !spec->layers[nlayers].isVisible )
498 continue ;
499
500 freeTile(tile);
501 tile = getLayerTile(&spec->layers[nlayers],where);
502 if (tile == XCF_PTR_EMPTY) {
503 return XCF_PTR_EMPTY;
504 }
505
506 if( tile->summary & TILESUMMARY_ALLNULL )
507 continue ; /* Simulate a tail call */
508
509 switch( spec->layers[nlayers].mode ) {
511 roundAlpha(tile) ;
512 /* Falls through */
514 dissolveTile(tile);
515 /* Falls through */
516 case GIMP_NORMAL_MODE:
517 top = merge_normal(tile,top);
518 break ;
519 default:
520 {
521 struct Tile *below, *above ;
522 unsigned i ;
523 if( !(top->summary & TILESUMMARY_ALLNULL) ) {
524 rgba tile_or = 0 ;
525 invalidateSummary(tile,0);
526 for( i=0; i<top->count; i++ )
527 if( FULLALPHA(top->pixels[i]) )
528 tile->pixels[i] = 0 ;
529 else
530 tile_or |= tile->pixels[i] ;
531 /* If the tile only has pixels that will be covered by 'top' anyway,
532 * forget it anyway.
533 */
534 if( ALPHA(tile_or) == 0 ) {
535 freeTile(tile);
536 break ; /* from the switch, which will continue the while */
537 }
538 }
539 /* Create a dummy top for the layers below this */
540 if( top->summary & TILESUMMARY_CRISP ) {
541 above = forkTile(top);
542 if(above == XCF_PTR_EMPTY) {
543 freeTile(tile);
544 return XCF_PTR_EMPTY;
545 }
546 } else {
548 above = newTile(*where);
549 for( i=0; i<top->count; i++ )
550 if( FULLALPHA(top->pixels[i]) ) {
551 above->pixels[i] = -1 ;
552 summary = 0 ;
553 } else
554 above->pixels[i] = 0 ;
556 }
557 below = flattenTopdown(spec, above, nlayers, where);
558 if (below == XCF_PTR_EMPTY) {
559 freeTile(tile);
560 return XCF_PTR_EMPTY;
561 }
562 if( below->refcount > 1 ) {
563 if (below != top) {
564 freeTile(tile);
565 return XCF_PTR_EMPTY;
566 }
567 /* This can only happen if 'below' is a copy of 'top'
568 * THROUGH 'above', which in turn means that none of all
569 * this is visible after all. So just free it and return 'top'.
570 */
571 freeTile(below);
572 freeTile(tile);
573 return top ;
574 }
575 if (merge_exotic(below,tile,spec->layers[nlayers].mode) != XCF_OK) {
576 return XCF_PTR_EMPTY;
577 }
578 freeTile(tile);
579 top = merge_normal(below,top);
580 return top ;
581 }
582 }
583 }
584 freeTile(tile);
585 return top ;
586}
587
588static int
589addBackground(struct FlattenSpec *spec, struct Tile *tile, unsigned ncols)
590{
591 unsigned i ;
592
593 if( tileSummary(tile) & TILESUMMARY_ALLFULL )
594 return XCF_OK;
595
596 switch( spec->partial_transparency_mode ) {
597 case FORBID_PARTIAL_TRANSPARENCY:
598 if( !(tileSummary(tile) & TILESUMMARY_CRISP) ) {
599 FatalGeneric(102,_("Flattened image has partially transparent pixels"));
600 return XCF_ERROR;
601 }
602 break ;
603 case DISSOLVE_PARTIAL_TRANSPARENCY:
604 dissolveTile(tile);
605 break ;
606 case ALLOW_PARTIAL_TRANSPARENCY:
607 case PARTIAL_TRANSPARENCY_IMPOSSIBLE:
608 break ;
609 }
610
611 if( spec->default_pixel == CHECKERED_BACKGROUND ) {
613 for( i=0; i<tile->count; i++ )
614 if( !FULLALPHA(tile->pixels[i]) ) {
615 rgba fillwith = ((i/ncols)^(i%ncols))&8 ? 0x66 : 0x99 ;
616 fillwith = graytable[fillwith] + (255 << ALPHA_SHIFT) ;
617 if( NULLALPHA(tile->pixels[i]) )
618 tile->pixels[i] = fillwith ;
619 else
620 tile->pixels[i] = composite_one(fillwith,tile->pixels[i]);
621 }
624 return XCF_OK;
625 }
626 if( !FULLALPHA(spec->default_pixel) ) return XCF_OK;
627 if( tileSummary(tile) & TILESUMMARY_ALLNULL ) {
628 fillTile(tile,spec->default_pixel);
629 } else {
631 for( i=0; i<tile->count; i++ )
632 if( NULLALPHA(tile->pixels[i]) )
633 tile->pixels[i] = spec->default_pixel ;
634 else if( FULLALPHA(tile->pixels[i]) )
635 ;
636 else
637 tile->pixels[i] = composite_one(spec->default_pixel,tile->pixels[i]);
638
641 }
642 return XCF_OK;
643}
644
645int
647{
648 rgba *rows[TILE_HEIGHT] ;
649 unsigned i, y, nrows, ncols ;
650 struct rect where ;
651 struct Tile *tile ;
652 static struct Tile toptile ;
653
654 toptile.count = TILE_HEIGHT * TILE_WIDTH ;
655 fillTile(&toptile,0);
656
657 for( where.t = spec->dim.c.t; where.t < spec->dim.c.b; where.t=where.b ) {
658 where.b = TILE_TOP(where.t)+TILE_HEIGHT ;
659 if( where.b > spec->dim.c.b ) where.b = spec->dim.c.b ;
660 nrows = where.b - where.t ;
661 for( y = 0; y < nrows ; y++ )
662 rows[y] = xcfmalloc(4*(spec->dim.c.r-spec->dim.c.l));
663
664 for( where.l = spec->dim.c.l; where.l < spec->dim.c.r; where.l=where.r ) {
665 where.r = TILE_LEFT(where.l)+TILE_WIDTH ;
666 if( where.r > spec->dim.c.r ) where.r = spec->dim.c.r ;
667 ncols = where.r - where.l ;
668
669 toptile.count = ncols * nrows ;
670 toptile.refcount = 2 ; /* For bug checking */
671 assert( toptile.summary == TILESUMMARY_UPTODATE +
673 tile = flattenTopdown(spec,&toptile,spec->numLayers,&where) ;
674 if (tile == XCF_PTR_EMPTY) {
675 return XCF_ERROR;
676 }
677 toptile.refcount-- ; /* addBackground may change destructively */
678 if (addBackground(spec,tile,ncols) != XCF_OK) {
679 return XCF_ERROR;
680 }
681
682 for( i = 0 ; i < tile->count ; i++ )
683 if( NULLALPHA(tile->pixels[i]) )
684 tile->pixels[i] = 0 ;
685 for( y = 0 ; y < nrows ; y++ )
686 memcpy(rows[y] + (where.l - spec->dim.c.l),
687 tile->pixels + y * ncols, ncols*4);
688
689 if( tile == &toptile ) {
690 fillTile(&toptile,0);
691 } else {
692 freeTile(tile);
693 }
694 }
695 for( y = 0 ; y < nrows ; y++ )
696 callback(spec->dim.width,rows[y]);
697 }
698 return XCF_OK;
699}
700
702
703static void
704collector(unsigned num,rgba *row)
705{
706 (void)num;
707 *collectPointer++ = row ;
708}
709
710rgba **
712{
713 rgba **rows = xcfmalloc(spec->dim.height * sizeof(rgba*));
714 if( verboseFlag )
715 fprintf(stderr,_("Flattening image ..."));
716 collectPointer = rows ;
718 xcffree(rows);
720 return XCF_PTR_EMPTY;
721 }
722 if( verboseFlag )
723 fprintf(stderr,"\n");
724 return rows ;
725}
726
727void
729 lineCallback callback)
730{
731 unsigned i ;
732 for( i = 0; i < spec->dim.height; i++ ) {
733 callback(spec->dim.width,pixels[i]);
734 }
736}
const char * showGimpLayerModeEffects(GimpLayerModeEffects x)
Definition enums.c:6
GimpLayerModeEffects
Definition enums.h:8
@ GIMP_NORMAL_MODE
Definition enums.h:9
@ GIMP_DISSOLVE_MODE
Definition enums.h:10
@ GIMP_VALUE_MODE
Definition enums.h:23
@ GIMP_COLOR_MODE
Definition enums.h:22
@ GIMP_NORMAL_NOPARTIAL_MODE
Definition enums.h:35
@ GIMP_SOFTLIGHT_MODE
Definition enums.h:28
@ GIMP_HUE_MODE
Definition enums.h:20
@ GIMP_SATURATION_MODE
Definition enums.h:21
exotic_combinator ucombine_SCREEN(uint8_t bot, uint8_t top)
Definition flatten.c:170
rgba ** flattenAll(struct FlattenSpec *spec)
Definition flatten.c:711
static struct Tile * flattenTopdown(struct FlattenSpec *spec, struct Tile *top, unsigned nlayers, const struct rect *where)
Definition flatten.c:484
exotic_combinator ucombine_DARKEN_ONLY(uint8_t bot, uint8_t top)
Definition flatten.c:145
exotic_combinator ucombine_GRAIN_EXTRACT(uint8_t bot, uint8_t top)
Definition flatten.c:216
exotic_combinator ucombine_DIFFERENCE(uint8_t bot, uint8_t top)
Definition flatten.c:151
exotic_combinator ucombine_BURN(uint8_t bot, uint8_t top)
Definition flatten.c:198
exotic_combinator ucombine_DODGE(uint8_t bot, uint8_t top)
Definition flatten.c:192
exotic_combinator ucombine_ADDITION(uint8_t bot, uint8_t top)
Definition flatten.c:127
exotic_combinator ucombine_HARDLIGHT(uint8_t bot, uint8_t top)
Definition flatten.c:204
exotic_combinator ucombine_SUBTRACT(uint8_t bot, uint8_t top)
Definition flatten.c:133
int flattenIncrementally(struct FlattenSpec *spec, lineCallback callback)
Definition flatten.c:646
static void dissolveTile(struct Tile *tile)
Definition flatten.c:433
exotic_combinator ucombine_OVERLAY(uint8_t bot, uint8_t top)
Definition flatten.c:177
static void roundAlpha(struct Tile *tile)
Definition flatten.c:459
static rgba ** collectPointer
Definition flatten.c:701
void shipoutWithCallback(struct FlattenSpec *spec, rgba **pixels, lineCallback callback)
Definition flatten.c:728
exotic_combinator ucombine_LIGHTEN_ONLY(uint8_t bot, uint8_t top)
Definition flatten.c:139
exotic_combinator ucombine_GRAIN_MERGE(uint8_t bot, uint8_t top)
Definition flatten.c:223
exotic_combinator ucombine_DIVIDE(uint8_t bot, uint8_t top)
Definition flatten.c:163
#define HEXTANT(b, m, t)
static void RGBtoHSV(rgba rgb, struct HSV *hsv)
Definition flatten.c:236
static int addBackground(struct FlattenSpec *spec, struct Tile *tile, unsigned ncols)
Definition flatten.c:589
static void collector(unsigned num, rgba *row)
Definition flatten.c:704
#define UNIFORM(mode)
#define exotic_combinator
Definition flatten.c:122
exotic_combinator ucombine_MULTIPLY(uint8_t bot, uint8_t top)
Definition flatten.c:157
void(* lineCallback)(unsigned num, rgba *pixels)
Definition flatten.h:72
#define CHECKERED_BACKGROUND
Definition flatten.h:27
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
summary_t tileSummary(struct Tile *tile)
Definition pixels.c:262
struct Tile * getLayerTile(struct xcfLayer *layer, const struct rect *where)
Definition pixels.c:546
void freeTile(struct Tile *tile)
Definition pixels.c:255
void fillTile(struct Tile *tile, rgba data)
Definition pixels.c:283
struct Tile * newTile(struct rect r)
Definition pixels.c:231
struct Tile * forkTile(struct Tile *tile)
Definition pixels.c:244
#define TILESUMMARY_UPTODATE
Definition pixels.h:93
uint32_t rgba
Definition pixels.h:44
#define RED_SHIFT
Definition pixels.h:47
#define ALPHA_SHIFT
Definition pixels.h:46
#define TILESUMMARY_ALLNULL
Definition pixels.h:94
#define FULLALPHA(rgba)
Definition pixels.h:52
#define BLUE_SHIFT
Definition pixels.h:49
int summary_t
Definition pixels.h:89
#define TILESUMMARY_CRISP
Definition pixels.h:96
#define TILESUMMARY_ALLFULL
Definition pixels.h:95
#define GREEN_SHIFT
Definition pixels.h:48
#define ALPHA(rgba)
Definition pixels.h:51
const rgba graytable[256]
Definition table.c:6
#define NULLALPHA(rgba)
Definition pixels.h:53
#define assertTileCompatibility(t1, t2)
Definition pixels.h:110
uint8_t scaletable[256][256]
Definition scaletab.c:22
#define invalidateSummary(tile, mask)
Definition pixels.h:115
#define INIT_SCALETABLE_IF(foo)
Definition pixels.h:63
rgba default_pixel
Definition flatten.h:30
int numLayers
Definition flatten.h:31
struct tileDimensions dim
Definition flatten.h:29
struct xcfLayer * layers
Definition flatten.h:32
enum FlattenSpec::@14 partial_transparency_mode
Definition flatten.c:229
unsigned ch1
Definition flatten.c:232
unsigned ch2
Definition flatten.c:232
@ HUE_RED_GREEN_BLUE
Definition flatten.c:230
@ HUE_RED_BLUE_GREEN
Definition flatten.c:230
@ HUE_BLUE_RED_GREEN
Definition flatten.c:230
@ HUE_GREEN_RED_BLUE
Definition flatten.c:231
@ HUE_BLUE_GREEN_RED
Definition flatten.c:231
@ HUE_GREEN_BLUE_RED
Definition flatten.c:231
enum HSV::@16 hue
unsigned ch3
Definition flatten.c:232
Definition pixels.h:97
rgba pixels[TILE_WIDTH *TILE_HEIGHT]
Definition pixels.h:101
summary_t summary
Definition pixels.h:99
unsigned count
Definition pixels.h:100
refcount_t refcount
Definition pixels.h:98
int l
Definition xcftools.h:130
int r
Definition xcftools.h:130
int t
Definition xcftools.h:130
int b
Definition xcftools.h:130
struct rect c
Definition xcftools.h:166
unsigned height
Definition xcftools.h:167
unsigned width
Definition xcftools.h:167
int isVisible
Definition xcftools.h:186
GimpLayerModeEffects mode
Definition xcftools.h:183
void FatalUnsupportedXCF(const char *format,...)
Definition utils.c:91
void * xcfmalloc(size_t size)
Definition utils.c:114
void xcffree(void *block)
Definition utils.c:125
void FatalGeneric(int status, const char *format,...)
Definition utils.c:46
void FatalUnexpected(const char *format,...)
Definition utils.c:56
int verboseFlag
Definition utils.c:26
#define TILE_LEFT(x)
Definition xcftools.h:161
#define TILE_TOP(y)
Definition xcftools.h:162
#define __ATTRIBUTE__(x)
Definition xcftools.h:55
#define TILE_HEIGHT
Definition xcftools.h:155
#define TILE_WIDTH
Definition xcftools.h:154
#define XCF_OK
Definition xcftools.h:106
#define XCF_ERROR
Definition xcftools.h:105
#define XCF_PTR_EMPTY
Definition xcftools.h:107
#define _(s)
Definition xcftools.h:32