1 /*****************************************************************************
2 * This file is part of gfxprim library. *
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. *
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. *
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 *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 #include "core/GP_Context.h"
26 #include "core/GP_GetPutPixel.h"
27 #include "core/GP_Gamma.h"
29 #include "core/GP_Debug.h"
31 #include "GP_Resize.h"
33 int GP_FilterResizeNN_Raw(const GP_Context
*src
, GP_Context
*dst
,
34 GP_ProgressCallback
*callback
);
36 int GP_FilterResizeNN(const GP_Context
*src
, GP_Context
*dst
,
37 GP_ProgressCallback
*callback
)
39 GP_ASSERT(src
->pixel_type
== dst
->pixel_type
);
41 return GP_FilterResizeNN_Raw(src
, dst
, callback
);
44 GP_Context
*GP_FilterResizeNNAlloc(const GP_Context
*src
,
46 GP_ProgressCallback
*callback
)
48 GP_Context
*res
= GP_ContextAlloc(w
, h
, src
->pixel_type
);
53 if (GP_FilterResizeNN_Raw(src
, res
, callback
)) {
64 static float cubic(float x
)
70 return (2 - A
)*x
*x
*x
+ (A
- 3)*x
*x
+ 1;
73 return -A
*x
*x
*x
+ 5*A
*x
*x
- 8*A
*x
+ 4*A
;
78 typedef float v4sf
__attribute__ ((vector_size (sizeof(float) * 4)));
85 #define GP_USE_GCC_VECTOR
87 #ifdef GP_USE_GCC_VECTOR
88 #define MUL_V4SF(a, b) ({v4f ret; ret.v = (a).v * (b).v; ret;})
90 #define MUL_V4SF(a, b) ({v4f ret; \
91 ret.f[0] = (a).f[0] * (b).f[0]; \
92 ret.f[1] = (a).f[1] * (b).f[1]; \
93 ret.f[2] = (a).f[2] * (b).f[2]; \
94 ret.f[3] = (a).f[3] * (b).f[3]; \
96 #endif /* GP_USE_GCC_VECTOR */
98 #define SUM_V4SF(a) ((a).f[0] + (a).f[1] + (a).f[2] + (a).f[3])
100 #define CLAMP(val) do { \
107 int GP_FilterInterpolate_Cubic(const GP_Context
*src
, GP_Context
*dst
,
108 GP_ProgressCallback
*callback
)
110 float col_r
[src
->h
], col_g
[src
->h
], col_b
[src
->h
];
113 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
114 src
->w
, src
->h
, dst
->w
, dst
->h
,
115 1.00 * dst
->w
/ src
->w
, 1.00 * dst
->h
/ src
->h
);
117 for (i
= 0; i
< dst
->w
; i
++) {
118 float x
= (1.00 * i
/ dst
->w
) * src
->w
;
122 xi
[0] = floor(x
- 1);
127 cvx
.f
[0] = cubic(xi
[0] - x
);
128 cvx
.f
[1] = cubic(xi
[1] - x
);
129 cvx
.f
[2] = cubic(xi
[2] - x
);
130 cvx
.f
[3] = cubic(xi
[3] - x
);
135 if (xi
[2] >= (int)src
->w
)
138 if (xi
[3] >= (int)src
->w
)
141 /* Generate interpolated column */
142 for (j
= 0; j
< src
->h
; j
++) {
146 pix
[0] = GP_GetPixel_Raw_24BPP(src
, xi
[0], j
);
147 pix
[1] = GP_GetPixel_Raw_24BPP(src
, xi
[1], j
);
148 pix
[2] = GP_GetPixel_Raw_24BPP(src
, xi
[2], j
);
149 pix
[3] = GP_GetPixel_Raw_24BPP(src
, xi
[3], j
);
151 rv
.f
[0] = GP_Pixel_GET_R_RGB888(pix
[0]);
152 rv
.f
[1] = GP_Pixel_GET_R_RGB888(pix
[1]);
153 rv
.f
[2] = GP_Pixel_GET_R_RGB888(pix
[2]);
154 rv
.f
[3] = GP_Pixel_GET_R_RGB888(pix
[3]);
156 gv
.f
[0] = GP_Pixel_GET_G_RGB888(pix
[0]);
157 gv
.f
[1] = GP_Pixel_GET_G_RGB888(pix
[1]);
158 gv
.f
[2] = GP_Pixel_GET_G_RGB888(pix
[2]);
159 gv
.f
[3] = GP_Pixel_GET_G_RGB888(pix
[3]);
161 bv
.f
[0] = GP_Pixel_GET_B_RGB888(pix
[0]);
162 bv
.f
[1] = GP_Pixel_GET_B_RGB888(pix
[1]);
163 bv
.f
[2] = GP_Pixel_GET_B_RGB888(pix
[2]);
164 bv
.f
[3] = GP_Pixel_GET_B_RGB888(pix
[3]);
166 rv
= MUL_V4SF(rv
, cvx
);
167 gv
= MUL_V4SF(gv
, cvx
);
168 bv
= MUL_V4SF(bv
, cvx
);
170 col_r
[j
] = SUM_V4SF(rv
);
171 col_g
[j
] = SUM_V4SF(gv
);
172 col_b
[j
] = SUM_V4SF(bv
);
175 /* now interpolate column for new image */
176 for (j
= 0; j
< dst
->h
; j
++) {
177 float y
= (1.00 * j
/ dst
->h
) * src
->h
;
182 yi
[0] = floor(y
- 1);
187 cvy
.f
[0] = cubic(yi
[0] - y
);
188 cvy
.f
[1] = cubic(yi
[1] - y
);
189 cvy
.f
[2] = cubic(yi
[2] - y
);
190 cvy
.f
[3] = cubic(yi
[3] - y
);
195 if (yi
[2] >= (int)src
->h
)
198 if (yi
[3] >= (int)src
->h
)
201 rv
.f
[0] = col_r
[yi
[0]];
202 rv
.f
[1] = col_r
[yi
[1]];
203 rv
.f
[2] = col_r
[yi
[2]];
204 rv
.f
[3] = col_r
[yi
[3]];
206 gv
.f
[0] = col_g
[yi
[0]];
207 gv
.f
[1] = col_g
[yi
[1]];
208 gv
.f
[2] = col_g
[yi
[2]];
209 gv
.f
[3] = col_g
[yi
[3]];
211 bv
.f
[0] = col_b
[yi
[0]];
212 bv
.f
[1] = col_b
[yi
[1]];
213 bv
.f
[2] = col_b
[yi
[2]];
214 bv
.f
[3] = col_b
[yi
[3]];
216 rv
= MUL_V4SF(rv
, cvy
);
217 gv
= MUL_V4SF(gv
, cvy
);
218 bv
= MUL_V4SF(bv
, cvy
);
228 GP_Pixel pix
= GP_Pixel_CREATE_RGB888((uint8_t)r
, (uint8_t)g
, (uint8_t)b
);
229 GP_PutPixel_Raw_24BPP(dst
, i
, j
, pix
);
232 if (GP_ProgressCallbackReport(callback
, i
, dst
->w
, dst
->h
))
236 GP_ProgressCallbackDone(callback
);
242 #define MUL_I(a, b) ({ \
250 ((a)[0] + (a)[1] + (a)[2] + (a)[3])
252 #include "core/GP_GammaCorrection.h"
254 int GP_FilterInterpolate_CubicInt(const GP_Context
*src
, GP_Context
*dst
,
255 GP_ProgressCallback
*callback
)
257 int32_t col_r
[src
->w
], col_g
[src
->w
], col_b
[src
->w
];
260 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
261 src
->w
, src
->h
, dst
->w
, dst
->h
,
262 1.00 * dst
->w
/ src
->w
, 1.00 * dst
->h
/ src
->h
);
264 uint16_t *R_2_LIN
= NULL
;
265 uint16_t *G_2_LIN
= NULL
;
266 uint16_t *B_2_LIN
= NULL
;
268 uint8_t *R_2_GAMMA
= NULL
;
269 uint8_t *G_2_GAMMA
= NULL
;
270 uint8_t *B_2_GAMMA
= NULL
;
273 R_2_LIN
= src
->gamma
->tables
[0]->u16
;
274 G_2_LIN
= src
->gamma
->tables
[1]->u16
;
275 B_2_LIN
= src
->gamma
->tables
[2]->u16
;
277 R_2_GAMMA
= src
->gamma
->tables
[3]->u8
;
278 G_2_GAMMA
= src
->gamma
->tables
[4]->u8
;
279 B_2_GAMMA
= src
->gamma
->tables
[5]->u8
;
282 for (i
= 0; i
< dst
->h
; i
++) {
283 float y
= (1.00 * i
/ dst
->h
) * src
->h
;
287 yi
[0] = floor(y
- 1);
292 cvy
[0] = cubic(yi
[0] - y
) * MUL
+ 0.5;
293 cvy
[1] = cubic(yi
[1] - y
) * MUL
+ 0.5;
294 cvy
[2] = cubic(yi
[2] - y
) * MUL
+ 0.5;
295 cvy
[3] = cubic(yi
[3] - y
) * MUL
+ 0.5;
300 if (yi
[2] >= (int)src
->h
)
303 if (yi
[3] >= (int)src
->h
)
306 /* Generate interpolated row */
307 for (j
= 0; j
< src
->w
; j
++) {
308 int32_t rv
[4], gv
[4], bv
[4];
311 pix
[0] = GP_GetPixel_Raw_24BPP(src
, j
, yi
[0]);
312 pix
[1] = GP_GetPixel_Raw_24BPP(src
, j
, yi
[1]);
313 pix
[2] = GP_GetPixel_Raw_24BPP(src
, j
, yi
[2]);
314 pix
[3] = GP_GetPixel_Raw_24BPP(src
, j
, yi
[3]);
316 rv
[0] = GP_Pixel_GET_R_RGB888(pix
[0]);
317 rv
[1] = GP_Pixel_GET_R_RGB888(pix
[1]);
318 rv
[2] = GP_Pixel_GET_R_RGB888(pix
[2]);
319 rv
[3] = GP_Pixel_GET_R_RGB888(pix
[3]);
321 gv
[0] = GP_Pixel_GET_G_RGB888(pix
[0]);
322 gv
[1] = GP_Pixel_GET_G_RGB888(pix
[1]);
323 gv
[2] = GP_Pixel_GET_G_RGB888(pix
[2]);
324 gv
[3] = GP_Pixel_GET_G_RGB888(pix
[3]);
326 bv
[0] = GP_Pixel_GET_B_RGB888(pix
[0]);
327 bv
[1] = GP_Pixel_GET_B_RGB888(pix
[1]);
328 bv
[2] = GP_Pixel_GET_B_RGB888(pix
[2]);
329 bv
[3] = GP_Pixel_GET_B_RGB888(pix
[3]);
333 rv
[0] = R_2_LIN
[rv
[0]];
334 rv
[1] = R_2_LIN
[rv
[1]];
335 rv
[2] = R_2_LIN
[rv
[2]];
336 rv
[3] = R_2_LIN
[rv
[3]];
338 gv
[0] = G_2_LIN
[gv
[0]];
339 gv
[1] = G_2_LIN
[gv
[1]];
340 gv
[2] = G_2_LIN
[gv
[2]];
341 gv
[3] = G_2_LIN
[gv
[3]];
343 bv
[0] = G_2_LIN
[bv
[0]];
344 bv
[1] = G_2_LIN
[bv
[1]];
345 bv
[2] = G_2_LIN
[bv
[2]];
346 bv
[3] = G_2_LIN
[bv
[3]];
353 col_r
[j
] = SUM_I(rv
);
354 col_g
[j
] = SUM_I(gv
);
355 col_b
[j
] = SUM_I(bv
);
358 /* now interpolate column for new image */
359 for (j
= 0; j
< dst
->w
; j
++) {
360 float x
= (1.00 * j
/ dst
->w
) * src
->w
;
361 int32_t cvx
[4], rv
[4], gv
[4], bv
[4];
365 xi
[0] = floor(x
- 1);
370 cvx
[0] = cubic(xi
[0] - x
) * MUL
+ 0.5;
371 cvx
[1] = cubic(xi
[1] - x
) * MUL
+ 0.5;
372 cvx
[2] = cubic(xi
[2] - x
) * MUL
+ 0.5;
373 cvx
[3] = cubic(xi
[3] - x
) * MUL
+ 0.5;
378 if (xi
[2] >= (int)src
->w
)
381 if (xi
[3] >= (int)src
->w
)
384 rv
[0] = col_r
[xi
[0]];
385 rv
[1] = col_r
[xi
[1]];
386 rv
[2] = col_r
[xi
[2]];
387 rv
[3] = col_r
[xi
[3]];
389 gv
[0] = col_g
[xi
[0]];
390 gv
[1] = col_g
[xi
[1]];
391 gv
[2] = col_g
[xi
[2]];
392 gv
[3] = col_g
[xi
[3]];
394 bv
[0] = col_b
[xi
[0]];
395 bv
[1] = col_b
[xi
[1]];
396 bv
[2] = col_b
[xi
[2]];
397 bv
[3] = col_b
[xi
[3]];
403 r
= (SUM_I(rv
) + MUL
*MUL
/2) / MUL
/ MUL
;
404 g
= (SUM_I(gv
) + MUL
*MUL
/2) / MUL
/ MUL
;
405 b
= (SUM_I(bv
) + MUL
*MUL
/2) / MUL
/ MUL
;
431 GP_Pixel pix
= GP_Pixel_CREATE_RGB888((uint8_t)r
, (uint8_t)g
, (uint8_t)b
);
432 GP_PutPixel_Raw_24BPP(dst
, j
, i
, pix
);
435 if (GP_ProgressCallbackReport(callback
, i
, dst
->h
, dst
->w
))
439 GP_ProgressCallbackDone(callback
);
446 * The x and y are starting coordinates in source image.
448 * The xpix_dist is distance of two sampled pixels in source image coordinates.
450 * The xoff is offset of the first pixel.
452 * The r, g, b are used to store resulting values.
454 static inline void linear_lp_sample_x(const GP_Context
*src
,
455 uint32_t x
, uint32_t y
,
456 uint32_t xpix_dist
, uint32_t xoff
,
457 uint32_t *r
, uint32_t *g
, uint32_t *b
)
462 pix
= GP_GetPixel_Raw_24BPP(src
, x
, y
);
464 *r
= (GP_Pixel_GET_R_RGB888(pix
) * xoff
) >> 9;
465 *g
= (GP_Pixel_GET_G_RGB888(pix
) * xoff
) >> 9;
466 *b
= (GP_Pixel_GET_B_RGB888(pix
) * xoff
) >> 9;
468 for (i
= (1<<14) - xoff
; i
> xpix_dist
; i
-= xpix_dist
) {
472 pix
= GP_GetPixel_Raw_24BPP(src
, x
, y
);
474 *r
+= (GP_Pixel_GET_R_RGB888(pix
) * xpix_dist
) >> 9;
475 *g
+= (GP_Pixel_GET_G_RGB888(pix
) * xpix_dist
) >> 9;
476 *b
+= (GP_Pixel_GET_B_RGB888(pix
) * xpix_dist
) >> 9;
483 pix
= GP_GetPixel_Raw_24BPP(src
, x
, y
);
485 *r
+= (GP_Pixel_GET_R_RGB888(pix
) * i
) >> 9;
486 *g
+= (GP_Pixel_GET_G_RGB888(pix
) * i
) >> 9;
487 *b
+= (GP_Pixel_GET_B_RGB888(pix
) * i
) >> 9;
492 * Linear interpolation with low-pass filtering, used for fast downscaling
495 * Basically we do weighted arithmetic mean of the pixels:
497 * [x, y], [x + 1, y], [x + 2, y] ... [x + k, y]
503 * [x, y + l] .... [x + k, y + l]
506 * The parameter k respectively l is determined by the distance between
507 * sampled coordinates on x respectively y.
509 * The pixels are weighted by how much they are 'hit' by the rectangle defined
510 * by the sampled pixel.
512 * The implementation is inspired by imlib2 downscaling algorithm.
514 static int interpolate_linear_lp_xy(const GP_Context
*src
, GP_Context
*dst
,
515 GP_ProgressCallback
*callback
)
517 uint32_t xmap
[dst
->w
+ 1];
518 uint32_t ymap
[dst
->h
+ 1];
519 uint16_t xoff
[dst
->w
+ 1];
520 uint16_t yoff
[dst
->h
+ 1];
524 /* Pre-compute mapping for interpolation */
525 uint32_t xstep
= (src
->w
<< 16) / dst
->w
;
526 uint32_t xpix_dist
= (dst
->w
<< 14) / src
->w
;
528 for (i
= 0; i
< dst
->w
+ 1; i
++) {
529 uint32_t val
= i
* xstep
;
531 xoff
[i
] = ((255 - ((val
>> 8) & 0xff)) * xpix_dist
)>>8;
534 uint32_t ystep
= (src
->h
<< 16) / dst
->h
;
535 uint32_t ypix_dist
= (dst
->h
<< 14) / src
->h
;
537 for (i
= 0; i
< dst
->h
+ 1; i
++) {
538 uint32_t val
= i
* ystep
;
540 yoff
[i
] = ((255 - ((val
>> 8) & 0xff)) * ypix_dist
)>>8;
544 for (y
= 0; y
< dst
->h
; y
++) {
545 for (x
= 0; x
< dst
->w
; x
++) {
553 linear_lp_sample_x(src
, x0
, y0
,
557 r
= (r
* yoff
[y
]) >> 14;
558 g
= (g
* yoff
[y
]) >> 14;
559 b
= (b
* yoff
[y
]) >> 14;
561 for (j
= (1<<14) - yoff
[y
]; j
> ypix_dist
; j
-= ypix_dist
) {
568 linear_lp_sample_x(src
, x0
, y0
,
572 r
+= (r1
* ypix_dist
) >> 14;
573 g
+= (g1
* ypix_dist
) >> 14;
574 b
+= (b1
* ypix_dist
) >> 14;
583 linear_lp_sample_x(src
, x0
, y0
,
596 GP_PutPixel_Raw_24BPP(dst
, x
, y
,
597 GP_Pixel_CREATE_RGB888(r
, g
, b
));
600 if (GP_ProgressCallbackReport(callback
, y
, dst
->h
, dst
->w
))
604 GP_ProgressCallbackDone(callback
);
608 int GP_FilterInterpolate_LinearInt(const GP_Context
*src
, GP_Context
*dst
,
609 GP_ProgressCallback
*callback
)
611 uint32_t xmap
[dst
->w
+ 1];
612 uint32_t ymap
[dst
->h
+ 1];
613 uint8_t xoff
[dst
->w
+ 1];
614 uint8_t yoff
[dst
->h
+ 1];
617 GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
618 src
->w
, src
->h
, dst
->w
, dst
->h
,
619 1.00 * dst
->w
/ src
->w
, 1.00 * dst
->h
/ src
->h
);
621 /* Pre-compute mapping for interpolation */
622 uint32_t xstep
= (src
->w
<< 16) / dst
->w
;
624 for (i
= 0; i
< dst
->w
+ 1; i
++) {
625 uint32_t val
= i
* xstep
;
627 xoff
[i
] = (val
>> 8) & 0xff;
630 uint32_t ystep
= (src
->h
<< 16) / dst
->h
;
632 for (i
= 0; i
< dst
->h
+ 1; i
++) {
633 uint32_t val
= i
* ystep
;
635 yoff
[i
] = (val
>> 8) & 0xff;
639 for (y
= 0; y
< dst
->h
; y
++) {
640 for (x
= 0; x
< dst
->w
; x
++) {
641 GP_Pixel pix00
, pix01
, pix10
, pix11
;
642 uint32_t r0
, r1
, g0
, g1
, b0
, b1
;
643 GP_Coord x0
, x1
, y0
, y1
;
648 if (x1
>= (GP_Coord
)src
->w
)
654 if (y1
>= (GP_Coord
)src
->h
)
657 pix00
= GP_GetPixel_Raw_24BPP(src
, x0
, y0
);
658 pix10
= GP_GetPixel_Raw_24BPP(src
, x1
, y0
);
659 pix01
= GP_GetPixel_Raw_24BPP(src
, x0
, y1
);
660 pix11
= GP_GetPixel_Raw_24BPP(src
, x1
, y1
);
662 r0
= GP_Pixel_GET_R_RGB888(pix00
) * (255 - xoff
[x
]);
663 g0
= GP_Pixel_GET_G_RGB888(pix00
) * (255 - xoff
[x
]);
664 b0
= GP_Pixel_GET_B_RGB888(pix00
) * (255 - xoff
[x
]);
666 r0
+= GP_Pixel_GET_R_RGB888(pix10
) * xoff
[x
];
667 g0
+= GP_Pixel_GET_G_RGB888(pix10
) * xoff
[x
];
668 b0
+= GP_Pixel_GET_B_RGB888(pix10
) * xoff
[x
];
670 r1
= GP_Pixel_GET_R_RGB888(pix01
) * (255 - xoff
[x
]);
671 g1
= GP_Pixel_GET_G_RGB888(pix01
) * (255 - xoff
[x
]);
672 b1
= GP_Pixel_GET_B_RGB888(pix01
) * (255 - xoff
[x
]);
674 r1
+= GP_Pixel_GET_R_RGB888(pix11
) * xoff
[x
];
675 g1
+= GP_Pixel_GET_G_RGB888(pix11
) * xoff
[x
];
676 b1
+= GP_Pixel_GET_B_RGB888(pix11
) * xoff
[x
];
678 r0
= (r1
* yoff
[y
] + r0
* (255 - yoff
[y
]) + (1<<15)) >> 16;
679 g0
= (g1
* yoff
[y
] + g0
* (255 - yoff
[y
]) + (1<<15)) >> 16;
680 b0
= (b1
* yoff
[y
] + b0
* (255 - yoff
[y
]) + (1<<15)) >> 16;
682 GP_PutPixel_Raw_24BPP(dst
, x
, y
,
683 GP_Pixel_CREATE_RGB888(r0
, g0
, b0
));
686 if (GP_ProgressCallbackReport(callback
, y
, dst
->h
, dst
->w
))
690 GP_ProgressCallbackDone(callback
);
694 int GP_FilterInterpolate_LinearLFInt(const GP_Context
*src
, GP_Context
*dst
,
695 GP_ProgressCallback
*callback
)
697 float x_rat
= 1.00 * dst
->w
/ src
->w
;
698 float y_rat
= 1.00 * dst
->h
/ src
->h
;
700 if (x_rat
< 1.00 && y_rat
< 1.00) {
701 GP_DEBUG(1, "Downscaling image %ux%u -> %ux%u %2.2f %2.2f",
702 src
->w
, src
->h
, dst
->w
, dst
->h
, x_rat
, y_rat
);
703 return interpolate_linear_lp_xy(src
, dst
, callback
);
706 //TODO: x_rat > 1.00 && y_rat < 1.00
707 //TODO: x_rat < 1.00 && y_rat > 1.00
709 return GP_FilterInterpolate_LinearInt(src
, dst
, callback
);
712 int GP_FilterResize_Raw(const GP_Context
*src
, GP_Context
*dst
,
713 GP_InterpolationType type
,
714 GP_ProgressCallback
*callback
)
718 return GP_FilterResizeNN_Raw(src
, dst
, callback
);
719 case GP_INTERP_LINEAR_INT
:
720 return GP_FilterInterpolate_LinearInt(src
, dst
, callback
);
721 case GP_INTERP_LINEAR_LF_INT
:
722 return GP_FilterInterpolate_LinearLFInt(src
, dst
, callback
);
723 case GP_INTERP_CUBIC
:
724 return GP_FilterInterpolate_Cubic(src
, dst
, callback
);
725 case GP_INTERP_CUBIC_INT
:
726 return GP_FilterInterpolate_CubicInt(src
, dst
, callback
);
732 GP_Context
*GP_FilterResize(const GP_Context
*src
, GP_Context
*dst
,
733 GP_InterpolationType type
,
734 GP_Size w
, GP_Size h
,
735 GP_ProgressCallback
*callback
)
737 GP_Context sub
, *res
;
739 /* TODO: Templatize */
740 if (src
->pixel_type
!= GP_PIXEL_RGB888
)
744 res
= GP_ContextAlloc(w
, h
, src
->pixel_type
);
749 GP_ASSERT(src
->pixel_type
== dst
->pixel_type
,
750 "The src and dst pixel types must match");
752 * The size of w and h is asserted in subcontext initalization
754 res
= GP_SubContext(dst
, &sub
, 0, 0, w
, h
);
758 * Operation was aborted by progress callback.
760 * Free any alloacted data and exit.
762 if (GP_FilterResize_Raw(src
, res
, type
, callback
)) {
763 GP_DEBUG(1, "Operation aborted");
771 return dst
== NULL
? res
: dst
;