📄 pixbuf-render.c
字号:
/* GTK+ Pixbuf Engine * Copyright (C) 1998-2000 Red Hat, Inc. * * This 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. * * This 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. * * Written by Owen Taylor <otaylor@redhat.com>, based on code by * Carsten Haitzler <raster@rasterman.com> */#include <string.h>#include "pixbuf.h"#include <gdk-pixbuf/gdk-pixbuf.h>static GCache *pixbuf_cache = NULL;static GdkPixbuf *bilinear_gradient (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guint src_rowstride = gdk_pixbuf_get_rowstride (src); guchar *src_pixels = gdk_pixbuf_get_pixels (src); guchar *p1, *p2, *p3, *p4; guint dest_rowstride; guchar *dest_pixels; GdkPixbuf *result; int i, j, k; if (src_x == 0 || src_y == 0) { g_warning ("invalid source position for bilinear gradient\n"); return NULL; } p1 = src_pixels + (src_y - 1) * src_rowstride + (src_x - 1) * n_channels; p2 = p1 + n_channels; p3 = src_pixels + src_y * src_rowstride + (src_x - 1) * n_channels; p4 = p3 + n_channels; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { guchar *p = dest_pixels + dest_rowstride *i; guint v[4]; gint dv[4]; for (k = 0; k < n_channels; k++) { guint start = ((height - i) * p1[k] + (1 + i) * p3[k]) / (height + 1); guint end = ((height - i) * p2[k] + (1 + i) * p4[k]) / (height + 1); dv[k] = (((gint)end - (gint)start) << 16) / (width + 1); v[k] = (start << 16) + dv[k] + 0x8000; } for (j = width; j; j--) { for (k = 0; k < n_channels; k++) { *(p++) = v[k] >> 16; v[k] += dv[k]; } } } return result;}static GdkPixbuf *horizontal_gradient (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guint src_rowstride = gdk_pixbuf_get_rowstride (src); guchar *src_pixels = gdk_pixbuf_get_pixels (src); guint dest_rowstride; guchar *dest_pixels; GdkPixbuf *result; int i, j, k; if (src_x == 0) { g_warning ("invalid source position for horizontal gradient\n"); return NULL; } result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { guchar *p = dest_pixels + dest_rowstride *i; guchar *p1 = src_pixels + (src_y + i) * src_rowstride + (src_x - 1) * n_channels; guchar *p2 = p1 + n_channels; guint v[4]; gint dv[4]; for (k = 0; k < n_channels; k++) { dv[k] = (((gint)p2[k] - (gint)p1[k]) << 16) / (width + 1); v[k] = (p1[k] << 16) + dv[k] + 0x8000; } for (j = width; j; j--) { for (k = 0; k < n_channels; k++) { *(p++) = v[k] >> 16; v[k] += dv[k]; } } } return result;}static GdkPixbuf *vertical_gradient (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guint src_rowstride = gdk_pixbuf_get_rowstride (src); guchar *src_pixels = gdk_pixbuf_get_pixels (src); guchar *top_pixels, *bottom_pixels; guint dest_rowstride; guchar *dest_pixels; GdkPixbuf *result; int i, j; if (src_y == 0) { g_warning ("invalid source position for vertical gradient\n"); return NULL; } top_pixels = src_pixels + (src_y - 1) * src_rowstride + (src_x) * n_channels; bottom_pixels = top_pixels + src_rowstride; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { guchar *p = dest_pixels + dest_rowstride *i; guchar *p1 = top_pixels; guchar *p2 = bottom_pixels; for (j = width * n_channels; j; j--) *(p++) = ((height - i) * *(p1++) + (1 + i) * *(p2++)) / (height + 1); } return result;}static GdkPixbuf *replicate_single (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * gdk_pixbuf_get_rowstride (src) + src_x * n_channels); guchar r = *(pixels++); guchar g = *(pixels++); guchar b = *(pixels++); guint dest_rowstride; guchar *dest_pixels; guchar a = 0; GdkPixbuf *result; int i, j; if (n_channels == 4) a = *(pixels++); result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { guchar *p = dest_pixels + dest_rowstride *i; for (j = 0; j < width; j++) { *(p++) = r; *(p++) = g; *(p++) = b; if (n_channels == 4) *(p++) = a; } } return result;}static GdkPixbuf *replicate_rows (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guint src_rowstride = gdk_pixbuf_get_rowstride (src); guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels); guchar *dest_pixels; GdkPixbuf *result; guint dest_rowstride; int i; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width); return result;}static GdkPixbuf *replicate_cols (GdkPixbuf *src, gint src_x, gint src_y, gint width, gint height){ guint n_channels = gdk_pixbuf_get_n_channels (src); guint src_rowstride = gdk_pixbuf_get_rowstride (src); guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels); guchar *dest_pixels; GdkPixbuf *result; guint dest_rowstride; int i, j; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { guchar *p = dest_pixels + dest_rowstride * i; guchar *q = pixels + src_rowstride * i; guchar r = *(q++); guchar g = *(q++); guchar b = *(q++); guchar a = 0; if (n_channels == 4) a = *(q++); for (j = 0; j < width; j++) { *(p++) = r; *(p++) = g; *(p++) = b; if (n_channels == 4) *(p++) = a; } } return result;}/* Scale the rectangle (src_x, src_y, src_width, src_height) * onto the rectangle (dest_x, dest_y, dest_width, dest_height) * of the destination, clip by clip_rect and render */static voidpixbuf_render (GdkPixbuf *src, guint hints, GdkWindow *window, GdkBitmap *mask, GdkRectangle *clip_rect, gint src_x, gint src_y, gint src_width, gint src_height, gint dest_x, gint dest_y, gint dest_width, gint dest_height){ GdkPixbuf *tmp_pixbuf = NULL; GdkRectangle rect; int x_offset, y_offset; gboolean has_alpha = gdk_pixbuf_get_has_alpha (src); gint src_rowstride = gdk_pixbuf_get_rowstride (src); gint src_n_channels = gdk_pixbuf_get_n_channels (src); if (dest_width <= 0 || dest_height <= 0) return; rect.x = dest_x; rect.y = dest_y; rect.width = dest_width; rect.height = dest_height; if (hints & THEME_MISSING) return; /* FIXME: Because we use the mask to shape windows, we don't use * clip_rect to clip what we draw to the mask, only to clip * what we actually draw. But this leads to the horrible ineffiency * of scale the whole image to get a little bit of it. */ if (!mask && clip_rect) { if (!gdk_rectangle_intersect (clip_rect, &rect, &rect)) return; } if (dest_width == src_width && dest_height == src_height) { tmp_pixbuf = g_object_ref (src); x_offset = src_x + rect.x - dest_x; y_offset = src_y + rect.y - dest_y; } else if (src_width == 0 && src_height == 0) { tmp_pixbuf = bilinear_gradient (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if (src_width == 0 && dest_height == src_height) { tmp_pixbuf = horizontal_gradient (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if (src_height == 0 && dest_width == src_width) { tmp_pixbuf = vertical_gradient (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if ((hints & THEME_CONSTANT_COLS) && (hints & THEME_CONSTANT_ROWS)) { tmp_pixbuf = replicate_single (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if (dest_width == src_width && (hints & THEME_CONSTANT_COLS)) { tmp_pixbuf = replicate_rows (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if (dest_height == src_height && (hints & THEME_CONSTANT_ROWS)) { tmp_pixbuf = replicate_cols (src, src_x, src_y, dest_width, dest_height); x_offset = rect.x - dest_x; y_offset = rect.y - dest_y; } else if (src_width > 0 && src_height > 0) { double x_scale = (double)dest_width / src_width; double y_scale = (double)dest_height / src_height; guchar *pixels; GdkPixbuf *partial_src; pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * src_n_channels); partial_src = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8, src_width, src_height, src_rowstride, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -