Latest work on the bmp on-load scaler:
[kugel-rb.git] / apps / recorder / resize.c
blob3c1d34f0469540a3102d9156ebd9f6bdfaa7c837
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Akio Idehara, Andrew Mahone
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * Implementation of area average and linear row and vertical scalers, and
24 * nearest-neighbor grey scaler (C) 2008 Andrew Mahone
26 * All files in this archive are subject to the GNU General Public License.
27 * See the file COPYING in the source tree root for full license agreement.
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
30 * KIND, either express or implied.
32 ****************************************************************************/
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <general.h>
38 #include "inttypes.h"
39 #include "debug.h"
40 #include "lcd.h"
41 #include "file.h"
42 #ifdef HAVE_REMOTE_LCD
43 #include "lcd-remote.h"
44 #endif
45 #ifdef ROCKBOX_DEBUG_SCALERS
46 #define SDEBUGF DEBUGF
47 #else
48 #define SDEBUGF(...)
49 #endif
50 #ifndef __PCTOOL__
51 #include "config.h"
52 #include "system.h"
53 #include "bmp.h"
54 #include "resize.h"
55 #include "resize.h"
56 #include "debug.h"
57 #else
58 #undef DEBUGF
59 #define DEBUGF(...)
60 #endif
62 /* calculate the maximum dimensions which will preserve the aspect ration of
63 src while fitting in the constraints passed in dst, and store result in dst,
64 returning 0 if rounding and 1 if not rounding.
66 int recalc_dimension(struct dim *dst, struct dim *src)
68 int tmp;
69 if (dst->width <= 0)
70 dst->width = LCD_WIDTH;
71 if (dst->height <= 0)
72 dst->height = LCD_HEIGHT;
73 #ifndef HAVE_UPSCALER
74 if (dst->width > src->width || dst->height > src->height)
76 dst->width = src->width;
77 dst->height = src->height;
79 if (src->width == dst->width && src->height == dst->height)
80 return 1;
81 #endif
82 tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
83 if (tmp > dst->width)
84 dst->height = (src->height * dst->width + (src->width >> 1))
85 / src->width;
86 else
87 dst->width = tmp;
88 return src->width == dst->width && src->height == dst->height;
91 /* All of these scalers use variations of Bresenham's algorithm to convert from
92 their input to output coordinates. The error value is shifted from the
93 "classic" version such that it is a useful input to the scaling calculation.
96 #ifdef HAVE_LCD_COLOR
97 /* dither + pack on channel of RGB565, R an B share a packing macro */
98 #define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8)
99 #define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8)
100 #endif
102 /* read new img_part unconditionally, return false on failure */
103 #define FILL_BUF_INIT(img_part, store_part, args) { \
104 img_part = store_part(args); \
105 if (img_part == NULL) \
106 return false; \
109 /* read new img_part if current one is empty, return false on failure */
110 #define FILL_BUF(img_part, store_part, args) { \
111 if (img_part->len == 0) \
112 img_part = store_part(args); \
113 if (img_part == NULL) \
114 return false; \
117 /* struct which containers various parameters shared between vertical scaler,
118 horizontal scaler, and row output
120 struct scaler_context {
121 uint32_t divisor;
122 uint32_t round;
123 struct bitmap *bm;
124 struct dim *src;
125 unsigned char *buf;
126 bool dither;
127 int len;
128 void *args;
129 struct img_part* (*store_part)(void *);
130 void (*output_row)(uint32_t,void*,struct scaler_context*);
131 bool (*h_scaler)(void*,struct scaler_context*, bool);
134 /* Set up rounding and scale factors for horizontal area scaler */
135 static inline void scale_h_area_setup(struct scaler_context *ctx)
137 /* sum is output value * src->width */
138 SDEBUGF("scale_h_area_setup\n");
139 ctx->divisor = ctx->src->width;
142 /* horizontal area average scaler */
143 static bool scale_h_area(void *out_line_ptr,
144 struct scaler_context *ctx, bool accum)
146 SDEBUGF("scale_h_area\n");
147 unsigned int ix, ox, oxe, mul;
148 #ifdef HAVE_LCD_COLOR
149 struct uint32_rgb rgbvalacc = { 0, 0, 0 },
150 rgbvaltmp = { 0, 0, 0 },
151 *out_line = (struct uint32_rgb *)out_line_ptr;
152 #else
153 uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr;
154 #endif
155 struct img_part *part;
156 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
157 ox = 0;
158 oxe = 0;
159 mul = 0;
160 /* give other tasks a chance to run */
161 yield();
162 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++)
164 oxe += ctx->bm->width;
165 /* end of current area has been reached */
166 /* fill buffer if needed */
167 FILL_BUF(part,ctx->store_part,ctx->args);
168 #ifdef HAVE_LCD_COLOR
169 if (oxe >= (unsigned int)ctx->src->width)
171 /* "reset" error, which now represents partial coverage of next
172 pixel by the next area
174 oxe -= ctx->src->width;
176 /* add saved partial pixel from start of area */
177 rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul;
178 rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul;
179 rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul;
181 /* get new pixel , then add its partial coverage to this area */
182 rgbvaltmp.r = part->buf->red;
183 rgbvaltmp.g = part->buf->green;
184 rgbvaltmp.b = part->buf->blue;
185 mul = ctx->bm->width - oxe;
186 rgbvalacc.r += rgbvaltmp.r * mul;
187 rgbvalacc.g += rgbvaltmp.g * mul;
188 rgbvalacc.b += rgbvaltmp.b * mul;
189 /* store or accumulate to output row */
190 if (accum)
192 rgbvalacc.r += out_line[ox].r;
193 rgbvalacc.g += out_line[ox].g;
194 rgbvalacc.b += out_line[ox].b;
196 out_line[ox].r = rgbvalacc.r;
197 out_line[ox].g = rgbvalacc.g;
198 out_line[ox].b = rgbvalacc.b;
199 /* reset accumulator */
200 rgbvalacc.r = 0;
201 rgbvalacc.g = 0;
202 rgbvalacc.b = 0;
203 mul = ctx->bm->width - mul;
204 ox += 1;
205 /* inside an area */
206 } else {
207 /* add pixel value to accumulator */
208 rgbvalacc.r += part->buf->red;
209 rgbvalacc.g += part->buf->green;
210 rgbvalacc.b += part->buf->blue;
212 #else
213 if (oxe >= (unsigned int)ctx->src->width)
215 /* "reset" error, which now represents partial coverage of next
216 pixel by the next area
218 oxe -= ctx->src->width;
220 /* add saved partial pixel from start of area */
221 acc = acc * ctx->bm->width + tmp * mul;
223 /* get new pixel , then add its partial coverage to this area */
224 tmp = *(part->buf);
225 mul = ctx->bm->width - oxe;
226 acc += tmp * mul;
227 /* round, divide, and either store or accumulate to output row */
228 if (accum)
230 acc += out_line[ox];
232 out_line[ox] = acc;
233 /* reset accumulator */
234 acc = 0;
235 mul = ctx->bm->width - mul;
236 ox += 1;
237 /* inside an area */
238 } else {
239 /* add pixel value to accumulator */
240 acc += *(part->buf);
242 #endif
243 part->buf++;
244 part->len--;
246 return true;
249 /* vertical area average scaler */
250 static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx)
252 uint32_t mul, x, oy, iy, oye;
254 /* Set up rounding and scale factors */
255 ctx->divisor *= ctx->src->height;
256 ctx->round = ctx->divisor >> 1;
257 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
258 mul = 0;
259 oy = rset->rowstart;
260 oye = 0;
261 #ifdef HAVE_LCD_COLOR
262 uint32_t *rowacc = (uint32_t *) ctx->buf,
263 *rowtmp = rowacc + 3 * ctx->bm->width;
264 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb));
265 #else
266 uint32_t *rowacc = (uint32_t *) ctx->buf,
267 *rowtmp = rowacc + ctx->bm->width;
268 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t));
269 #endif
270 SDEBUGF("scale_v_area\n");
271 /* zero the accumulator and temp rows */
272 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++)
274 oye += ctx->bm->height;
275 /* end of current area has been reached */
276 if (oye >= (unsigned int)ctx->src->height)
278 /* "reset" error, which now represents partial coverage of the next
279 row by the next area
281 oye -= ctx->src->height;
282 /* add stored partial row to accumulator */
283 #ifdef HAVE_LCD_COLOR
284 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
285 #else
286 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
287 #endif
288 rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x];
289 /* store new scaled row in temp row */
290 if(!ctx->h_scaler(rowtmp, ctx, false))
291 return false;
292 /* add partial coverage by new row to this area, then round and
293 scale to final value
295 mul = ctx->bm->height - oye;
296 #ifdef HAVE_LCD_COLOR
297 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
298 #else
299 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
300 #endif
301 rowacc[x] += mul * rowtmp[x];
302 ctx->output_row(oy, (void*)rowacc, ctx);
303 /* clear accumulator row, store partial coverage for next row */
304 #ifdef HAVE_LCD_COLOR
305 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3);
306 #else
307 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t));
308 #endif
309 mul = oye;
310 oy += rset->rowstep;
311 /* inside an area */
312 } else {
313 /* accumulate new scaled row to rowacc */
314 if (!ctx->h_scaler(rowacc, ctx, true))
315 return false;
318 return true;
321 #ifdef HAVE_UPSCALER
322 /* Set up rounding and scale factors for the horizontal scaler. The divisor
323 is bm->width - 1, so that the first and last pixels in the row align
324 exactly between input and output
326 static inline void scale_h_linear_setup(struct scaler_context *ctx)
328 ctx->divisor = ctx->bm->width - 1;
331 /* horizontal linear scaler */
332 static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx,
333 bool accum)
335 unsigned int ix, ox, ixe;
336 /* type x = x is an ugly hack for hiding an unitialized data warning. The
337 values are conditionally initialized before use, but other values are
338 set such that this will occur before these are used.
340 #ifdef HAVE_LCD_COLOR
341 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc,
342 *out_line = (struct uint32_rgb*)out_line_ptr;
343 #else
344 uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr;
345 #endif
346 struct img_part *part;
347 SDEBUGF("scale_h_linear\n");
348 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
349 ix = 0;
350 /* The error is set so that values are initialized on the first pass. */
351 ixe = ctx->bm->width - 1;
352 /* give other tasks a chance to run */
353 yield();
354 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++)
356 #ifdef HAVE_LCD_COLOR
357 if (ixe >= ((uint32_t)ctx->bm->width - 1))
359 /* Store the new "current" pixel value in rgbval, and the color
360 step value in rgbinc.
362 ixe -= (ctx->bm->width - 1);
363 rgbinc.r = -(part->buf->red);
364 rgbinc.g = -(part->buf->green);
365 rgbinc.b = -(part->buf->blue);
366 rgbval.r = (part->buf->red) * (ctx->bm->width - 1);
367 rgbval.g = (part->buf->green) * (ctx->bm->width - 1);
368 rgbval.b = (part->buf->blue) * (ctx->bm->width - 1);
369 ix += 1;
370 /* If this wasn't the last pixel, add the next one to rgbinc. */
371 if (ix < (uint32_t)ctx->src->width) {
372 part->buf++;
373 part->len--;
374 /* Fetch new pixels if needed */
375 FILL_BUF(part,ctx->store_part,ctx->args);
376 rgbinc.r += part->buf->red;
377 rgbinc.g += part->buf->green;
378 rgbinc.b += part->buf->blue;
379 /* Add a partial step to rgbval, in this pixel isn't precisely
380 aligned with the new source pixel
382 rgbval.r += rgbinc.r * ixe;
383 rgbval.g += rgbinc.g * ixe;
384 rgbval.b += rgbinc.b * ixe;
386 /* Now multiple the color increment to its proper value */
387 rgbinc.r *= ctx->src->width - 1;
388 rgbinc.g *= ctx->src->width - 1;
389 rgbinc.b *= ctx->src->width - 1;
390 } else {
391 rgbval.r += rgbinc.r;
392 rgbval.g += rgbinc.g;
393 rgbval.b += rgbinc.b;
395 /* round and scale values, and accumulate or store to output */
396 if (accum)
398 out_line[ox].r += rgbval.r;
399 out_line[ox].g += rgbval.g;
400 out_line[ox].b += rgbval.b;
401 } else {
402 out_line[ox].r = rgbval.r;
403 out_line[ox].g = rgbval.g;
404 out_line[ox].b = rgbval.b;
406 #else
407 if (ixe >= ((uint32_t)ctx->bm->width - 1))
409 /* Store the new "current" pixel value in rgbval, and the color
410 step value in rgbinc.
412 ixe -= (ctx->bm->width - 1);
413 val = *(part->buf);
414 inc = -val;
415 val *= (ctx->bm->width - 1);
416 ix += 1;
417 /* If this wasn't the last pixel, add the next one to rgbinc. */
418 if (ix < (uint32_t)ctx->src->width) {
419 part->buf++;
420 part->len--;
421 /* Fetch new pixels if needed */
422 FILL_BUF(part,ctx->store_part,ctx->args);
423 inc += *(part->buf);
424 /* Add a partial step to rgbval, in this pixel isn't precisely
425 aligned with the new source pixel
427 val += inc * ixe;
429 /* Now multiply the color increment to its proper value */
430 inc *= ctx->src->width - 1;
431 } else
432 val += inc;
433 /* round and scale values, and accumulate or store to output */
434 if (accum)
436 out_line[ox] += val;
437 } else {
438 out_line[ox] = val;
440 #endif
441 ixe += ctx->src->width - 1;
443 return true;
446 /* vertical linear scaler */
447 static inline bool scale_v_linear(struct rowset *rset,
448 struct scaler_context *ctx)
450 uint32_t mul, x, iy, iye;
451 int32_t oy;
452 /* Set up scale and rounding factors, the divisor is bm->height - 1 */
453 ctx->divisor *= (ctx->bm->height - 1);
454 ctx->round = ctx->divisor >> 1;
455 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
456 /* Set up our two temp buffers. The names are generic because they'll be
457 swapped each time a new input row is read
459 #ifdef HAVE_LCD_COLOR
460 uint32_t *rowinc = (uint32_t *)(ctx->buf),
461 *rowval = rowinc + 3 * ctx->bm->width,
462 *rowtmp = rowval + 3 * ctx->bm->width;
463 #else
464 uint32_t *rowinc = (uint32_t *)(ctx->buf),
465 *rowval = rowinc + ctx->bm->width,
466 *rowtmp = rowval + ctx->bm->width;
467 #endif
469 SDEBUGF("scale_v_linear\n");
470 mul = 0;
471 iy = 0;
472 iye = ctx->bm->height - 1;
473 /* get first scaled row in rowtmp */
474 if(!ctx->h_scaler((void*)rowtmp, ctx, false))
475 return false;
476 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep)
478 if (iye >= (uint32_t)ctx->bm->height - 1)
480 iye -= ctx->bm->height - 1;
481 iy += 1;
482 #ifdef HAVE_LCD_COLOR
483 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
484 #else
485 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
486 #endif
488 rowinc[x] = -rowtmp[x];
489 rowval[x] = rowtmp[x] * (ctx->bm->height - 1);
491 if (iy < (uint32_t)ctx->src->height)
493 if (!ctx->h_scaler((void*)rowtmp, ctx, false))
494 return false;
495 #ifdef HAVE_LCD_COLOR
496 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
497 #else
498 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
499 #endif
501 rowinc[x] += rowtmp[x];
502 rowval[x] += rowinc[x] * iye;
503 rowinc[x] *= ctx->src->height - 1;
506 } else
507 #ifdef HAVE_LCD_COLOR
508 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
509 #else
510 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
511 #endif
512 rowval[x] += rowinc[x];
513 ctx->output_row(oy, (void*)rowval, ctx);
514 iye += ctx->src->height - 1;
516 return true;
518 #endif /* HAVE_UPSCALER */
520 void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx)
522 int col;
523 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
524 uint8_t dy = DITHERY(row);
525 #ifdef HAVE_LCD_COLOR
526 struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
527 #else
528 uint32_t *qp = (uint32_t*)row_in;
529 #endif
530 SDEBUGF("output_row: y: %d in: %p\n",row, row_in);
531 #if LCD_DEPTH == 2
532 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
533 /* greyscale iPods */
534 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
535 int shift = 6;
536 int delta = 127;
537 unsigned bright;
538 unsigned data = 0;
540 for (col = 0; col < ctx->bm->width; col++) {
541 if (ctx->dither)
542 delta = DITHERXDY(col,dy);
543 bright = ((*qp++) + ctx->round) *
544 (uint64_t)ctx->divisor >> 32;
545 bright = (3 * bright + (bright >> 6) + delta) >> 8;
546 data |= (~bright & 3) << shift;
547 shift -= 2;
548 if (shift < 0) {
549 *dest++ = data;
550 data = 0;
551 shift = 6;
554 if (shift < 6)
555 *dest++ = data;
556 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
557 /* iriver H1x0 */
558 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
559 (row >> 2);
560 int shift = 2 * (row & 3);
561 int delta = 127;
562 unsigned bright;
564 for (col = 0; col < ctx->bm->width; col++) {
565 if (ctx->dither)
566 delta = DITHERXDY(col,dy);
567 bright = ((*qp++) + ctx->round) *
568 (uint64_t)ctx->divisor >> 32;
569 bright = (3 * bright + (bright >> 6) + delta) >> 8;
570 *dest++ |= (~bright & 3) << shift;
572 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
573 /* iAudio M3 */
574 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
575 (row >> 3);
576 int shift = row & 7;
577 int delta = 127;
578 unsigned bright;
580 for (col = 0; col < ctx->bm->width; col++) {
581 if (ctx->dither)
582 delta = DITHERXDY(col,dy);
583 bright = ((*qp++) + ctx->round) *
584 (uint64_t)ctx->divisor >> 32;
585 bright = (3 * bright + (bright >> 6) + delta) >> 8;
586 *dest++ |= vi_pattern[bright] << shift;
588 #endif /* LCD_PIXELFORMAT */
589 #elif LCD_DEPTH == 16
590 /* iriver h300, colour iPods, X5 */
591 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
592 int delta = 127;
593 unsigned r, g, b;
594 struct uint32_rgb q0;
596 for (col = 0; col < ctx->bm->width; col++) {
597 if (ctx->dither)
598 delta = DITHERXDY(col,dy);
599 q0 = *qp++;
600 r = (q0.r + ctx->round) * (uint64_t)ctx->divisor >> 32;
601 g = (q0.g + ctx->round) * (uint64_t)ctx->divisor >> 32;
602 b = (q0.b + ctx->round) * (uint64_t)ctx->divisor >> 32;
603 r = (31 * r + (r >> 3) + delta) >> 8;
604 g = (63 * g + (g >> 2) + delta) >> 8;
605 b = (31 * b + (b >> 3) + delta) >> 8;
606 *dest++ = LCD_RGBPACK_LCD(r, g, b);
608 #endif /* LCD_DEPTH */
611 int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
612 struct rowset *rset, unsigned char *buf, unsigned int len,
613 struct img_part* (*store_part)(void *args),
614 void *args)
617 #ifdef HAVE_UPSCALER
618 const int sw = src->width;
619 const int sh = src->height;
620 const int dw = bm->width;
621 const int dh = bm->height;
622 #endif
623 int ret;
624 #ifdef HAVE_LCD_COLOR
625 unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
626 #else
627 unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
628 #endif
629 #if MAX_SC_STACK_ALLOC
630 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
631 0 : needed];
632 #endif
633 len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len,
634 sizeof(uint32_t));
635 if (needed > len)
637 #if MAX_SC_STACK_ALLOC
638 if (needed > MAX_SC_STACK_ALLOC)
640 DEBUGF("unable to allocate required buffer: %d needed, "
641 "%d available, %d permitted from stack\n",
642 needed, len, MAX_SC_STACK_ALLOC);
643 return 0;
645 if (sizeof(sc_buf) < needed)
647 DEBUGF("failed to allocate large enough buffer on stack: "
648 "%d needed, only got %d",
649 needed, MAX_SC_STACK_ALLOC);
650 return 0;
652 #else
653 DEBUGF("unable to allocate required buffer: %d needed, "
654 "%d available\n", needed, len);
655 return 0;
656 #endif
659 struct scaler_context ctx;
660 cpu_boost(true);
661 ctx.store_part = store_part;
662 ctx.args = args;
663 #if MAX_SC_STACK_ALLOC
664 ctx.buf = needed > len ? sc_buf : buf;
665 #else
666 ctx.buf = buf;
667 #endif
668 ctx.len = len;
669 ctx.bm = bm;
670 ctx.src = src;
671 ctx.dither = dither;
672 ctx.output_row = output_row_native;
673 #ifdef HAVE_UPSCALER
674 if (sw > dw)
676 #endif
677 ctx.h_scaler = scale_h_area;
678 scale_h_area_setup(&ctx);
679 #ifdef HAVE_UPSCALER
680 } else {
681 ctx.h_scaler = scale_h_linear;
682 scale_h_linear_setup(&ctx);
684 #endif
685 #ifdef HAVE_UPSCALER
686 if (sh > dh)
687 #endif
688 ret = scale_v_area(rset, &ctx);
689 #ifdef HAVE_UPSCALER
690 else
691 ret = scale_v_linear(rset, &ctx);
692 #endif
693 cpu_boost(false);
694 if (!ret)
695 return 0;
696 return BM_SIZE(bm->width,bm->height,bm->format,0);