2 * Image Scaling Functions
3 * Copyright (c) 2005 David A. Schleef <ds@schleef.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
28 #include "vs_scanline.h"
30 #include <liboil/liboil.h>
32 /* greyscale, i.e., single componenet */
35 vs_scanline_downsample_Y (uint8_t * dest, uint8_t * src, int n)
39 for (i = 0; i < n; i++) {
40 dest[i] = (src[i * 2] + src[i * 2 + 1]) / 2;
45 vs_scanline_resample_nearest_Y (uint8_t * dest, uint8_t * src, int src_width,
46 int n, int *accumulator, int increment)
48 int acc = *accumulator;
53 for (i = 0; i < n; i++) {
56 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
66 vs_scanline_resample_linear_Y (uint8_t * dest, uint8_t * src, int src_width,
67 int n, int *accumulator, int increment)
69 int acc = *accumulator;
74 for (i = 0; i < n; i++) {
78 if (j + 1 < src_width)
79 dest[i] = (src[j] * (65536 - x) + src[j + 1] * x) >> 16;
90 vs_scanline_merge_linear_Y (uint8_t * dest, uint8_t * src1, uint8_t * src2,
93 uint32_t value = x >> 8;
95 oil_merge_linear_u8 (dest, src1, src2, &value, n);
102 vs_scanline_downsample_RGBA (uint8_t * dest, uint8_t * src, int n)
106 for (i = 0; i < n; i++) {
107 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2;
108 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 5]) / 2;
109 dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2;
110 dest[i * 4 + 3] = (src[i * 8 + 3] + src[i * 8 + 7]) / 2;
115 vs_scanline_resample_nearest_RGBA (uint8_t * dest, uint8_t * src, int src_width,
116 int n, int *accumulator, int increment)
118 int acc = *accumulator;
123 for (i = 0; i < n; i++) {
127 if (j + 1 < src_width) {
128 dest[i * 4 + 0] = (x < 32768) ? src[j * 4 + 0] : src[j * 4 + 4];
129 dest[i * 4 + 1] = (x < 32768) ? src[j * 4 + 1] : src[j * 4 + 5];
130 dest[i * 4 + 2] = (x < 32768) ? src[j * 4 + 2] : src[j * 4 + 6];
131 dest[i * 4 + 3] = (x < 32768) ? src[j * 4 + 3] : src[j * 4 + 7];
133 dest[i * 4 + 0] = src[j * 4 + 0];
134 dest[i * 4 + 1] = src[j * 4 + 1];
135 dest[i * 4 + 2] = src[j * 4 + 2];
136 dest[i * 4 + 3] = src[j * 4 + 3];
147 vs_scanline_resample_linear_RGBA (uint8_t * dest, uint8_t * src, int src_width,
148 int n, int *accumulator, int increment)
152 vals[0] = *accumulator;
155 if (src_width % 2 == 0) {
156 oil_resample_linear_argb ((uint32_t *) dest, (uint32_t *) src, n, vals);
157 } else if (src_width > 1) {
159 oil_resample_linear_argb ((uint32_t *) dest, (uint32_t *) src, n - 1,
161 dest[4 * (n - 1) + 0] = src[(vals[0] >> 16) + 0];
162 dest[4 * (n - 1) + 1] = src[(vals[0] >> 16) + 1];
163 dest[4 * (n - 1) + 2] = src[(vals[0] >> 16) + 2];
164 dest[4 * (n - 1) + 3] = src[(vals[0] >> 16) + 3];
165 vals[0] += increment;
169 for (i = 0; i < n; i++) {
170 dest[4 * i + 0] = src[0];
171 dest[4 * i + 1] = src[1];
172 dest[4 * i + 2] = src[2];
173 dest[4 * i + 3] = src[3];
174 vals[0] += increment;
178 *accumulator = vals[0];
182 vs_scanline_merge_linear_RGBA (uint8_t * dest, uint8_t * src1, uint8_t * src2,
185 uint32_t value = x >> 8;
187 oil_merge_linear_argb ((uint32_t *) dest, (uint32_t *) src1,
188 (uint32_t *) src2, &value, n);
195 vs_scanline_downsample_RGB (uint8_t * dest, uint8_t * src, int n)
199 for (i = 0; i < n; i++) {
200 dest[i * 3 + 0] = (src[i * 6 + 0] + src[i * 6 + 3]) / 2;
201 dest[i * 3 + 1] = (src[i * 6 + 1] + src[i * 6 + 4]) / 2;
202 dest[i * 3 + 2] = (src[i * 6 + 2] + src[i * 6 + 5]) / 2;
207 vs_scanline_resample_nearest_RGB (uint8_t * dest, uint8_t * src, int src_width,
208 int n, int *accumulator, int increment)
210 int acc = *accumulator;
215 for (i = 0; i < n; i++) {
218 dest[i * 3 + 0] = (x < 32768
219 || j + 1 >= src_width) ? src[j * 3 + 0] : src[j * 3 + 3];
220 dest[i * 3 + 1] = (x < 32768
221 || j + 1 >= src_width) ? src[j * 3 + 1] : src[j * 3 + 4];
222 dest[i * 3 + 2] = (x < 32768
223 || j + 1 >= src_width) ? src[j * 3 + 2] : src[j * 3 + 5];
232 vs_scanline_resample_linear_RGB (uint8_t * dest, uint8_t * src, int src_width,
233 int n, int *accumulator, int increment)
235 int acc = *accumulator;
240 for (i = 0; i < n; i++) {
244 if (j + 1 < src_width) {
246 (src[j * 3 + 0] * (65536 - x) + src[j * 3 + 3] * x) >> 16;
248 (src[j * 3 + 1] * (65536 - x) + src[j * 3 + 4] * x) >> 16;
250 (src[j * 3 + 2] * (65536 - x) + src[j * 3 + 5] * x) >> 16;
252 dest[i * 3 + 0] = src[j * 3 + 0];
253 dest[i * 3 + 1] = src[j * 3 + 1];
254 dest[i * 3 + 2] = src[j * 3 + 2];
264 vs_scanline_merge_linear_RGB (uint8_t * dest, uint8_t * src1, uint8_t * src2,
267 uint32_t value = x >> 8;
269 oil_merge_linear_u8 (dest, src1, src2, &value, n * 3);
275 /* n is the number of pixels */
276 /* increment is per Y pixel */
279 vs_scanline_downsample_YUYV (uint8_t * dest, uint8_t * src, int n)
283 for (i = 0; i < n; i++) {
284 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 2]) / 2;
285 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 5]) / 2;
286 dest[i * 4 + 2] = (src[i * 8 + 4] + src[i * 8 + 6]) / 2;
287 dest[i * 4 + 3] = (src[i * 8 + 3] + src[i * 8 + 7]) / 2;
292 vs_scanline_resample_nearest_YUYV (uint8_t * dest, uint8_t * src, int src_width,
293 int n, int *accumulator, int increment)
295 int acc = *accumulator;
299 int quads = (n + 1) / 2;
301 for (i = 0; i < quads; i++) {
304 dest[i * 4 + 0] = (x < 32768
305 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
309 dest[i * 4 + 1] = (x < 65536
310 || 2 * (j + 2) >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
312 if (2 * i + 1 < n && 2 * (j + 1) < src_width)
313 dest[i * 4 + 3] = (x < 65536
314 || 2 * (j + 3) >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
321 if (2 * i + 1 < n && j < src_width) {
322 dest[i * 4 + 2] = (x < 32768
323 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
332 vs_scanline_resample_linear_YUYV (uint8_t * dest, uint8_t * src, int src_width,
333 int n, int *accumulator, int increment)
335 int acc = *accumulator;
339 int quads = (n + 1) / 2;
341 for (i = 0; i < quads; i++) {
345 if (j + 1 < src_width)
347 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
349 dest[i * 4 + 0] = src[j * 2 + 0];
354 if (2 * (j + 2) < src_width)
356 (src[j * 4 + 1] * (131072 - x) + src[j * 4 + 5] * x) >> 17;
358 dest[i * 4 + 1] = src[j * 4 + 1];
360 if (2 * i + 1 < n && 2 * (j + 1) < src_width) {
361 if (2 * (j + 3) < src_width)
363 (src[j * 4 + 3] * (131072 - x) + src[j * 4 + 7] * x) >> 17;
365 dest[i * 4 + 3] = src[j * 4 + 3];
373 if (2 * i + 1 < n && j < src_width) {
374 if (j + 1 < src_width)
376 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
378 dest[i * 4 + 2] = src[j * 2 + 0];
388 vs_scanline_merge_linear_YUYV (uint8_t * dest, uint8_t * src1, uint8_t * src2,
392 int quads = (n + 1) / 2;
394 for (i = 0; i < quads; i++) {
396 (src1[i * 4 + 0] * (65536 - x) + src2[i * 4 + 0] * x) >> 16;
398 (src1[i * 4 + 1] * (65536 - x) + src2[i * 4 + 1] * x) >> 16;
402 (src1[i * 4 + 2] * (65536 - x) + src2[i * 4 + 2] * x) >> 16;
404 (src1[i * 4 + 3] * (65536 - x) + src2[i * 4 + 3] * x) >> 16;
412 /* n is the number of bi-pixels */
413 /* increment is per Y pixel */
416 vs_scanline_downsample_UYVY (uint8_t * dest, uint8_t * src, int n)
420 for (i = 0; i < n; i++) {
421 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2;
422 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 3]) / 2;
423 dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2;
424 dest[i * 4 + 3] = (src[i * 8 + 5] + src[i * 8 + 7]) / 2;
429 vs_scanline_resample_nearest_UYVY (uint8_t * dest, uint8_t * src, int src_width,
430 int n, int *accumulator, int increment)
432 int acc = *accumulator;
436 int quads = (n + 1) / 2;
438 for (i = 0; i < quads; i++) {
442 dest[i * 4 + 1] = (x < 32768
443 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
448 dest[i * 4 + 0] = (x < 65536
449 || 2 * (j + 2) >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
451 if (2 * i + 1 < n && 2 * (j + 1) < src_width)
452 dest[i * 4 + 2] = (x < 65536
453 || 2 * (j + 3) >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
460 if (2 * i + 1 < n && j < src_width) {
461 dest[i * 4 + 3] = (x < 32768
462 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
471 vs_scanline_resample_linear_UYVY (uint8_t * dest, uint8_t * src, int src_width,
472 int n, int *accumulator, int increment)
474 int acc = *accumulator;
478 int quads = (n + 1) / 2;
480 for (i = 0; i < quads; i++) {
484 if (j + 1 < src_width)
486 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
488 dest[i * 4 + 1] = src[j * 2 + 1];
492 if (2 * (j + 2) < src_width)
494 (src[j * 4 + 0] * (131072 - x) + src[j * 4 + 4] * x) >> 17;
496 dest[i * 4 + 0] = src[j * 4 + 0];
498 if (i * 2 + 1 < n && 2 * (j + 1) < src_width) {
499 if (2 * (j + 3) < src_width)
501 (src[j * 4 + 2] * (131072 - x) + src[j * 4 + 6] * x) >> 17;
503 dest[i * 4 + 2] = src[j * 4 + 2];
511 if (2 * i + 1 < n && j < src_width) {
512 if (j + 1 < src_width)
514 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
516 dest[i * 4 + 3] = src[j * 2 + 1];
525 vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
526 uint8_t * src2, int n, int x)
529 int quads = (n + 1) / 2;
531 for (i = 0; i < quads; i++) {
533 (src1[i * 4 + 0] * (65536 - x) + src2[i * 4 + 0] * x) >> 16;
535 (src1[i * 4 + 1] * (65536 - x) + src2[i * 4 + 1] * x) >> 16;
539 (src1[i * 4 + 2] * (65536 - x) + src2[i * 4 + 2] * x) >> 16;
541 (src1[i * 4 + 3] * (65536 - x) + src2[i * 4 + 3] * x) >> 16;
549 /* note that src and dest are uint16_t, and thus endian dependent */
551 #define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13)
552 #define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9)
553 #define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
555 #define RGB565(r,g,b) \
556 ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f))
560 vs_scanline_downsample_RGB565 (uint8_t * dest_u8, uint8_t * src_u8, int n)
562 uint16_t *dest = (uint16_t *) dest_u8;
563 uint16_t *src = (uint16_t *) src_u8;
566 for (i = 0; i < n; i++) {
568 (RGB565_R (src[i * 2]) + RGB565_R (src[i * 2 + 1])) / 2,
569 (RGB565_G (src[i * 2]) + RGB565_G (src[i * 2 + 1])) / 2,
570 (RGB565_B (src[i * 2]) + RGB565_B (src[i * 2 + 1])) / 2);
575 vs_scanline_resample_nearest_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
576 int src_width, int n, int *accumulator, int increment)
578 uint16_t *dest = (uint16_t *) dest_u8;
579 uint16_t *src = (uint16_t *) src_u8;
580 int acc = *accumulator;
585 for (i = 0; i < n; i++) {
588 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
597 vs_scanline_resample_linear_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
598 int src_width, int n, int *accumulator, int increment)
600 uint16_t *dest = (uint16_t *) dest_u8;
601 uint16_t *src = (uint16_t *) src_u8;
602 int acc = *accumulator;
607 for (i = 0; i < n; i++) {
611 if (j + 1 < src_width) {
613 (RGB565_R (src[j]) * (65536 - x) + RGB565_R (src[j + 1]) * x) >> 16,
614 (RGB565_G (src[j]) * (65536 - x) + RGB565_G (src[j + 1]) * x) >> 16,
615 (RGB565_B (src[j]) * (65536 - x) + RGB565_B (src[j + 1]) * x) >> 16);
617 dest[i] = RGB565 (RGB565_R (src[j]),
618 RGB565_G (src[j]), RGB565_B (src[j]));
628 vs_scanline_merge_linear_RGB565 (uint8_t * dest_u8, uint8_t * src1_u8,
629 uint8_t * src2_u8, int n, int x)
631 uint16_t *dest = (uint16_t *) dest_u8;
632 uint16_t *src1 = (uint16_t *) src1_u8;
633 uint16_t *src2 = (uint16_t *) src2_u8;
636 for (i = 0; i < n; i++) {
638 (RGB565_R (src1[i]) * (65536 - x) + RGB565_R (src2[i]) * x) >> 16,
639 (RGB565_G (src1[i]) * (65536 - x) + RGB565_G (src2[i]) * x) >> 16,
640 (RGB565_B (src1[i]) * (65536 - x) + RGB565_B (src2[i]) * x) >> 16);
647 /* note that src and dest are uint16_t, and thus endian dependent */
649 #define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13)
650 #define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9)
651 #define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
653 #define RGB555(r,g,b) \
654 ((((r)<<7)&0x7c00) | (((g)<<3)&0x03e0) | (((b)>>3)&0x001f))
658 vs_scanline_downsample_RGB555 (uint8_t * dest_u8, uint8_t * src_u8, int n)
660 uint16_t *dest = (uint16_t *) dest_u8;
661 uint16_t *src = (uint16_t *) src_u8;
664 for (i = 0; i < n; i++) {
666 (RGB555_R (src[i * 2]) + RGB555_R (src[i * 2 + 1])) / 2,
667 (RGB555_G (src[i * 2]) + RGB555_G (src[i * 2 + 1])) / 2,
668 (RGB555_B (src[i * 2]) + RGB555_B (src[i * 2 + 1])) / 2);
673 vs_scanline_resample_nearest_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
674 int src_width, int n, int *accumulator, int increment)
676 uint16_t *dest = (uint16_t *) dest_u8;
677 uint16_t *src = (uint16_t *) src_u8;
678 int acc = *accumulator;
683 for (i = 0; i < n; i++) {
686 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
695 vs_scanline_resample_linear_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
696 int src_width, int n, int *accumulator, int increment)
698 uint16_t *dest = (uint16_t *) dest_u8;
699 uint16_t *src = (uint16_t *) src_u8;
700 int acc = *accumulator;
705 for (i = 0; i < n; i++) {
709 if (j + 1 < src_width) {
711 (RGB555_R (src[j]) * (65536 - x) + RGB555_R (src[j + 1]) * x) >> 16,
712 (RGB555_G (src[j]) * (65536 - x) + RGB555_G (src[j + 1]) * x) >> 16,
713 (RGB555_B (src[j]) * (65536 - x) + RGB555_B (src[j + 1]) * x) >> 16);
715 dest[i] = RGB555 (RGB555_R (src[j]),
716 RGB555_G (src[j]), RGB555_B (src[j]));
726 vs_scanline_merge_linear_RGB555 (uint8_t * dest_u8, uint8_t * src1_u8,
727 uint8_t * src2_u8, int n, int x)
729 uint16_t *dest = (uint16_t *) dest_u8;
730 uint16_t *src1 = (uint16_t *) src1_u8;
731 uint16_t *src2 = (uint16_t *) src2_u8;
734 for (i = 0; i < n; i++) {
736 (RGB555_R (src1[i]) * (65536 - x) + RGB555_R (src2[i]) * x) >> 16,
737 (RGB555_G (src1[i]) * (65536 - x) + RGB555_G (src2[i]) * x) >> 16,
738 (RGB555_B (src1[i]) * (65536 - x) + RGB555_B (src2[i]) * x) >> 16);