Ticket #6: image.patch
| File image.patch, 11.8 KB (added by , 6 days ago) |
|---|
-
gtk/dw.c
9221 9221 DW_MUTEX_LOCK; 9222 9222 #if GTK_MAJOR_VERSION > 1 9223 9223 pixmap->pixbuf = gdk_pixbuf_new_from_file(file, NULL); 9224 if(!pixmap->pixbuf) 9225 { 9226 free(pixmap); 9227 DW_MUTEX_UNLOCK; 9228 return NULL; 9229 } 9224 9230 pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf); 9225 9231 pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf); 9226 9232 gdk_pixbuf_render_pixmap_and_mask(pixmap->pixbuf, &pixmap->pixmap, &pixmap->bitmap, 1); … … 9262 9268 #endif 9263 9269 char template[] = "/tmp/dwpixmapXXXXXX"; 9264 9270 9265 if(!data || !(pixmap = calloc(1,sizeof(struct _hpixmap))))9271 if(!data || len < 1 || !(pixmap = calloc(1,sizeof(struct _hpixmap)))) 9266 9272 return NULL; 9267 9273 9268 9274 DW_MUTEX_LOCK; … … 9278 9284 /* Bail if we couldn't write full file */ 9279 9285 if(fd == -1 || written != len) 9280 9286 { 9287 if(fd != -1) 9288 unlink(template); 9289 free(pixmap); 9281 9290 DW_MUTEX_UNLOCK; 9282 return 0;9291 return NULL; 9283 9292 } 9284 9293 #if GTK_MAJOR_VERSION > 1 9285 9294 pixbuf = gdk_pixbuf_new_from_file(template, NULL); 9295 if(!pixbuf) 9296 { 9297 unlink(template); 9298 free(pixmap); 9299 DW_MUTEX_UNLOCK; 9300 return NULL; 9301 } 9286 9302 pixmap->width = gdk_pixbuf_get_width(pixbuf); 9287 9303 pixmap->height = gdk_pixbuf_get_height(pixbuf); 9288 9304 gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap->pixmap, &pixmap->bitmap, 1); -
gtk3/dw.c
8263 8263 return 0; 8264 8264 } 8265 8265 pixmap->pixbuf = gdk_pixbuf_new_from_file(template, NULL); 8266 pixmap->image = cairo_image_surface_create_from_png(template); 8267 pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf); 8268 pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf); 8266 /* Decode once with GdkPixbuf, then create the Cairo drawing surface from 8267 * that decoded image. cairo_image_surface_create_from_png() made the 8268 * previous implementation silently PNG-only for drawing even though 8269 * GdkPixbuf had successfully decoded GIF, JPEG and other formats. */ 8270 if(pixmap->pixbuf) 8271 { 8272 pixmap->image = gdk_cairo_surface_create_from_pixbuf(pixmap->pixbuf, 1, NULL); 8273 pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf); 8274 pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf); 8275 } 8269 8276 /* remove our temporary file */ 8270 8277 unlink(template); 8278 if(!pixmap->pixbuf || !pixmap->image || 8279 cairo_surface_status(pixmap->image) != CAIRO_STATUS_SUCCESS) 8280 { 8281 if(pixmap->pixbuf) 8282 g_object_unref(pixmap->pixbuf); 8283 if(pixmap->image) 8284 cairo_surface_destroy(pixmap->image); 8285 free(pixmap); 8286 DW_MUTEX_UNLOCK; 8287 return NULL; 8288 } 8271 8289 pixmap->handle = handle; 8272 8290 DW_MUTEX_UNLOCK; 8273 8291 return pixmap; -
gtk4/dw.c
9026 9026 DW_FUNCTION_RETURN_NOTHING; 9027 9027 } 9028 9028 9029 /* Internal function to copy a decoded GdkTexture into a new ARGB32 Cairo surface. */ 9030 static cairo_surface_t *_dw_surface_from_texture(GdkTexture *texture) 9031 { 9032 cairo_surface_t *surface; 9033 9034 if(!texture) 9035 return NULL; 9036 9037 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 9038 gdk_texture_get_width(texture), 9039 gdk_texture_get_height(texture)); 9040 if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) 9041 { 9042 cairo_surface_destroy(surface); 9043 return NULL; 9044 } 9045 gdk_texture_download(texture, cairo_image_surface_get_data(surface), 9046 cairo_image_surface_get_stride(surface)); 9047 cairo_surface_mark_dirty(surface); 9048 return surface; 9049 } 9050 9051 /* Internal function to copy a decoded GdkPixbuf into a new ARGB32 Cairo surface. 9052 * Converted by hand to a premultiplied native-endian ARGB32 so it does not 9053 * depend on any GdkPixbuf/Cairo helper that GTK 4 may deprecate. 9054 */ 9055 static cairo_surface_t *_dw_surface_from_pixbuf(GdkPixbuf *pixbuf) 9056 { 9057 cairo_surface_t *surface; 9058 const guchar *src; 9059 guchar *dst; 9060 int x, y, width, height, srcstride, dststride, channels; 9061 9062 if(!pixbuf || gdk_pixbuf_get_colorspace(pixbuf) != GDK_COLORSPACE_RGB || 9063 gdk_pixbuf_get_bits_per_sample(pixbuf) != 8) 9064 return NULL; 9065 9066 channels = gdk_pixbuf_get_n_channels(pixbuf); 9067 if(channels < 3) 9068 return NULL; 9069 9070 width = gdk_pixbuf_get_width(pixbuf); 9071 height = gdk_pixbuf_get_height(pixbuf); 9072 srcstride = gdk_pixbuf_get_rowstride(pixbuf); 9073 src = gdk_pixbuf_read_pixels(pixbuf); 9074 9075 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 9076 if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) 9077 { 9078 cairo_surface_destroy(surface); 9079 return NULL; 9080 } 9081 cairo_surface_flush(surface); 9082 dst = cairo_image_surface_get_data(surface); 9083 dststride = cairo_image_surface_get_stride(surface); 9084 9085 for(y = 0; y < height; y++) 9086 { 9087 const guchar *s = src + (size_t)y * srcstride; 9088 guint32 *d = (guint32 *)(dst + (size_t)y * dststride); 9089 9090 for(x = 0; x < width; x++, s += channels) 9091 { 9092 guint32 a = (channels == 4) ? s[3] : 255; 9093 guint32 r = (s[0] * a + 127) / 255; 9094 guint32 g = (s[1] * a + 127) / 255; 9095 guint32 b = (s[2] * a + 127) / 255; 9096 9097 d[x] = (a << 24) | (r << 16) | (g << 8) | b; 9098 } 9099 } 9100 cairo_surface_mark_dirty(surface); 9101 return surface; 9102 } 9103 9104 /* Internal function to create a Cairo surface from image data in memory. 9105 * GdkTexture is tried first (PNG, JPEG and TIFF are guaranteed), then 9106 * gdk-pixbuf is used for anything else it has a loader for (GIF, BMP, ICO, 9107 * WebP with webp-pixbuf-loader, ...). Animations yield the first frame. 9108 */ 9109 static cairo_surface_t *_dw_surface_from_memory(const char *data, gsize len) 9110 { 9111 cairo_surface_t *surface = NULL; 9112 GBytes *bytes = g_bytes_new(data, len); 9113 GdkTexture *texture = gdk_texture_new_from_bytes(bytes, NULL); 9114 9115 g_bytes_unref(bytes); 9116 if(texture) 9117 { 9118 surface = _dw_surface_from_texture(texture); 9119 g_object_unref(G_OBJECT(texture)); 9120 } 9121 else 9122 { 9123 GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); 9124 9125 if(loader) 9126 { 9127 GError *error = NULL; 9128 gboolean ok = gdk_pixbuf_loader_write(loader, (const guchar *)data, len, &error); 9129 9130 g_clear_error(&error); 9131 /* Always close the loader, even after a failed write */ 9132 if(!gdk_pixbuf_loader_close(loader, &error)) 9133 ok = FALSE; 9134 g_clear_error(&error); 9135 if(ok) 9136 surface = _dw_surface_from_pixbuf(gdk_pixbuf_loader_get_pixbuf(loader)); 9137 g_object_unref(G_OBJECT(loader)); 9138 } 9139 } 9140 return surface; 9141 } 9142 9143 /* Internal function to create a Cairo surface from an image file, 9144 * with the same GdkTexture then gdk-pixbuf fallback order. 9145 */ 9146 static cairo_surface_t *_dw_surface_from_file(const char *file) 9147 { 9148 cairo_surface_t *surface = NULL; 9149 GdkTexture *texture = gdk_texture_new_from_filename(file, NULL); 9150 9151 if(texture) 9152 { 9153 surface = _dw_surface_from_texture(texture); 9154 g_object_unref(G_OBJECT(texture)); 9155 } 9156 else 9157 { 9158 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, NULL); 9159 9160 if(pixbuf) 9161 { 9162 surface = _dw_surface_from_pixbuf(pixbuf); 9163 g_object_unref(G_OBJECT(pixbuf)); 9164 } 9165 } 9166 return surface; 9167 } 9168 9029 9169 /* 9030 9170 * Creates a pixmap with given parameters. 9031 9171 * Parameters: … … 9078 9218 if(filename && *filename && (pixmap = calloc(1,sizeof(struct _hpixmap)))) 9079 9219 { 9080 9220 char *file = alloca(strlen(filename) + 6); 9081 GdkTexture *texture = NULL;9082 9221 9083 9222 strcpy(file, filename); 9084 9223 … … 9088 9227 int i = 0; 9089 9228 9090 9229 /* Try with various extentions */ 9091 while(_dw_image_exts[i] && ! texture)9230 while(_dw_image_exts[i] && !pixmap->image) 9092 9231 { 9093 9232 strcpy(file, filename); 9094 9233 strcat(file, _dw_image_exts[i]); 9095 9234 if(access(file, 04) == 0) 9096 texture = gdk_texture_new_from_filename(file, NULL);9235 pixmap->image = _dw_surface_from_file(file); 9097 9236 i++; 9098 9237 } 9099 9238 } 9100 9239 else 9101 texture = gdk_texture_new_from_filename(file, NULL);9240 pixmap->image = _dw_surface_from_file(file); 9102 9241 9103 if( texture)9242 if(pixmap->image) 9104 9243 { 9105 pixmap->width = gdk_texture_get_width(texture); 9106 pixmap->height = gdk_texture_get_height(texture); 9107 pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 9108 pixmap->width, 9109 pixmap->height); 9110 gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 9111 cairo_image_surface_get_stride(pixmap->image)); 9112 cairo_surface_mark_dirty(pixmap->image); 9244 pixmap->width = cairo_image_surface_get_width(pixmap->image); 9245 pixmap->height = cairo_image_surface_get_height(pixmap->image); 9113 9246 pixmap->handle = handle; 9114 g_object_unref(G_OBJECT(texture));9115 9247 } 9116 9248 else 9117 9249 { … … 9141 9273 9142 9274 if(data && len > 0 && (pixmap = calloc(1,sizeof(struct _hpixmap)))) 9143 9275 { 9144 int fd, written = -1; 9145 char template[] = "/tmp/dwpixmapXXXXXX"; 9146 GdkTexture *texture; 9147 9148 /* 9149 * A real hack; create a temporary file and write the contents 9150 * of the data to the file 9151 */ 9152 if((fd = mkstemp(template)) != -1) 9276 /* Decode directly from memory, no temporary file required */ 9277 if((pixmap->image = _dw_surface_from_memory(data, (gsize)len))) 9153 9278 { 9154 written = write(fd, data, len); 9155 close(fd); 9156 } 9157 /* Bail if we couldn't write full file */ 9158 if(fd != -1 && written == len && 9159 (texture = gdk_texture_new_from_filename(template, NULL))) 9160 { 9161 pixmap->width = gdk_texture_get_width(texture); 9162 pixmap->height = gdk_texture_get_height(texture); 9163 pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 9164 pixmap->width, pixmap->height); 9165 gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 9166 cairo_image_surface_get_stride(pixmap->image)); 9167 cairo_surface_mark_dirty(pixmap->image); 9168 /* remove our temporary file */ 9169 unlink(template); 9279 pixmap->width = cairo_image_surface_get_width(pixmap->image); 9280 pixmap->height = cairo_image_surface_get_height(pixmap->image); 9170 9281 pixmap->handle = handle; 9171 g_object_unref(G_OBJECT(texture));9172 9282 } 9173 9283 else 9174 9284 { … … 9210 9320 if((pixmap = calloc(1,sizeof(struct _hpixmap)))) 9211 9321 { 9212 9322 GdkTexture *texture = _dw_find_texture((HICN)id, 0, 0); 9213 pixmap->width = gdk_texture_get_width(texture); 9214 pixmap->height = gdk_texture_get_height(texture); 9215 pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 9216 pixmap->width, pixmap->height); 9217 gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 9218 cairo_image_surface_get_stride(pixmap->image)); 9219 cairo_surface_mark_dirty(pixmap->image); 9220 pixmap->handle = handle; 9221 g_object_unref(G_OBJECT(texture)); 9323 9324 if(texture && (pixmap->image = _dw_surface_from_texture(texture))) 9325 { 9326 pixmap->width = gdk_texture_get_width(texture); 9327 pixmap->height = gdk_texture_get_height(texture); 9328 pixmap->handle = handle; 9329 } 9330 else 9331 { 9332 free(pixmap); 9333 pixmap = 0; 9334 } 9335 if(texture) 9336 g_object_unref(G_OBJECT(texture)); 9222 9337 } 9223 9338 DW_FUNCTION_RETURN_THIS(pixmap); 9224 9339 }
