loaders: PNG: Handle gamma on 16bpp conversion
[gfxprim.git] / libs / filters / GP_ResizeCubicFloat.c
blob10820438a3f8f00bc7f454770a94ab9921e65ea8
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <math.h>
24 #include <errno.h>
26 #include "core/GP_Pixmap.h"
27 #include "core/GP_GetPutPixel.h"
28 #include "core/GP_Gamma.h"
30 #include "core/GP_Debug.h"
32 #include "GP_ResizeCubic.h"
34 #define A 0.5
36 static float cubic(float x)
38 if (x < 0)
39 x = -x;
41 if (x < 1)
42 return (2 - A)*x*x*x + (A - 3)*x*x + 1;
44 if (x < 2)
45 return -A*x*x*x + 5*A*x*x - 8*A*x + 4*A;
47 return 0;
50 typedef float v4sf __attribute__ ((vector_size (sizeof(float) * 4)));
52 typedef union v4f {
53 v4sf v;
54 float f[4];
55 } v4f;
57 #define GP_USE_GCC_VECTOR
59 #ifdef GP_USE_GCC_VECTOR
60 #define MUL_V4SF(a, b) ({v4f ret; ret.v = (a).v * (b).v; ret;})
61 #else
62 #define MUL_V4SF(a, b) ({v4f ret; \
63 ret.f[0] = (a).f[0] * (b).f[0]; \
64 ret.f[1] = (a).f[1] * (b).f[1]; \
65 ret.f[2] = (a).f[2] * (b).f[2]; \
66 ret.f[3] = (a).f[3] * (b).f[3]; \
67 ret;})
68 #endif /* GP_USE_GCC_VECTOR */
70 #define SUM_V4SF(a) ((a).f[0] + (a).f[1] + (a).f[2] + (a).f[3])
72 #define CLAMP(val) do { \
73 if (val < 0) \
74 val = 0; \
75 if (val > 255) \
76 val = 255; \
77 } while (0)
79 int GP_FilterResizeCubic(const GP_Pixmap *src, GP_Pixmap *dst,
80 GP_ProgressCallback *callback)
82 float col_r[src->h], col_g[src->h], col_b[src->h];
83 uint32_t i, j;
85 if (src->pixel_type != GP_PIXEL_RGB888 || dst->pixel_type != GP_PIXEL_RGB888) {
86 errno = ENOSYS;
87 return 1;
90 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
91 src->w, src->h, dst->w, dst->h,
92 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
94 for (i = 0; i < dst->w; i++) {
95 float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
96 v4f cvx;
97 int xi[4];
99 xi[0] = floor(x - 1);
100 xi[1] = x;
101 xi[2] = x + 1;
102 xi[3] = x + 2;
104 cvx.f[0] = cubic(xi[0] - x);
105 cvx.f[1] = cubic(xi[1] - x);
106 cvx.f[2] = cubic(xi[2] - x);
107 cvx.f[3] = cubic(xi[3] - x);
109 if (xi[0] < 0)
110 xi[0] = 0;
112 if (xi[2] >= (int)src->w)
113 xi[2] = src->w - 1;
115 if (xi[3] >= (int)src->w)
116 xi[3] = src->w - 1;
118 /* Generate interpolated column */
119 for (j = 0; j < src->h; j++) {
120 v4f rv, gv, bv;
121 GP_Pixel pix[4];
123 pix[0] = GP_GetPixel_Raw_24BPP(src, xi[0], j);
124 pix[1] = GP_GetPixel_Raw_24BPP(src, xi[1], j);
125 pix[2] = GP_GetPixel_Raw_24BPP(src, xi[2], j);
126 pix[3] = GP_GetPixel_Raw_24BPP(src, xi[3], j);
128 rv.f[0] = GP_Pixel_GET_R_RGB888(pix[0]);
129 rv.f[1] = GP_Pixel_GET_R_RGB888(pix[1]);
130 rv.f[2] = GP_Pixel_GET_R_RGB888(pix[2]);
131 rv.f[3] = GP_Pixel_GET_R_RGB888(pix[3]);
133 gv.f[0] = GP_Pixel_GET_G_RGB888(pix[0]);
134 gv.f[1] = GP_Pixel_GET_G_RGB888(pix[1]);
135 gv.f[2] = GP_Pixel_GET_G_RGB888(pix[2]);
136 gv.f[3] = GP_Pixel_GET_G_RGB888(pix[3]);
138 bv.f[0] = GP_Pixel_GET_B_RGB888(pix[0]);
139 bv.f[1] = GP_Pixel_GET_B_RGB888(pix[1]);
140 bv.f[2] = GP_Pixel_GET_B_RGB888(pix[2]);
141 bv.f[3] = GP_Pixel_GET_B_RGB888(pix[3]);
143 rv = MUL_V4SF(rv, cvx);
144 gv = MUL_V4SF(gv, cvx);
145 bv = MUL_V4SF(bv, cvx);
147 col_r[j] = SUM_V4SF(rv);
148 col_g[j] = SUM_V4SF(gv);
149 col_b[j] = SUM_V4SF(bv);
152 /* now interpolate column for new image */
153 for (j = 0; j < dst->h; j++) {
154 float y = (1.00 * j / (dst->h - 1)) * (src->h - 1);
155 v4f cvy, rv, gv, bv;
156 float r, g, b;
157 int yi[4];
159 yi[0] = floor(y - 1);
160 yi[1] = y;
161 yi[2] = y + 1;
162 yi[3] = y + 2;
164 cvy.f[0] = cubic(yi[0] - y);
165 cvy.f[1] = cubic(yi[1] - y);
166 cvy.f[2] = cubic(yi[2] - y);
167 cvy.f[3] = cubic(yi[3] - y);
169 if (yi[0] < 0)
170 yi[0] = 0;
172 if (yi[2] >= (int)src->h)
173 yi[2] = src->h - 1;
175 if (yi[3] >= (int)src->h)
176 yi[3] = src->h - 1;
178 rv.f[0] = col_r[yi[0]];
179 rv.f[1] = col_r[yi[1]];
180 rv.f[2] = col_r[yi[2]];
181 rv.f[3] = col_r[yi[3]];
183 gv.f[0] = col_g[yi[0]];
184 gv.f[1] = col_g[yi[1]];
185 gv.f[2] = col_g[yi[2]];
186 gv.f[3] = col_g[yi[3]];
188 bv.f[0] = col_b[yi[0]];
189 bv.f[1] = col_b[yi[1]];
190 bv.f[2] = col_b[yi[2]];
191 bv.f[3] = col_b[yi[3]];
193 rv = MUL_V4SF(rv, cvy);
194 gv = MUL_V4SF(gv, cvy);
195 bv = MUL_V4SF(bv, cvy);
197 r = SUM_V4SF(rv);
198 g = SUM_V4SF(gv);
199 b = SUM_V4SF(bv);
201 CLAMP(r);
202 CLAMP(g);
203 CLAMP(b);
205 GP_Pixel pix = GP_Pixel_CREATE_RGB888((uint8_t)r, (uint8_t)g, (uint8_t)b);
206 GP_PutPixel_Raw_24BPP(dst, i, j, pix);
209 if (GP_ProgressCallbackReport(callback, i, dst->w, dst->h))
210 return 1;
213 GP_ProgressCallbackDone(callback);
214 return 0;