/* * Copyright (c) 2009 M Joonas Pihlaja * Copyright (c) 2009 Paul-Virak Khuong * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* An unpremultiplier using reciprocal multiplication. It specialises * constant runs and solid runs of pixels with low overhead loops and * uses only a 1KB table of reciprocals. */ #include #include /* Pixel format config for a 32 bit pixel with 8 bit components. Only * the location of alpha matters. */ #ifndef ASHIFT # define ASHIFT 24 #endif #define RSHIFT ((24 + ASHIFT) % 32) #define GSHIFT ((16 + ASHIFT) % 32) #define BSHIFT (( 8 + ASHIFT) % 32) #define AMASK (255U << ASHIFT) #define RMASK (255U << RSHIFT) #define GMASK (255U << GSHIFT) #define BMASK (255U << BSHIFT) /* Set to 1 if the input can have superluminant pixels. */ #define DO_CLAMP_INPUT 0 /* Shift x left by y bits. Supports negative y for right shifts. */ #define SHIFT(x, y) ((y) < 0 ? (x) >> (-(y)) : (x) << (y)) #define ceil_div(a,b) ((a) + (b)-1) / (b) /* The reciprocal_table[i] entries are defined by * * 0 when i = 0 * 255 / i when i > 0 * * represented in fixed point format with RECIPROCAL_BITS of * precision and errors rounded up. */ #define RECIPROCAL_BITS 16 static uint32_t const reciprocal_table[256] = { # define R(i) ((i) ? ceil_div(255*(1<> ASHIFT) & 255; accu += a; r = (rgba >> RSHIFT) & 255; g = (rgba >> GSHIFT) & 255; b = (rgba >> BSHIFT) & 255; recip = reciprocal_table[a]; #if DO_CLAMP_INPUT r = r < a ? r : a; g = g < a ? g : a; b = b < a ? b : a; #endif r = SHIFT(r * recip, RSHIFT - RECIPROCAL_BITS); g = SHIFT(g * recip, GSHIFT - RECIPROCAL_BITS); b = SHIFT(b * recip, BSHIFT - RECIPROCAL_BITS); dst[i] = const_out = (r & RMASK) | (g & GMASK) | (b & BMASK) | (rgba & AMASK); } if (i + 1 == num_pixels) return; { uint32_t rgba, a, r, g, b, recip; rgba = src[i+1]; a = (rgba >> ASHIFT) & 255; accu += a; r = (rgba >> RSHIFT) & 255; g = (rgba >> GSHIFT) & 255; b = (rgba >> BSHIFT) & 255; recip = reciprocal_table[a]; #if DO_CLAMP_INPUT r = r < a ? r : a; g = g < a ? g : a; b = b < a ? b : a; #endif diff = rgba ^ const_in; r = SHIFT(r * recip, RSHIFT - RECIPROCAL_BITS); g = SHIFT(g * recip, GSHIFT - RECIPROCAL_BITS); b = SHIFT(b * recip, BSHIFT - RECIPROCAL_BITS); dst[i+1] = (r & RMASK) | (g & GMASK) | (b & BMASK) | (rgba & AMASK); } i += 2; /* Fall into special cases if we have special * circumstances. */ if (0 != (accu & diff)) continue; if (0 == accu) { /* a run of solid pixels. */ uint32_t in; while (AMASK == ((in = src[i]) & AMASK)) { dst[i++] = in; if (i == num_pixels) return; } } else if (0 == diff) { /* a run of constant pixels. */ while (src[i] == const_in) { dst[i++] = const_out; if (i == num_pixels) return; } } } }