📄 pixops.c
字号:
/* Copyright (C) 2000 Red Hat, Inc. * Portions copyright (C) 2004 VMware, Inc. * This file is part of the Pixops Library. * * The pixops library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * The pixops library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * pixops.c -- * * Implements C routines for image scaling. Some functions also have an * MMX-accelerated implementation, see the corresponding .S files for the * code. */#include <math.h>#include <stdlib.h>#include "pixops.h"#include "pixops-internal.h"#include "convert.h"#define SUBSAMPLE_BITS 4#define SUBSAMPLE (1 << SUBSAMPLE_BITS)#define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)#define SCALE_SHIFT 16static intget_check_shift (int check_size){ int check_shift = 0; return_val_if_fail (check_size >= 0, 4); while (!(check_size & 1)) { check_shift++; check_size >>= 1; } return check_shift;}static voidpixops_scale_nearest (uint8 *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_bytes_per_pixel, int dest_depth, boolean dest_has_alpha, const uint8 *src_buf, int src_width, int src_height, int src_rowstride, int src_bytes_per_pixel, int src_depth, uint32 *src_colormap, boolean src_has_alpha, double scale_x, double scale_y){ int i, j; int x; int x_step = (1 << SCALE_SHIFT) / scale_x; int y_step = (1 << SCALE_SHIFT) / scale_y; int src_bppdepth = BPPDEPTH(src_bytes_per_pixel << 3, src_depth); int dest_bppdepth = BPPDEPTH(dest_bytes_per_pixel << 3, dest_depth); /* * Define this bogus type so the macro loop will work */ typedef unsigned char uint24;#define INNER_LOOP(op, SRC_BPP, DEST_BPP, INDEXED) \ for (j=0; j < (render_x1 - render_x0); j++) { \ const unsigned char *p = src + (x >> SCALE_SHIFT) * (SRC_BPP >> 3); \ unsigned int pix; \ if (SRC_BPP == 24 && INDEXED == FALSE) { \ pix = op((p[0] | (p[1] << 8) | (p[2] << 16))); \ } else if (INDEXED == TRUE) { \ pix = op(src_colormap[*p]); \ } else { \ pix = op((*(uint##SRC_BPP *) p)); \ } \ if (DEST_BPP == 24) { \ dest[0] = pix & 0xff; \ dest[1] = (pix >> 8) & 0xff; \ dest[2] = (pix >> 16) & 0xff; \ } else { \ *((uint##DEST_BPP *) dest) = (uint##DEST_BPP) pix; \ } \ dest += DEST_BPP >> 3; \ x += x_step; \ } \ break; for (i = 0; i < (render_y1 - render_y0); i++) { const uint8 *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride; uint8 *dest = dest_buf + i * dest_rowstride; x = render_x0 * x_step + x_step / 2; switch(src_bppdepth) { case 8: switch(dest_bppdepth) { case 8: INNER_LOOP(CONVERT_NOP, 8, 8, TRUE); case 15: INNER_LOOP(CONVERT_24_TO_15, 8, 16, TRUE); case 16: INNER_LOOP(CONVERT_24_TO_16, 8, 16, TRUE); case 24: INNER_LOOP(CONVERT_NOP, 8, 24, TRUE); case 32: INNER_LOOP(CONVERT_NOP, 8, 32, TRUE); } break; case 15: switch(dest_bppdepth) { case 8: INNER_LOOP(CONVERT_15_TO_8BGR, 16, 8, FALSE); case 15: INNER_LOOP(CONVERT_NOP, 16, 16, FALSE); case 16: INNER_LOOP(CONVERT_15_TO_16, 16, 16, FALSE); case 24: INNER_LOOP(CONVERT_15_TO_24, 16, 24, FALSE); case 32: INNER_LOOP(CONVERT_15_TO_24, 16, 32, FALSE); } break; case 16: switch(dest_bppdepth) { case 8: INNER_LOOP(CONVERT_16_TO_8BGR, 16, 8, FALSE); case 15: INNER_LOOP(CONVERT_16_TO_15, 16, 16, FALSE); case 16: INNER_LOOP(CONVERT_NOP, 16, 16, FALSE); case 24: INNER_LOOP(CONVERT_16_TO_24, 16, 24, FALSE); case 32: INNER_LOOP(CONVERT_16_TO_24, 16, 32, FALSE); } break; case 24: switch(dest_bppdepth) { case 8: INNER_LOOP(CONVERT_24_TO_8BGR, 24, 8, FALSE); case 15: INNER_LOOP(CONVERT_24_TO_15, 24, 16, FALSE); case 16: INNER_LOOP(CONVERT_24_TO_16, 24, 16, FALSE); case 24: INNER_LOOP(CONVERT_NOP, 24, 24, FALSE); case 32: INNER_LOOP(CONVERT_NOP, 24, 32, FALSE); } break; case 32: switch(dest_bppdepth) { case 8: INNER_LOOP(CONVERT_24_TO_8BGR, 32, 8, FALSE); case 15: INNER_LOOP(CONVERT_24_TO_15, 32, 16, FALSE); case 16: INNER_LOOP(CONVERT_24_TO_16, 32, 16, FALSE); case 24: INNER_LOOP(CONVERT_NOP, 32, 24, FALSE); case 32: INNER_LOOP(CONVERT_NOP, 32, 32, FALSE); } break; } }#undef INNER_LOOP}static voidpixops_scale_composite_nearest (uint8 *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, boolean dest_has_alpha, const uint8 *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, boolean src_has_alpha, double scale_x, double scale_y, int overall_alpha){ int i, j; int x; int x_step = (1 << SCALE_SHIFT) / scale_x; int y_step = (1 << SCALE_SHIFT) / scale_y; for (i = 0; i < (render_y1 - render_y0); i++) { const uint8 *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride; uint8 *dest = dest_buf + i * dest_rowstride; x = render_x0 * x_step + x_step / 2; for (j=0; j < (render_x1 - render_x0); j++) { const uint8 *p = src + (x >> SCALE_SHIFT) * src_channels; unsigned int a0; if (src_has_alpha) a0 = (p[3] * overall_alpha) / 0xff; else a0 = overall_alpha; switch (a0) { case 0: break; case 255: dest[0] = p[0]; dest[1] = p[1]; dest[2] = p[2]; if (dest_has_alpha) dest[3] = 0xff; break; default: if (dest_has_alpha) { unsigned int w0 = 0xff * a0; unsigned int w1 = (0xff - a0) * dest[3]; unsigned int w = w0 + w1; dest[0] = (w0 * p[0] + w1 * dest[0]) / w; dest[1] = (w0 * p[1] + w1 * dest[1]) / w; dest[2] = (w0 * p[2] + w1 * dest[2]) / w; dest[3] = w / 0xff; } else { unsigned int a1 = 0xff - a0; unsigned int tmp; tmp = a0 * p[0] + a1 * dest[0] + 0x80; dest[0] = (tmp + (tmp >> 8)) >> 8; tmp = a0 * p[1] + a1 * dest[1] + 0x80; dest[1] = (tmp + (tmp >> 8)) >> 8; tmp = a0 * p[2] + a1 * dest[2] + 0x80; dest[2] = (tmp + (tmp >> 8)) >> 8; } break; } dest += dest_channels; x += x_step; } }}static voidpixops_scale_composite_color_nearest (uint8 *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, boolean dest_has_alpha, const uint8 *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, boolean src_has_alpha, double scale_x, double scale_y, int overall_alpha, int check_x, int check_y, int check_size, uint32 color1, uint32 color2){ int i, j; int x; int x_step = (1 << SCALE_SHIFT) / scale_x; int y_step = (1 << SCALE_SHIFT) / scale_y; int r1, g1, b1, r2, g2, b2; int check_shift = get_check_shift (check_size); for (i = 0; i < (render_y1 - render_y0); i++) { const uint8 *src = src_buf + (((i + render_y0) * y_step + y_step/2) >> SCALE_SHIFT) * src_rowstride; uint8 *dest = dest_buf + i * dest_rowstride; x = render_x0 * x_step + x_step / 2; if (((i + check_y) >> check_shift) & 1) { r1 = (color2 & 0xff0000) >> 16; g1 = (color2 & 0xff00) >> 8; b1 = color2 & 0xff; r2 = (color1 & 0xff0000) >> 16; g2 = (color1 & 0xff00) >> 8; b2 = color1 & 0xff; } else { r1 = (color1 & 0xff0000) >> 16; g1 = (color1 & 0xff00) >> 8; b1 = color1 & 0xff; r2 = (color2 & 0xff0000) >> 16; g2 = (color2 & 0xff00) >> 8; b2 = color2 & 0xff; } for (j=0 ; j < (render_x1 - render_x0); j++) { const uint8 *p = src + (x >> SCALE_SHIFT) * src_channels; int a0; int tmp; if (src_has_alpha) a0 = (p[3] * overall_alpha + 0xff) >> 8; else a0 = overall_alpha; switch (a0) { case 0: if (((j + check_x) >> check_shift) & 1) { dest[0] = r2; dest[1] = g2; dest[2] = b2; } else { dest[0] = r1; dest[1] = g1; dest[2] = b1; } break; case 255: dest[0] = p[0]; dest[1] = p[1]; dest[2] = p[2]; break; default: if (((j + check_x) >> check_shift) & 1) { tmp = ((int) p[0] - r2) * a0; dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = ((int) p[1] - g2) * a0; dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = ((int) p[2] - b2) * a0; dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8); } else { tmp = ((int) p[0] - r1) * a0; dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = ((int) p[1] - g1) * a0; dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = ((int) p[2] - b1) * a0; dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8); } break; } if (dest_channels == 4) dest[3] = 0xff; dest += dest_channels; x += x_step; } }}static voidcomposite_pixel (uint8 *dest, int dest_x, int dest_bytes_per_pixel, int dest_depth, int dest_has_alpha, int src_has_alpha, int check_size, uint32 color1, uint32 color2, uint r, uint g, uint b, uint a){ if (dest_has_alpha) { unsigned int w0 = a - (a >> 8); unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3]; unsigned int w = w0 + w1; if (w != 0) { dest[0] = (r - (r >> 8) + w1 * dest[0]) / w; dest[1] = (g - (g >> 8) + w1 * dest[1]) / w; dest[2] = (b - (b >> 8) + w1 * dest[2]) / w; dest[3] = w / 0xff00; } else { dest[0] = 0; dest[1] = 0; dest[2] = 0; dest[3] = 0; } } else { dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000; dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000; dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000; }}static uint8 *composite_line (int *weights, int n_x, int n_y, uint8 *dest, int dest_x, uint8 *dest_end, int dest_bytes_per_pixel, int dest_depth, int dest_has_alpha, uint8 **src, int src_bytes_per_pixel, int src_depth, uint32 *src_colormap, boolean src_has_alpha, int x_init, int x_step, int src_width, int check_size, uint32 color1, uint32 color2){ int x = x_init; int i, j; while (dest < dest_end) { int x_scaled = x >> SCALE_SHIFT; unsigned int r = 0, g = 0, b = 0, a = 0; int *pixel_weights; pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y; for (i=0; i<n_y; i++) { uint8 *q = src[i] + x_scaled * src_bytes_per_pixel; int *line_weights = pixel_weights + n_x * i; for (j=0; j<n_x; j++) { unsigned int ta; if (src_has_alpha) ta = q[3] * line_weights[j]; else ta = 0xff * line_weights[j];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -