📄 pixops.c
字号:
((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * filter->x.n * filter->y.n * SUBSAMPLE; guchar *new_outbuf; guint32 tcolor1, tcolor2; guchar *outbuf = dest_buf + dest_rowstride * i; guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0); if (((i + check_y) >> check_shift) & 1) { tcolor1 = color2; tcolor2 = color1; } else { tcolor1 = color1; tcolor2 = color2; } for (j=0; j<filter->y.n; j++) { if (y_start < 0) line_bufs[j] = (guchar *)src_buf; else if (y_start < src_height) line_bufs[j] = (guchar *)src_buf + src_rowstride * y_start; else line_bufs[j] = (guchar *)src_buf + src_rowstride * (src_height - 1); y_start++; } dest_x = check_x; x = render_x0 * x_step + scaled_x_offset; x_start = x >> SCALE_SHIFT; while (x_start < 0 && outbuf < outbuf_end) { process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n, outbuf, dest_x, dest_channels, dest_has_alpha, line_bufs, src_channels, src_has_alpha, x >> SCALE_SHIFT, src_width, check_size, tcolor1, tcolor2, pixel_func); x += x_step; x_start = x >> SCALE_SHIFT; dest_x++; outbuf += dest_channels; } new_outbuf = (*line_func) (run_weights, filter->x.n, filter->y.n, outbuf, dest_x, dest_buf + dest_rowstride * i + run_end_index * dest_channels, dest_channels, dest_has_alpha, line_bufs, src_channels, src_has_alpha, x, x_step, src_width, check_size, tcolor1, tcolor2); dest_x += (new_outbuf - outbuf) / dest_channels; x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset; outbuf = new_outbuf; while (outbuf < outbuf_end) { process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n, outbuf, dest_x, dest_channels, dest_has_alpha, line_bufs, src_channels, src_has_alpha, x >> SCALE_SHIFT, src_width, check_size, tcolor1, tcolor2, pixel_func); x += x_step; dest_x++; outbuf += dest_channels; } y += y_step; } g_free (line_bufs); g_free (filter_weights);}/* Compute weights for reconstruction by replication followed by * sampling with a box filter */static voidtile_make_weights (PixopsFilterDimension *dim, double scale){ int n = ceil (1 / scale + 1); double *pixel_weights = g_new (double, SUBSAMPLE * n); int offset; int i; dim->n = n; dim->offset = 0; dim->weights = pixel_weights; for (offset = 0; offset < SUBSAMPLE; offset++) { double x = (double)offset / SUBSAMPLE; double a = x + 1 / scale; for (i = 0; i < n; i++) { if (i < x) { if (i + 1 > x) *(pixel_weights++) = (MIN (i + 1, a) - x) * scale; else *(pixel_weights++) = 0; } else { if (a > i) *(pixel_weights++) = (MIN (i + 1, a) - i) * scale; else *(pixel_weights++) = 0; } } }}/* Compute weights for a filter that, for minification * is the same as 'tiles', and for magnification, is bilinear * reconstruction followed by a sampling with a delta function. */static voidbilinear_magnify_make_weights (PixopsFilterDimension *dim, double scale){ double *pixel_weights; int n; int offset; int i; if (scale > 1.0) /* Linear */ { n = 2; dim->offset = 0.5 * (1 / scale - 1); } else /* Tile */ { n = ceil (1.0 + 1.0 / scale); dim->offset = 0.0; } dim->n = n; dim->weights = g_new (double, SUBSAMPLE * n); pixel_weights = dim->weights; for (offset=0; offset < SUBSAMPLE; offset++) { double x = (double)offset / SUBSAMPLE; if (scale > 1.0) /* Linear */ { for (i = 0; i < n; i++) *(pixel_weights++) = (((i == 0) ? (1 - x) : x) / scale) * scale; } else /* Tile */ { double a = x + 1 / scale; /* x * ---------|--.-|----|--.-|------- SRC * ------------|---------|--------- DEST */ for (i = 0; i < n; i++) { if (i < x) { if (i + 1 > x) *(pixel_weights++) = (MIN (i + 1, a) - x) * scale; else *(pixel_weights++) = 0; } else { if (a > i) *(pixel_weights++) = (MIN (i + 1, a) - i) * scale; else *(pixel_weights++) = 0; } } } }}/* Computes the integral from b0 to b1 of * * f(x) = x; 0 <= x < 1 * f(x) = 0; otherwise * * We combine two of these to compute the convolution of * a box filter with a triangular spike. */static doublelinear_box_half (double b0, double b1){ double a0, a1; double x0, x1; a0 = 0.; a1 = 1.; if (a0 < b0) { if (a1 > b0) { x0 = b0; x1 = MIN (a1, b1); } else return 0; } else { if (b1 > a0) { x0 = a0; x1 = MIN (a1, b1); } else return 0; } return 0.5 * (x1*x1 - x0*x0);}/* Compute weights for reconstructing with bilinear * interpolation, then sampling with a box filter */static voidbilinear_box_make_weights (PixopsFilterDimension *dim, double scale){ int n = ceil (1/scale + 3.0); double *pixel_weights = g_new (double, SUBSAMPLE * n); double w; int offset, i; dim->offset = -1.0; dim->n = n; dim->weights = pixel_weights; for (offset = 0; offset < SUBSAMPLE; offset++) { double x = (double)offset / SUBSAMPLE; double a = x + 1 / scale; for (i = 0; i < n; i++) { w = linear_box_half (0.5 + i - a, 0.5 + i - x); w += linear_box_half (1.5 + x - i, 1.5 + a - i); *(pixel_weights++) = w * scale; } }}static voidmake_weights (PixopsFilter *filter, PixopsInterpType interp_type, double scale_x, double scale_y){ switch (interp_type) { case PIXOPS_INTERP_NEAREST: g_assert_not_reached (); break; case PIXOPS_INTERP_TILES: tile_make_weights (&filter->x, scale_x); tile_make_weights (&filter->y, scale_y); break; case PIXOPS_INTERP_BILINEAR: bilinear_magnify_make_weights (&filter->x, scale_x); bilinear_magnify_make_weights (&filter->y, scale_y); break; case PIXOPS_INTERP_HYPER: bilinear_box_make_weights (&filter->x, scale_x); bilinear_box_make_weights (&filter->y, scale_y); break; }}void_pixops_composite_color (guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, gboolean dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, gboolean src_has_alpha, double scale_x, double scale_y, PixopsInterpType interp_type, int overall_alpha, int check_x, int check_y, int check_size, guint32 color1, guint32 color2){ PixopsFilter filter; PixopsLineFunc line_func; #ifdef USE_MMX gboolean found_mmx = _pixops_have_mmx ();#endif g_return_if_fail (!(dest_channels == 3 && dest_has_alpha)); g_return_if_fail (!(src_channels == 3 && src_has_alpha)); if (scale_x == 0 || scale_y == 0) return; if (!src_has_alpha && overall_alpha == 255) { _pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, interp_type); return; } if (interp_type == PIXOPS_INTERP_NEAREST) { pixops_composite_color_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, overall_alpha, check_x, check_y, check_size, color1, color2); return; } filter.overall_alpha = overall_alpha / 255.; make_weights (&filter, interp_type, scale_x, scale_y);#ifdef USE_MMX if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha && found_mmx) line_func = composite_line_color_22_4a4_mmx_stub; else#endif line_func = composite_line_color; pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2, &filter, line_func, composite_pixel_color); g_free (filter.x.weights); g_free (filter.y.weights);}/** * _pixops_composite: * @dest_buf: pointer to location to store result * @render_x0: x0 of region of scaled source to store into @dest_buf * @render_y0: y0 of region of scaled source to store into @dest_buf * @render_x1: x1 of region of scaled source to store into @dest_buf * @render_y1: y1 of region of scaled source to store into @dest_buf * @dest_rowstride: rowstride of @dest_buf * @dest_channels: number of channels in @dest_buf * @dest_has_alpha: whether @dest_buf has alpha * @src_buf: pointer to source pixels * @src_width: width of source (used for clipping) * @src_height: height of source (used for clipping) * @src_rowstride: rowstride of source * @src_channels: number of channels in @src_buf * @src_has_alpha: whether @src_buf has alpha * @scale_x: amount to scale source by in X direction * @scale_y: amount to scale source by in Y direction * @interp_type: type of enumeration * @overall_alpha: overall alpha factor to multiply source by * * Scale source buffer by scale_x / scale_y, then composite a given rectangle * of the result into the destination buffer. **/void_pixops_composite (guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, gboolean dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, gboolean src_has_alpha, double scale_x, double scale_y, PixopsInterpType interp_type, int overall_alpha){ PixopsFilter filter; PixopsLineFunc line_func; #ifdef USE_MMX gboolean found_mmx = _pixops_have_mmx ();#endif g_return_if_fail (!(dest_channels == 3 && dest_has_alpha)); g_return_if_fail (!(src_channels == 3 && src_has_alpha)); if (scale_x == 0 || scale_y == 0) return; if (!src_has_alpha && overall_alpha == 255) { _pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, interp_type); return; } if (interp_type == PIXOPS_INTERP_NEAREST) { pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, overall_alpha); return; } filter.overall_alpha = overall_alpha / 255.; make_weights (&filter, interp_type, scale_x, scale_y); if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha) {#ifdef USE_MMX if (found_mmx) line_func = composite_line_22_4a4_mmx_stub; else#endif line_func = composite_line_22_4a4; } else line_func = composite_line; pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, &filter, line_func, composite_pixel); g_free (filter.x.weights); g_free (filter.y.weights);}void_pixops_scale (guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, gboolean dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, gboolean src_has_alpha, double scale_x, double scale_y, PixopsInterpType interp_type){ PixopsFilter filter; PixopsLineFunc line_func;#ifdef USE_MMX gboolean found_mmx = _pixops_have_mmx ();#endif g_return_if_fail (!(dest_channels == 3 && dest_has_alpha)); g_return_if_fail (!(src_channels == 3 && src_has_alpha)); g_return_if_fail (!(src_has_alpha && !dest_has_alpha)); if (scale_x == 0 || scale_y == 0) return; if (interp_type == PIXOPS_INTERP_NEAREST) { pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y); return; } filter.overall_alpha = 1.0; make_weights (&filter, interp_type, scale_x, scale_y); if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 3 && src_channels == 3) {#ifdef USE_MMX if (found_mmx) line_func = scale_line_22_33_mmx_stub; else#endif line_func = scale_line_22_33; } else line_func = scale_line; pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, &filter, line_func, scale_pixel); g_free (filter.x.weights); g_free (filter.y.weights);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -