/* Compares two CAIRO_FORMAT_ARGB32 buffers, returning NULL if the * buffers are equal or a surface containing a diff between the two * surfaces. * * This function should be rewritten to compare all formats supported by * cairo_format_t instead of taking a mask as a parameter. * * This function is originally from cairo:test/buffer-diff.c. * Copyright © 2004 Richard D. Worth */ static cairo_surface_t * buffer_diff_core (const guchar *buf_a, int stride_a, const guchar *buf_b, int stride_b, int width, int height) { int x, y; guchar *buf_diff = NULL; int stride_diff = 0; cairo_surface_t *diff = NULL; for (y = 0; y < height; y++) { const guint32 *row_a = (const guint32 *) (buf_a + y * stride_a); const guint32 *row_b = (const guint32 *) (buf_b + y * stride_b); guint32 *row = (guint32 *) (buf_diff + y * stride_diff); for (x = 0; x < width; x++) { int channel; guint32 diff_pixel = 0; /* check if the pixels are the same */ if (row_a[x] == row_b[x]) continue; if (diff == NULL) { diff = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); g_assert (cairo_surface_status (diff) == CAIRO_STATUS_SUCCESS); buf_diff = cairo_image_surface_get_data (diff); stride_diff = cairo_image_surface_get_stride (diff); row = (guint32 *) (buf_diff + y * stride_diff); } /* calculate a difference value for all 4 channels */ for (channel = 0; channel < 4; channel++) { int value_a = (row_a[x] >> (channel*8)) & 0xff; int value_b = (row_b[x] >> (channel*8)) & 0xff; guint diff; diff = ABS (value_a - value_b); diff *= 4; /* emphasize */ if (diff) diff += 128; /* make sure it's visible */ if (diff > 255) diff = 255; diff_pixel |= diff << (channel*8); } if ((diff_pixel & 0x00ffffff) == 0) { /* alpha only difference, convert to luminance */ guint8 alpha = diff_pixel >> 24; diff_pixel = alpha * 0x010101; } row[x] = diff_pixel; } }
static PyObject * image_surface_get_stride (PycairoImageSurface *o) { return PyInt_FromLong (cairo_image_surface_get_stride (o->surface)); }
void setup_tile (gint w, gint h) { cairo_status_t status; cairo_t* cr = NULL; cairo_surface_t* cr_surf = NULL; cairo_surface_t* tmp = NULL; cairo_surface_t* dummy_surf = NULL; cairo_surface_t* norm_surf = NULL; cairo_surface_t* blur_surf = NULL; gdouble width = (gdouble) w; gdouble height = (gdouble) h; raico_blur_t* blur = NULL; cr_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE); status = cairo_surface_status (cr_surf); if (status != CAIRO_STATUS_SUCCESS) g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); cr = cairo_create (cr_surf); status = cairo_status (cr); if (status != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (cr_surf); g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); } // clear and render drop-shadow and bubble-background cairo_scale (cr, 1.0f, 1.0f); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); if (g_composited) { draw_shadow (cr, width, height, BUBBLE_SHADOW_SIZE, CORNER_RADIUS); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); draw_round_rect (cr, 1.0f, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f* BUBBLE_SHADOW_SIZE)); cairo_fill (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B, 0.95f); } else cairo_set_source_rgb (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B); draw_round_rect (cr, 1.0f, BUBBLE_SHADOW_SIZE, BUBBLE_SHADOW_SIZE, CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f * BUBBLE_SHADOW_SIZE)); cairo_fill (cr); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (cr_surf), cairo_image_surface_get_format (cr_surf), 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (cr_surf)); dummy_surf = copy_surface (tmp); cairo_surface_destroy (tmp); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); norm_surf = copy_surface (tmp); cairo_surface_destroy (tmp); blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW); raico_blur_set_radius (blur, 6); raico_blur_apply (blur, dummy_surf); raico_blur_destroy (blur); tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); blur_surf = copy_surface (tmp); cairo_surface_destroy (tmp); cairo_surface_destroy (dummy_surf); g_tile = tile_new_for_padding (norm_surf, blur_surf); cairo_surface_destroy (norm_surf); cairo_surface_destroy (blur_surf); cairo_surface_destroy (cr_surf); cairo_destroy (cr); }
/* * Arguments: * 1) .node file to compare * 2) .png file to compare the rendered .node file to */ int main (int argc, char **argv) { cairo_surface_t *reference_surface = NULL; cairo_surface_t *rendered_surface = NULL; cairo_surface_t *diff_surface = NULL; GdkTexture *texture; GskRenderer *renderer; GdkSurface *window; GskRenderNode *node; const char *node_file; const char *png_file; g_assert (argc == 3); gtk_init (); node_file = argv[1]; png_file = argv[2]; window = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10); renderer = gsk_renderer_new_for_surface (window); g_test_message ("Node file: '%s'\n", node_file); g_test_message ("PNG file: '%s'\n", png_file); /* Load the render node from the given .node file */ { GBytes *bytes; GError *error = NULL; gsize len; char *contents; if (!g_file_get_contents (node_file, &contents, &len, &error)) { g_test_message ("Could not open node file: %s\n", error->message); g_clear_error (&error); g_test_fail (); return -1; } bytes = g_bytes_new_take (contents, len); node = gsk_render_node_deserialize (bytes, &error); g_bytes_unref (bytes); g_assert (node != NULL); } /* Render the .node file and download to cairo surface */ texture = gsk_renderer_render_texture (renderer, node, NULL); g_assert (texture != NULL); rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); gdk_texture_download (texture, cairo_image_surface_get_data (rendered_surface), cairo_image_surface_get_stride (rendered_surface)); cairo_surface_mark_dirty (rendered_surface); /* Load the given reference png file */ reference_surface = cairo_image_surface_create_from_png (png_file); g_assert (reference_surface != NULL); /* Now compare the two */ diff_surface = reftest_compare_surfaces (rendered_surface, reference_surface); save_image (rendered_surface, node_file, ".out.png"); if (diff_surface) save_image (diff_surface, node_file, ".diff.png"); g_assert (diff_surface == NULL); return 0; }
static void st_drawing_area_paint (ClutterActor *self) { StDrawingArea *area = ST_DRAWING_AREA (self); StDrawingAreaPrivate *priv = area->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self)); ClutterActorBox allocation_box; ClutterActorBox content_box; int width, height; CoglColor color; guint8 paint_opacity; (CLUTTER_ACTOR_CLASS (st_drawing_area_parent_class))->paint (self); clutter_actor_get_allocation_box (self, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); width = (int)(0.5 + content_box.x2 - content_box.x1); height = (int)(0.5 + content_box.y2 - content_box.y1); if (priv->material == COGL_INVALID_HANDLE) priv->material = cogl_material_new (); if (priv->texture != COGL_INVALID_HANDLE && (width != cogl_texture_get_width (priv->texture) || height != cogl_texture_get_height (priv->texture))) { cogl_handle_unref (priv->texture); priv->texture = COGL_INVALID_HANDLE; } if (width > 0 && height > 0) { if (priv->texture == COGL_INVALID_HANDLE) { priv->texture = st_cogl_texture_new_with_size_wrapper (width, height, COGL_TEXTURE_NONE, CLUTTER_CAIRO_FORMAT_ARGB32); priv->needs_repaint = TRUE; } if (priv->needs_repaint) { cairo_surface_t *surface; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); priv->context = cairo_create (surface); priv->in_repaint = TRUE; priv->needs_repaint = FALSE; g_signal_emit ((GObject*)area, st_drawing_area_signals[REPAINT], 0); priv->in_repaint = FALSE; cairo_destroy (priv->context); priv->context = NULL; cogl_texture_set_region (priv->texture, 0, 0, 0, 0, width, height, width, height, CLUTTER_CAIRO_FORMAT_ARGB32, cairo_image_surface_get_stride (surface), cairo_image_surface_get_data (surface)); cairo_surface_destroy (surface); } } cogl_material_set_layer (priv->material, 0, priv->texture); if (priv->texture) { paint_opacity = clutter_actor_get_paint_opacity (self); cogl_color_set_from_4ub (&color, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_material_set_color (priv->material, &color); cogl_set_source (priv->material); cogl_rectangle_with_texture_coords (content_box.x1, content_box.y1, width, height, 0.0f, 0.0f, 1.0f, 1.0f); } }
void text_rsrc::updatePixels() { scoped_lock< mutex > slock( text_mutex ); text_update_context context; // Set up Cairo then Pango with initial values ///////////////////////////////////////////////////////////////////////////////////////////////////////// if( max_dimensions[ 0 ] < 0 ) dimensions[ 0 ] = PANGOCAIRO_INITIAL_PX_WIDTH; else dimensions[ 0 ] = max_dimensions[ 0 ]; if( max_dimensions[ 1 ] < 0 ) dimensions[ 1 ] = PANGOCAIRO_INITIAL_PX_HEIGHT; else dimensions[ 1 ] = max_dimensions[ 1 ]; updatePixels_setup( &context ); // Redo everything if we need to resize //////////////////////////////////////////////////////////////////////////////////////////////////////////////// if( max_dimensions[ 0 ] < 0 || max_dimensions[ 1 ] < 0 ) { // Get Pango pixel dimensions ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PangoRectangle p_layout_inkrect; pango_layout_get_extents( context.p_layout, &p_layout_inkrect, NULL ); // Make sure we have enough room dimensions[ 0 ] = ceil( ( double )( p_layout_inkrect.width + p_layout_inkrect.x ) / PANGO_SCALE ); dimensions[ 1 ] = ceil( ( double )( p_layout_inkrect.height + p_layout_inkrect.y ) / PANGO_SCALE ); // Clean up Pango then Cairo /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// updatePixels_cleanup( &context ); // Re-set up Cairo then Pango with actual values /////////////////////////////////////////////////////////////////////////////////////////////////// updatePixels_setup( &context ); } // Draw text to surface //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// pango_cairo_show_layout( context.c_context, context.p_layout ); // Render text tex_offset[ 0 ] = 0; tex_offset[ 1 ] = pango_layout_get_baseline( context.p_layout ) / PANGO_SCALE * -1; // Convert Cairo surface to RGBA for OpenGL //////////////////////////////////////////////////////////////////////////////////////////////////////////// if( pixel_space != NULL ) delete[] pixel_space; pixel_space = new unsigned char[ dimensions[ 0 ] * dimensions [ 1 ] * 4 ]; if( pixel_space == NULL ) throw exception( "text_rsrc::updatePixels(): Could not allocate pixel space" ); unsigned char* c_data = cairo_image_surface_get_data( context.c_surf ); int c_stride = cairo_image_surface_get_stride( context.c_surf ); unsigned char* c_pixelp; for( long i = 0; i < dimensions[ 0 ] * dimensions[ 1 ]; ++i ) { if( i % dimensions[ 0 ] == 0 ) c_pixelp = c_data + c_stride * ( i / dimensions[ 0 ] ); // Important since the surface stride might be wider than the surface width pixel_space[ i * 4 + 0 ] = 0xFF; pixel_space[ i * 4 + 1 ] = 0xFF; pixel_space[ i * 4 + 2 ] = 0xFF; pixel_space[ i * 4 + 3 ] = c_pixelp[ i % dimensions[ 0 ] ]; } // Clean up Pango then Cairo /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// updatePixels_cleanup( &context ); }
void blur_surface(cairo_surface_t *surface, int margin) { cairo_surface_t *tmp; int32_t width, height, stride, x, y, z, w; uint8_t *src, *dst; uint32_t *s, *d, a, p; int i, j, k, size = 17, half; uint8_t kernel[100]; double f; width = cairo_image_surface_get_width(surface); height = cairo_image_surface_get_height(surface); stride = cairo_image_surface_get_stride(surface); src = cairo_image_surface_get_data(surface); tmp = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); dst = cairo_image_surface_get_data(tmp); half = size / 2; a = 0; for (i = 0; i < size; i++) { f = (i - half); kernel[i] = exp(- f * f / 30.0) * 80; a += kernel[i]; } for (i = 0; i < height; i++) { s = (uint32_t *) (src + i * stride); d = (uint32_t *) (dst + i * stride); for (j = 0; j < width; j++) { if (margin < j && j < width - margin && margin < i && i < height - margin) continue; x = 0; y = 0; z = 0; w = 0; for (k = 0; k < size; k++) { if (j - half + k < 0 || j - half + k >= width) continue; p = s[j - half + k]; x += (p >> 24) * kernel[k]; y += ((p >> 16) & 0xff) * kernel[k]; z += ((p >> 8) & 0xff) * kernel[k]; w += (p & 0xff) * kernel[k]; } d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; } } for (i = 0; i < height; i++) { s = (uint32_t *) (dst + i * stride); d = (uint32_t *) (src + i * stride); for (j = 0; j < width; j++) { if (margin <= j && j < width - margin && margin <= i && i < height - margin) continue; x = 0; y = 0; z = 0; w = 0; for (k = 0; k < size; k++) { if (i - half + k < 0 || i - half + k >= height) continue; s = (uint32_t *) (dst + (i - half + k) * stride); p = s[j]; x += (p >> 24) * kernel[k]; y += ((p >> 16) & 0xff) * kernel[k]; z += ((p >> 8) & 0xff) * kernel[k]; w += (p & 0xff) * kernel[k]; } d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; } } cairo_surface_destroy(tmp); }
QImage QImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) { Q_UNUSED(size); QUrl dir(id); RsvgDimensionData dimensions; int width = 1; int height = 1; /* Set the locale so that UTF-8 filenames work */ setlocale(LC_ALL, ""); double zoom = 1.0; rsvg_set_default_dpi_x_y (-1, -1); RsvgHandle *rsvg = rsvg_handle_new_from_file(dir.toLocalFile().toStdString().c_str(),NULL); if(rsvg!=NULL) { rsvg_handle_get_dimensions(rsvg, &dimensions); QRect desktop = QRect(0,0,requestedSize.width(),requestedSize.height()); if(dimensions.width!=dimensions.height) { width = (dimensions.width<dimensions.height) ? (double)desktop.height() / (double)dimensions.height * dimensions.width : desktop.width() ; height = (dimensions.height<dimensions.width) ? (double)desktop.width() / (double)dimensions.width * dimensions.height : desktop.height() ; zoom = (width > height) ? (double)width / (double)dimensions.width : (double)height / (double)dimensions.height; } else if(desktop.width() > desktop.height()) { width = desktop.height(); height = desktop.height(); zoom = (double)height / (double)dimensions.height; } else { width = desktop.width(); height = desktop.width(); zoom = (double)width / (double)dimensions.width; } qDebug() << width << "x" << height << ";" << dimensions.width << "x" << dimensions.height << ";" << zoom; } cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(surface); cairo_scale(cr, zoom, zoom); rsvg_handle_render_cairo(rsvg, cr); QImage *source = new QImage( cairo_image_surface_get_data(surface), cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), cairo_image_surface_get_stride(surface), QImage::Format_ARGB32_Premultiplied ); QImage image(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), QImage::Format_ARGB32_Premultiplied); image.fill(qRgba(0, 0, 0, 0)); QPainter painter(&image); painter.drawImage(QPoint(0, 0), *source); delete source; g_object_unref(rsvg); cairo_destroy(cr); cairo_surface_destroy(surface); return image; }
/** * gdk_cairo_draw_from_gl: * @cr: a cairo context * @window: The window we're rendering for (not necessarily into) * @source: The GL ID of the source buffer * @source_type: The type of the @source * @buffer_scale: The scale-factor that the @source buffer is allocated for * @x: The source x position in @source to start copying from in GL coordinates * @y: The source y position in @source to start copying from in GL coordinates * @width: The width of the region to draw * @height: The height of the region to draw * * This is the main way to draw GL content in GTK+. It takes a render buffer ID * (@source_type == #GL_RENDERBUFFER) or a texture id (@source_type == #GL_TEXTURE) * and draws it onto @cr with an OVER operation, respecting the current clip. * The top left corner of the rectangle specified by @x, @y, @width and @height * will be drawn at the current (0,0) position of the cairo_t. * * This will work for *all* cairo_t, as long as @window is realized, but the * fallback implementation that reads back the pixels from the buffer may be * used in the general case. In the case of direct drawing to a window with * no special effects applied to @cr it will however use a more efficient * approach. * * For #GL_RENDERBUFFER the code will always fall back to software for buffers * with alpha components, so make sure you use #GL_TEXTURE if using alpha. * * Calling this may change the current GL context. * * Since: 3.16 */ void gdk_cairo_draw_from_gl (cairo_t *cr, GdkWindow *window, int source, int source_type, int buffer_scale, int x, int y, int width, int height) { GdkGLContext *paint_context; cairo_surface_t *image; cairo_matrix_t matrix; int dx, dy, window_scale; gboolean trivial_transform; cairo_surface_t *group_target; GdkWindow *direct_window, *impl_window; guint framebuffer; int alpha_size = 0; cairo_region_t *clip_region; GdkGLContextPaintData *paint_data; impl_window = window->impl_window; window_scale = gdk_window_get_scale_factor (impl_window); paint_context = gdk_window_get_paint_gl_context (window, NULL); if (paint_context == NULL) { g_warning ("gdk_cairo_draw_gl_render_buffer failed - no paint context"); return; } clip_region = gdk_cairo_region_from_clip (cr); gdk_gl_context_make_current (paint_context); paint_data = gdk_gl_context_get_paint_data (paint_context); if (paint_data->tmp_framebuffer == 0) glGenFramebuffersEXT (1, &paint_data->tmp_framebuffer); if (source_type == GL_RENDERBUFFER) { glBindRenderbuffer (GL_RENDERBUFFER, source); glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size); } else if (source_type == GL_TEXTURE) { glBindTexture (GL_TEXTURE_2D, source); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &alpha_size); } else { g_warning ("Unsupported gl source type %d\n", source_type); return; } group_target = cairo_get_group_target (cr); direct_window = cairo_surface_get_user_data (group_target, &direct_key); cairo_get_matrix (cr, &matrix); dx = matrix.x0; dy = matrix.y0; /* Trivial == integer-only translation */ trivial_transform = (double)dx == matrix.x0 && (double)dy == matrix.y0 && matrix.xx == 1.0 && matrix.xy == 0.0 && matrix.yx == 0.0 && matrix.yy == 1.0; /* For direct paint of non-alpha renderbuffer, we can just do a bitblit */ if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 && source_type == GL_RENDERBUFFER && alpha_size == 0 && direct_window != NULL && direct_window->current_paint.use_gl && trivial_transform && clip_region != NULL) { int unscaled_window_height; int i; /* Create a framebuffer with the source renderbuffer and make it the current target for reads */ framebuffer = paint_data->tmp_framebuffer; glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer); glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, source); glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT, 0); /* Translate to impl coords */ cairo_region_translate (clip_region, dx, dy); glEnable (GL_SCISSOR_TEST); gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height); glDrawBuffer (GL_BACK); #define FLIP_Y(_y) (unscaled_window_height - (_y)) for (i = 0; i < cairo_region_num_rectangles (clip_region); i++) { cairo_rectangle_int_t clip_rect, dest; cairo_region_get_rectangle (clip_region, i, &clip_rect); clip_rect.x *= window_scale; clip_rect.y *= window_scale; clip_rect.width *= window_scale; clip_rect.height *= window_scale; glScissor (clip_rect.x, FLIP_Y (clip_rect.y + clip_rect.height), clip_rect.width, clip_rect.height); dest.x = dx * window_scale; dest.y = dy * window_scale; dest.width = width * window_scale / buffer_scale; dest.height = height * window_scale / buffer_scale; if (gdk_rectangle_intersect (&clip_rect, &dest, &dest)) { int clipped_src_x = x + (dest.x - dx * window_scale); int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale)); glBlitFramebufferEXT(clipped_src_x, clipped_src_y, (clipped_src_x + dest.width), (clipped_src_y + dest.height), dest.x, FLIP_Y(dest.y + dest.height), dest.x + dest.width, FLIP_Y(dest.y), GL_COLOR_BUFFER_BIT, GL_NEAREST); if (impl_window->current_paint.flushed_region) { cairo_rectangle_int_t flushed_rect; flushed_rect.x = dest.x / window_scale; flushed_rect.y = dest.y / window_scale; flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x; flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y; cairo_region_union_rectangle (impl_window->current_paint.flushed_region, &flushed_rect); cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region, &flushed_rect); } } } glDisable (GL_SCISSOR_TEST); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); #undef FLIP_Y } /* For direct paint of alpha or non-alpha textures we can use texturing */ else if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 && source_type == GL_TEXTURE && direct_window != NULL && direct_window->current_paint.use_gl && trivial_transform && clip_region != NULL) { int unscaled_window_height; GLint texture_width; GLint texture_height; int i, n_rects, n_quads; GdkTexturedQuad *quads; cairo_rectangle_int_t clip_rect; /* Translate to impl coords */ cairo_region_translate (clip_region, dx, dy); if (alpha_size != 0) { cairo_region_t *opaque_region, *blend_region; opaque_region = cairo_region_copy (clip_region); cairo_region_subtract (opaque_region, impl_window->current_paint.flushed_region); cairo_region_subtract (opaque_region, impl_window->current_paint.need_blend_region); if (!cairo_region_is_empty (opaque_region)) gdk_gl_texture_from_surface (impl_window->current_paint.surface, opaque_region); blend_region = cairo_region_copy (clip_region); cairo_region_intersect (blend_region, impl_window->current_paint.need_blend_region); glEnable (GL_BLEND); if (!cairo_region_is_empty (blend_region)) gdk_gl_texture_from_surface (impl_window->current_paint.surface, blend_region); cairo_region_destroy (opaque_region); cairo_region_destroy (blend_region); } glBindTexture (GL_TEXTURE_2D, source); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texture_width); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texture_height); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable (GL_SCISSOR_TEST); gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height); #define FLIP_Y(_y) (unscaled_window_height - (_y)) cairo_region_get_extents (clip_region, &clip_rect); glScissor (clip_rect.x * window_scale, FLIP_Y ((clip_rect.y + clip_rect.height) * window_scale), clip_rect.width * window_scale, clip_rect.height * window_scale); n_quads = 0; n_rects = cairo_region_num_rectangles (clip_region); quads = g_new (GdkTexturedQuad, n_rects); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t dest; cairo_region_get_rectangle (clip_region, i, &clip_rect); clip_rect.x *= window_scale; clip_rect.y *= window_scale; clip_rect.width *= window_scale; clip_rect.height *= window_scale; dest.x = dx * window_scale; dest.y = dy * window_scale; dest.width = width * window_scale / buffer_scale; dest.height = height * window_scale / buffer_scale; if (gdk_rectangle_intersect (&clip_rect, &dest, &dest)) { int clipped_src_x = x + (dest.x - dx * window_scale); int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale)); GdkTexturedQuad quad = { dest.x, FLIP_Y(dest.y), dest.x + dest.width, FLIP_Y(dest.y + dest.height), clipped_src_x / (float)texture_width, (clipped_src_y + dest.height) / (float)texture_height, (clipped_src_x + dest.width) / (float)texture_width, clipped_src_y / (float)texture_height, }; quads[n_quads++] = quad; if (impl_window->current_paint.flushed_region) { cairo_rectangle_int_t flushed_rect; flushed_rect.x = dest.x / window_scale; flushed_rect.y = dest.y / window_scale; flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x; flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y; cairo_region_union_rectangle (impl_window->current_paint.flushed_region, &flushed_rect); cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region, &flushed_rect); } } } if (n_quads > 0) gdk_gl_texture_quads (paint_context, GL_TEXTURE_2D, n_quads, quads); g_free (quads); if (alpha_size != 0) glDisable (GL_BLEND); #undef FLIP_Y } else { /* Software fallback */ /* TODO: avoid reading back non-required data due to dest clip */ image = cairo_surface_create_similar_image (cairo_get_target (cr), (alpha_size == 0) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32, width, height); cairo_surface_set_device_scale (image, buffer_scale, buffer_scale); framebuffer = paint_data->tmp_framebuffer; glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer); if (source_type == GL_RENDERBUFFER) { /* Create a framebuffer with the source renderbuffer and make it the current target for reads */ glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, source); } else { glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, source, 0); } glPixelStorei (GL_PACK_ALIGNMENT, 4); glPixelStorei (GL_PACK_ROW_LENGTH, cairo_image_surface_get_stride (image) / 4); glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, cairo_image_surface_get_data (image)); glPixelStorei (GL_PACK_ROW_LENGTH, 0); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); cairo_surface_mark_dirty (image); /* Invert due to opengl having different origin */ cairo_scale (cr, 1, -1); cairo_translate (cr, 0, -height / buffer_scale); cairo_set_source_surface (cr, image, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_paint (cr); cairo_surface_destroy (image); } if (clip_region) cairo_region_destroy (clip_region); }
static char* get_stride_attrib(cdCtxCanvas* ctxcanvas) { static char data[100]; sprintf(data, "%d", cairo_image_surface_get_stride(cairo_get_target(ctxcanvas->cr))); return data; }
int guac_png_write(guac_socket* socket, guac_stream* stream, cairo_surface_t* surface) { png_structp png; png_infop png_info; png_byte** png_rows; int bpp; int x, y; guac_png_write_state write_state; /* Get image surface properties and data */ cairo_format_t format = cairo_image_surface_get_format(surface); int width = cairo_image_surface_get_width(surface); int height = cairo_image_surface_get_height(surface); int stride = cairo_image_surface_get_stride(surface); unsigned char* data = cairo_image_surface_get_data(surface); /* If not RGB24, use Cairo PNG writer */ if (format != CAIRO_FORMAT_RGB24 || data == NULL) return guac_png_cairo_write(socket, stream, surface); /* Flush pending operations to surface */ cairo_surface_flush(surface); /* Attempt to build palette */ guac_palette* palette = guac_palette_alloc(surface); /* If not possible, resort to Cairo PNG writer */ if (palette == NULL) return guac_png_cairo_write(socket, stream, surface); /* Calculate BPP from palette size */ if (palette->size <= 2) bpp = 1; else if (palette->size <= 4) bpp = 2; else if (palette->size <= 16) bpp = 4; else bpp = 8; /* Set up PNG writer */ png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { guac_error = GUAC_STATUS_INTERNAL_ERROR; guac_error_message = "libpng failed to create write structure"; return -1; } png_info = png_create_info_struct(png); if (!png_info) { png_destroy_write_struct(&png, NULL); guac_error = GUAC_STATUS_INTERNAL_ERROR; guac_error_message = "libpng failed to create info structure"; return -1; } /* Set error handler */ if (setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &png_info); guac_error = GUAC_STATUS_IO_ERROR; guac_error_message = "libpng output error"; return -1; } /* Init write state */ write_state.socket = socket; write_state.stream = stream; write_state.buffer_size = 0; /* Set up writer */ png_set_write_fn(png, &write_state, guac_png_write_handler, guac_png_flush_handler); /* Copy data from surface into PNG data */ png_rows = (png_byte**) malloc(sizeof(png_byte*) * height); for (y=0; y<height; y++) { /* Allocate new PNG row */ png_byte* row = (png_byte*) malloc(sizeof(png_byte) * width); png_rows[y] = row; /* Copy data from surface into current row */ for (x=0; x<width; x++) { /* Get pixel color */ int color = ((uint32_t*) data)[x] & 0xFFFFFF; /* Set index in row */ row[x] = guac_palette_find(palette, color); } /* Advance to next data row */ data += stride; } /* Write image info */ png_set_IHDR( png, png_info, width, height, bpp, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); /* Write palette */ png_set_PLTE(png, png_info, palette->colors, palette->size); /* Write image */ png_set_rows(png, png_info, png_rows); png_write_png(png, png_info, PNG_TRANSFORM_PACKING, NULL); /* Finish write */ png_destroy_write_struct(&png, &png_info); /* Free palette */ guac_palette_free(palette); /* Free PNG data */ for (y=0; y<height; y++) free(png_rows[y]); free(png_rows); /* Ensure all data is written */ guac_png_flush_data(&write_state); return 0; }
int draw(tr_params * render) { fontface * face = NULL; cairo_surface_t * sub_surface; cairo_t * sub_context; cairo_status_t status; cairo_text_extents_t text_extents, help_extents; int stride; cairo_matrix_t matrix; double elapsed; #ifdef __linux struct timespec tp_start, tp_end; #else clock_t start, end; #endif #ifdef __linux clock_gettime(CLOCK_REALTIME, &tp_start); #else start = clock(); #endif if ( render->text == NULL || strlen(render->text) == 0 ) { fwrite(nullpng, 1, sizeof(nullpng), stdout); return 0; } if ( render->font != NULL ) face = hash_get(faces, render->font); if ( face == NULL ) face = hash_get(faces, "__DEFAULT__"); cairo_set_font_size(main_context, render->size); cairo_set_font_face(main_context, face->cface); // the help parameter will probably alter the text to draw, so let's check it first if ( render->help != NULL && strncmp(render->help, "debug", sizeof("debug")) != 0 ) render->text = help_text(render); // how big will the rendered text be? cairo_text_extents(main_context, render->text, &text_extents); // we'll might also need to know the extents of the help text if ( render->help != NULL && strncmp(render->help, "debug", sizeof("debug")) == 0 ) cairo_text_extents(main_context, help_text(render), &help_extents); // since Cairo origins it's draw from the lower-left (for l2r text) we have to adjust y if ( render->y == _DEFAULT_Y ) render->y = text_extents.height; // TODO - if helptext, grow render w and h as needed... // 1.06 is a swizzle factor to compensate for the incorrect extents cairo produces if ( render->w == _DEFAULT_WIDTH ) { render->w = ceil(render->x) + ceil(text_extents.width * 1.06); } if ( render->h == _DEFAULT_HEIGHT ) { render->h = ceil(render->y) + ceil(text_extents.height); } stride = cairo_image_surface_get_stride(main_surface); // we know how big the image will be, create our sub_surface from the main_surface sub_surface = cairo_image_surface_create_for_data(cairo_image_surface_get_data(main_surface), CAIRO_FORMAT_ARGB32, render->w, render->h, stride); sub_context = cairo_create(sub_surface); // Remember, this is a new surface that just happens to share the same // buffer as main_surface so we have to set the font size and face for it cairo_set_font_size(sub_context, render->size); cairo_set_font_face(sub_context, face->cface); // clear the buffer of left-over data cairo_set_operator(sub_context, CAIRO_OPERATOR_CLEAR); cairo_paint(sub_context); // And now we're ready to draw! cairo_set_operator(sub_context, CAIRO_OPERATOR_OVER); // do we need to show a background color? if ( render->bgr != 0.0 || render->bgg != 0.0 || render->bgb != 0.0 || render->bga != 0.0 ) { cairo_set_source_rgba(sub_context, render->bgr, render->bgg, render->bgb, render->bga); cairo_paint_with_alpha(sub_context, render->bga); } // set text color cairo_set_source_rgba(sub_context, render->r, render->g, render->b, render->a); cairo_move_to(sub_context, render->x, render->y); /* // TODO: rotation currently rotates around the upper-left corner, fix to rotate around text center if ( render->th != 0.0 ) { cairo_get_font_matrix(sub_context, &matrix); cairo_matrix_rotate(&matrix, render->th); cairo_set_font_matrix(sub_context, &matrix); } */ cairo_show_text(sub_context, render->text); // if we're set to debug, we'll have attempted a render above, and now we draw a parameters placard if ( render->help != NULL && (strncmp(render->help, "debug", sizeof("debug")) == 0) ) { // half-transparent black fill cairo_set_source_rgba(sub_context, 0, 0, 0, 1.0); cairo_paint_with_alpha(sub_context, 0.5); face = hash_get(faces, "__DEFAULT__"); cairo_set_font_face(sub_context, face->cface); cairo_set_font_size(sub_context, 12); cairo_move_to(sub_context, 0, 12); cairo_set_source_rgba(sub_context, 1, 1, 1, 1.0); cairo_show_text(sub_context, help_text(render)); } status = cairo_surface_write_to_png_stream(sub_surface, FCGI_cairo_write_stream, NULL); cairo_destroy(sub_context); cairo_surface_destroy(sub_surface); #ifdef __linux clock_gettime(CLOCK_REALTIME, &tp_end); elapsed = tp_end.tv_sec - tp_start.tv_sec; elapsed += (tp_end.tv_nsec - tp_start.tv_nsec)/1000000000.0; #else end = clock(); elapsed = ((double) (end - start)) / CLOCKS_PER_SEC; #endif // fprintf(stderr, "elapsed: %.3fms", elapsed*1000); // logging }
static gboolean select_area_expose (GtkWidget *widget, GdkEventExpose *event) { cairo_t *cr; GtkAllocation allocation; gdouble dx; gdouble dy; cairo_surface_t *surface; guchar *dest; gdouble y; gint j; cr = gdk_cairo_create (event->window); gdk_cairo_region (cr, event->region); cairo_clip (cr); gtk_widget_get_allocation (widget, &allocation); dx = 1.0 / allocation.width; dy = 1.0 / allocation.height; surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, event->area.width, event->area.height); dest = cairo_image_surface_get_data (surface); for (j = 0, y = event->area.y / allocation.height; j < event->area.height; j++, y += dy) { guchar *d = dest; gdouble r = calc (0, y, 0); gdouble g = calc (0, y, 120); gdouble b = calc (0, y, 240); gdouble dr = calc (dx, y, 0) - r; gdouble dg = calc (dx, y, 120) - g; gdouble db = calc (dx, y, 240) - b; gint i; r += event->area.x * dr; g += event->area.x * dg; b += event->area.x * db; for (i = 0; i < event->area.width; i++) { GIMP_CAIRO_RGB24_SET_PIXEL (d, CLAMP ((gint) r, 0, 255), CLAMP ((gint) g, 0, 255), CLAMP ((gint) b, 0, 255)); r += dr; g += dg; b += db; d += 4; } dest += cairo_image_surface_get_stride (surface); } cairo_surface_mark_dirty (surface); cairo_set_source_surface (cr, surface, event->area.x, event->area.y); cairo_surface_destroy (surface); cairo_paint (cr); cairo_destroy (cr); return FALSE; }
static PangoClutterGlyphCacheValue * pango_clutter_renderer_get_cached_glyph (PangoRenderer *renderer, PangoFont *font, PangoGlyph glyph) { PangoClutterRenderer *priv = PANGO_CLUTTER_RENDERER (renderer); PangoClutterGlyphCacheValue *value; PangoClutterGlyphCache *glyph_cache; glyph_cache = priv->use_mipmapping ? priv->mipmapped_glyph_cache : priv->glyph_cache; if ((value = pango_clutter_glyph_cache_lookup (glyph_cache, font, glyph)) == NULL) { cairo_surface_t *surface; cairo_t *cr; cairo_scaled_font_t *scaled_font; PangoRectangle ink_rect; cairo_glyph_t cairo_glyph; pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); surface = cairo_image_surface_create (CAIRO_FORMAT_A8, ink_rect.width, ink_rect.height); cr = cairo_create (surface); scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font)); cairo_set_scaled_font (cr, scaled_font); cairo_glyph.x = -ink_rect.x; cairo_glyph.y = -ink_rect.y; /* The PangoCairo glyph numbers directly map to Cairo glyph numbers */ cairo_glyph.index = glyph; cairo_show_glyphs (cr, &cairo_glyph, 1); cairo_destroy (cr); cairo_surface_flush (surface); /* Copy the glyph to the cache */ value = pango_clutter_glyph_cache_set (glyph_cache, font, glyph, cairo_image_surface_get_data (surface), cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface), cairo_image_surface_get_stride (surface), ink_rect.x, ink_rect.y); cairo_surface_destroy (surface); CLUTTER_NOTE (PANGO, "cache fail %i", glyph); } else CLUTTER_NOTE (PANGO, "cache success %i", glyph); return value; }
static void gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer, GtkWidget *widget, GimpTempBuf *temp_buf, gint temp_buf_x, gint temp_buf_y, gint channel, GimpViewBG inside_bg, GimpViewBG outside_bg, cairo_surface_t *surface, gint surface_width, gint surface_height) { cairo_t *cr; gint x, y; gint width, height; const Babl *temp_buf_format; gint temp_buf_width; gint temp_buf_height; g_return_if_fail (temp_buf != NULL); g_return_if_fail (surface != NULL); temp_buf_format = gimp_temp_buf_get_format (temp_buf); temp_buf_width = gimp_temp_buf_get_width (temp_buf); temp_buf_height = gimp_temp_buf_get_height (temp_buf); /* Here are the different cases this functions handles correctly: * 1) Offset temp_buf which does not necessarily cover full image area * 2) Color conversion of temp_buf if it is gray and image is color * 3) Background check buffer for transparent temp_bufs * 4) Using the optional "channel" argument, one channel can be extracted * from a multi-channel temp_buf and composited as a grayscale * Prereqs: * 1) Grayscale temp_bufs have bytes == {1, 2} * 2) Color temp_bufs have bytes == {3, 4} * 3) If image is gray, then temp_buf should have bytes == {1, 2} */ cr = cairo_create (surface); if (outside_bg == GIMP_VIEW_BG_CHECKS || inside_bg == GIMP_VIEW_BG_CHECKS) { if (! renderer->pattern) renderer->pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, gimp_render_light_check_color (), gimp_render_dark_check_color ()); } switch (outside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_paint (cr); if (! gimp_rectangle_intersect (0, 0, surface_width, surface_height, temp_buf_x, temp_buf_y, temp_buf_width, temp_buf_height, &x, &y, &width, &height)) { cairo_destroy (cr); return; } if (inside_bg != outside_bg && babl_format_has_alpha (temp_buf_format) && channel == -1) { cairo_rectangle (cr, x, y, width, height); switch (inside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_fill (cr); } if (babl_format_has_alpha (temp_buf_format) && channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_t *alpha_surface; alpha_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (alpha_surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (alpha_surface); cairo_translate (cr, x, y); cairo_rectangle (cr, 0, 0, width, height); cairo_set_source_surface (cr, alpha_surface, 0, 0); cairo_fill (cr); cairo_surface_destroy (alpha_surface); } else if (channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_flush (surface); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (surface); } else { const Babl *fish; const guchar *src; guchar *dest; gint dest_stride; gint bytes; gint rowstride; gint i; cairo_surface_flush (surface); bytes = babl_format_get_bytes_per_pixel (temp_buf_format); rowstride = temp_buf_width * bytes; src = gimp_temp_buf_get_data (temp_buf) + ((y - temp_buf_y) * rowstride + (x - temp_buf_x) * bytes); dest = cairo_image_surface_get_data (surface); dest_stride = cairo_image_surface_get_stride (surface); dest += y * dest_stride + x * 4; fish = babl_fish (temp_buf_format, babl_format ("cairo-RGB24")); for (i = y; i < (y + height); i++) { const guchar *s = src; guchar *d = dest; gint j; for (j = x; j < (x + width); j++, d += 4, s += bytes) { if (bytes > 2) { guchar pixel[4] = { s[channel], s[channel], s[channel], 255 }; babl_process (fish, pixel, d, 1); } else { guchar pixel[2] = { s[channel], 255 }; babl_process (fish, pixel, d, 1); } } src += rowstride; dest += dest_stride; } cairo_surface_mark_dirty (surface); } cairo_destroy (cr); }
static const char * write_ppm (cairo_surface_t *surface, int fd) { char buf[4096]; cairo_format_t format; const char *format_str; const unsigned char *data; int len; int width, height, stride; int i, j; data = cairo_image_surface_get_data (surface); height = cairo_image_surface_get_height (surface); width = cairo_image_surface_get_width (surface); stride = cairo_image_surface_get_stride (surface); format = cairo_image_surface_get_format (surface); if (format == CAIRO_FORMAT_ARGB32) { /* see if we can convert to a standard ppm type and trim a few bytes */ const unsigned char *alpha = data; for (j = height; j--; alpha += stride) { for (i = 0; i < width; i++) { if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000) goto done; } } format = CAIRO_FORMAT_RGB24; done: ; } switch (format) { case CAIRO_FORMAT_ARGB32: /* XXX need true alpha for svg */ format_str = "P7"; break; case CAIRO_FORMAT_RGB24: format_str = "P6"; break; case CAIRO_FORMAT_A8: format_str = "P5"; break; case CAIRO_FORMAT_A1: default: return "unhandled image format"; } len = sprintf (buf, "%s %d %d 255\n", format_str, width, height); for (j = 0; j < height; j++) { const unsigned int *row = (unsigned int *) (data + stride * j); switch ((int) format) { case CAIRO_FORMAT_ARGB32: len = _write (fd, buf, sizeof (buf), len, (unsigned char *) row, 4 * width); break; case CAIRO_FORMAT_RGB24: for (i = 0; i < width; i++) { unsigned char rgb[3]; unsigned int p = *row++; rgb[0] = (p & 0xff0000) >> 16; rgb[1] = (p & 0x00ff00) >> 8; rgb[2] = (p & 0x0000ff) >> 0; len = _write (fd, buf, sizeof (buf), len, rgb, 3); } break; case CAIRO_FORMAT_A8: len = _write (fd, buf, sizeof (buf), len, (unsigned char *) row, width); break; } if (len < 0) return "write failed"; } if (len && ! _writen (fd, buf, len)) return "write failed"; return NULL; }
static gboolean spectrogram_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) { w_spectrogram_t *w = user_data; GtkAllocation a; gtk_widget_get_allocation (widget, &a); if (!w->samples || a.height < 1) { return FALSE; } int width, height; width = a.width; height = a.height; int ratio = ftoi (FFT_SIZE/(a.height*2)); ratio = CLAMP (ratio,0,1023); if (deadbeef->get_output ()->state () == OUTPUT_STATE_PLAYING) { do_fft (w); float log_scale = (log2f(w->samplerate/2)-log2f(25.))/(a.height); float freq_res = w->samplerate / FFT_SIZE; if (a.height != w->height) { w->height = MIN (a.height, MAX_HEIGHT); for (int i = 0; i < w->height; i++) { w->log_index[i] = ftoi (powf(2.,((float)i) * log_scale + log2f(25.)) / freq_res); if (i > 0 && w->log_index[i-1] == w->log_index [i]) { w->low_res_end = i; } } } } // start drawing if (!w->surf || cairo_image_surface_get_width (w->surf) != a.width || cairo_image_surface_get_height (w->surf) != a.height) { if (w->surf) { cairo_surface_destroy (w->surf); w->surf = NULL; } w->surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, a.width, a.height); } cairo_surface_flush (w->surf); unsigned char *data = cairo_image_surface_get_data (w->surf); if (!data) { return FALSE; } int stride = cairo_image_surface_get_stride (w->surf); if (deadbeef->get_output ()->state () == OUTPUT_STATE_PLAYING) { for (int i = 0; i < a.height; i++) { // scrolling: move line i 1px to the left memmove (data + (i*stride), data + sizeof (uint32_t) + (i*stride), stride - sizeof (uint32_t)); } for (int i = 0; i < a.height; i++) { float f = 1.0; int index0, index1; int bin0, bin1, bin2; if (CONFIG_LOG_SCALE) { bin0 = w->log_index[CLAMP (i-1,0,height-1)]; bin1 = w->log_index[i]; bin2 = w->log_index[CLAMP (i+1,0,height-1)]; } else { bin0 = (i-1) * ratio; bin1 = i * ratio; bin2 = (i+1) * ratio; } index0 = bin0 + ftoi ((bin1 - bin0)/2.f); if (index0 == bin0) index0 = bin1; index1 = bin1 + ftoi ((bin2 - bin1)/2.f); if (index1 == bin2) index1 = bin1; index0 = CLAMP (index0,0,FFT_SIZE/2-1); index1 = CLAMP (index1,0,FFT_SIZE/2-1); f = spectrogram_get_value (w, index0, index1); float x = 10 * log10f (f); // interpolate if (i <= w->low_res_end && CONFIG_LOG_SCALE) { int j = 0; // find index of next value while (i+j < height && w->log_index[i+j] == w->log_index[i]) { j++; } float v0 = x; float v1 = w->data[w->log_index[i+j]]; if (v1 != 0) { v1 = 10 * log10f (v1); } int k = 0; while ((k+i) >= 0 && w->log_index[k+i] == w->log_index[i]) { j++; k--; } x = linear_interpolate (v0,v1,(1.0/(j-1)) * ((-1 * k) - 1)); } // TODO: get rid of hardcoding x += CONFIG_DB_RANGE - 63; x = CLAMP (x, 0, CONFIG_DB_RANGE); int color_index = GRADIENT_TABLE_SIZE - ftoi (GRADIENT_TABLE_SIZE/(float)CONFIG_DB_RANGE * x); color_index = CLAMP (color_index, 0, GRADIENT_TABLE_SIZE-1); _draw_point (data, stride, width-1, height-1-i, w->colors[color_index]); } } cairo_surface_mark_dirty (w->surf); cairo_save (cr); cairo_set_source_surface (cr, w->surf, 0, 0); cairo_rectangle (cr, 0, 0, a.width, a.height); cairo_fill (cr); cairo_restore (cr); return FALSE; }
int32_t DataSourceSurfaceCairo::Stride() { return cairo_image_surface_get_stride(mImageSurface); }
GthImage * _cairo_image_surface_create_from_tiff (GInputStream *istream, GthFileData *file_data, int requested_size, int *original_width_p, int *original_height_p, gboolean *loaded_original_p, gpointer user_data, GCancellable *cancellable, GError **error) { GthImage *image; Handle handle; TIFF *tif; gboolean first_directory; int best_directory; int max_width, max_height, min_diff; uint32 image_width; uint32 image_height; uint32 spp; uint16 extrasamples; uint16 *sampleinfo; uint16 orientation; char emsg[1024]; cairo_surface_t *surface; cairo_surface_metadata_t*metadata; uint32 *raster; image = gth_image_new (); handle.cancellable = cancellable; handle.size = 0; if ((file_data != NULL) && (file_data->info != NULL)) { handle.istream = g_buffered_input_stream_new (istream); handle.size = g_file_info_get_size (file_data->info); } else { void *data; gsize size; /* read the whole stream to get the file size */ if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error)) return image; handle.istream = g_memory_input_stream_new_from_data (data, size, g_free); handle.size = size; } TIFFSetErrorHandler (tiff_error_handler); TIFFSetWarningHandler (tiff_error_handler); tif = TIFFClientOpen ("gth-tiff-reader", "r", &handle, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); if (tif == NULL) { g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } /* find the best image to load */ first_directory = TRUE; best_directory = -1; max_width = -1; max_height = -1; min_diff = 0; do { int width; int height; if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) != 1) continue; if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) != 1) continue; if (! TIFFRGBAImageOK (tif, emsg)) continue; if (width > max_width) { max_width = width; max_height = height; if (requested_size <= 0) best_directory = TIFFCurrentDirectory (tif); } if (requested_size > 0) { int diff = abs (requested_size - width); if (first_directory) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } else if (diff < min_diff) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } } first_directory = FALSE; } while (TIFFReadDirectory (tif)); if (best_directory == -1) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid TIFF format"); return image; } /* read the image */ TIFFSetDirectory (tif, best_directory); TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width); TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height); TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1) orientation = ORIENTATION_TOPLEFT; if (original_width_p) *original_width_p = max_width; if (original_height_p) *original_height_p = max_height; if (loaded_original_p) *loaded_original_p = (max_width == image_width); surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height); if (surface == NULL) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } metadata = _cairo_image_surface_get_metadata (surface); _cairo_metadata_set_has_alpha (metadata, (extrasamples == 1) || (spp == 4)); _cairo_metadata_set_original_size (metadata, max_width, max_height); raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32)); if (raster == NULL) { cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) { guchar *surface_row; int line_step; int x, y, temp; guchar r, g, b, a; uint32 *src_pixel; surface_row = _cairo_image_surface_flush_and_get_data (surface); line_step = cairo_image_surface_get_stride (surface); src_pixel = raster; for (y = 0; y < image_height; y++) { guchar *dest_pixel = surface_row; if (g_cancellable_is_cancelled (cancellable)) goto stop_loading; for (x = 0; x < image_width; x++) { r = TIFFGetR (*src_pixel); g = TIFFGetG (*src_pixel); b = TIFFGetB (*src_pixel); a = TIFFGetA (*src_pixel); CAIRO_SET_RGBA (dest_pixel, r, g, b, a); dest_pixel += 4; src_pixel += 1; } surface_row += line_step; } } stop_loading: cairo_surface_mark_dirty (surface); if (! g_cancellable_is_cancelled (cancellable)) gth_image_set_cairo_surface (image, surface); _TIFFfree (raster); cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); return image; }
/* Performs a simple 2D Gaussian blur of radius @radius on surface @surface. */ static void blur_image_surface (cairo_surface_t *surface, int radius) { cairo_surface_t *tmp; int width, height; int src_stride, dst_stride; int x, y, z, w; uint8_t *src, *dst; uint32_t *s, *d, a, p; int i, j, k; uint8_t kernel[17]; const int size = ARRAY_LENGTH (kernel); const int half = size / 2; if (cairo_surface_status (surface)) return; cairo_surface_flush(surface); width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); switch (cairo_image_surface_get_format (surface)) { case CAIRO_FORMAT_A1: default: /* Don't even think about it! */ return; case CAIRO_FORMAT_A8: /* Handle a8 surfaces by effectively unrolling the loops by a * factor of 4 - this is safe since we know that stride has to be a * multiple of uint32_t. */ width /= 4; break; case CAIRO_FORMAT_RGB24: case CAIRO_FORMAT_ARGB32: break; } tmp = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status (tmp)) return; src = cairo_image_surface_get_data (surface); src_stride = cairo_image_surface_get_stride (surface); dst = cairo_image_surface_get_data (tmp); dst_stride = cairo_image_surface_get_stride (tmp); a = 0; for (i = 0; i < size; i++) { double f = i - half; a += kernel[i] = exp (- f * f / 30.0) * 80; } /* Horizontally blur from surface -> tmp */ for (i = 0; i < height; i++) { s = (uint32_t *) (src + i * src_stride); d = (uint32_t *) (dst + i * dst_stride); for (j = 0; j < width; j++) { if (radius < j && j < width - radius) { d[j] = s[j]; continue; } x = y = z = w = 0; for (k = 0; k < size; k++) { if (j - half + k < 0 || j - half + k >= width) continue; p = s[j - half + k]; x += ((p >> 24) & 0xff) * kernel[k]; y += ((p >> 16) & 0xff) * kernel[k]; z += ((p >> 8) & 0xff) * kernel[k]; w += ((p >> 0) & 0xff) * kernel[k]; } d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; } } /* Then vertically blur from tmp -> surface */ for (i = 0; i < height; i++) { s = (uint32_t *) (dst + i * dst_stride); d = (uint32_t *) (src + i * src_stride); for (j = 0; j < width; j++) { if (radius <= i && i < height - radius) { d[j] = s[j]; continue; } x = y = z = w = 0; for (k = 0; k < size; k++) { if (i - half + k < 0 || i - half + k >= height) continue; s = (uint32_t *) (dst + (i - half + k) * dst_stride); p = s[j]; x += ((p >> 24) & 0xff) * kernel[k]; y += ((p >> 16) & 0xff) * kernel[k]; z += ((p >> 8) & 0xff) * kernel[k]; w += ((p >> 0) & 0xff) * kernel[k]; } d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; } } cairo_surface_destroy (tmp); cairo_surface_mark_dirty (surface); }
int Image::getSurfaceStride() const { return cairo_image_surface_get_stride(_surface); }
bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) { // This implementation is taken from GraphicsContext3DCairo. if (!m_image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. m_decoder = new ImageSource(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); if (!m_decoder) return false; ImageSource& decoder = *m_decoder; m_alphaOp = AlphaDoNothing; if (m_image->data()) { decoder.setData(m_image->data(), true); if (!decoder.frameCount()) return false; m_imageSurface = decoder.createFrameAtIndex(0); if (!m_imageSurface || !decoder.frameIsCompleteAtIndex(0)) return false; } else { m_imageSurface = m_image->nativeImageForCurrentFrame(); // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel, // which is true at present and may be changed in the future and needs adjustment accordingly. // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. if (!premultiplyAlpha && m_imageHtmlDomSource != HtmlDomVideo) m_alphaOp = AlphaDoUnmultiply; } if (!m_imageSurface) return false; m_imageWidth = cairo_image_surface_get_width(m_imageSurface.get()); m_imageHeight = cairo_image_surface_get_height(m_imageSurface.get()); if (!m_imageWidth || !m_imageHeight) return false; if (cairo_image_surface_get_format(m_imageSurface.get()) != CAIRO_FORMAT_ARGB32) return false; uint srcUnpackAlignment = 1; size_t bytesPerRow = cairo_image_surface_get_stride(m_imageSurface.get()); size_t bitsPerPixel = 32; unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } m_imagePixelData = cairo_image_surface_get_data(m_imageSurface.get()); m_imageSourceFormat = DataFormatBGRA8; m_imageSourceUnpackAlignment = srcUnpackAlignment; return true; }
bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) { if (!m_image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. m_decoder = new ImageSource(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); if (!m_decoder) return false; ImageSource& decoder = *m_decoder; m_alphaOp = AlphaDoNothing; if (m_image->data()) { decoder.setData(m_image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; m_imageSurface = decoder.createFrameAtIndex(0); } else { m_imageSurface = m_image->nativeImageForCurrentFrame(); // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel, // which is true at present and may be changed in the future and needs adjustment accordingly. // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. if (!premultiplyAlpha && m_imageHtmlDomSource != HtmlDomVideo) m_alphaOp = AlphaDoUnmultiply; // if m_imageSurface is not an image, extract a copy of the surface if (m_imageSurface && cairo_surface_get_type(m_imageSurface.get()) != CAIRO_SURFACE_TYPE_IMAGE) { RefPtr<cairo_surface_t> tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_imageWidth, m_imageHeight)); copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(0, 0, m_imageWidth, m_imageHeight), IntSize(), CAIRO_OPERATOR_SOURCE); m_imageSurface = tmpSurface.release(); } } if (!m_imageSurface) return false; ASSERT(cairo_surface_get_type(m_imageSurface.get()) == CAIRO_SURFACE_TYPE_IMAGE); IntSize imageSize = cairoSurfaceSize(m_imageSurface.get()); m_imageWidth = imageSize.width(); m_imageHeight = imageSize.height(); if (!m_imageWidth || !m_imageHeight) return false; if (cairo_image_surface_get_format(m_imageSurface.get()) != CAIRO_FORMAT_ARGB32) return false; unsigned int srcUnpackAlignment = 1; size_t bytesPerRow = cairo_image_surface_get_stride(m_imageSurface.get()); size_t bitsPerPixel = 32; unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } m_imagePixelData = cairo_image_surface_get_data(m_imageSurface.get()); m_imageSourceFormat = DataFormatBGRA8; m_imageSourceUnpackAlignment = srcUnpackAlignment; return true; }
void setup_tile (gint w, gint h) { cairo_status_t status; cairo_t* cr = NULL; cairo_surface_t* cr_surf = NULL; gdouble width = (gdouble) w; gdouble height = (gdouble) h; cairo_surface_t* tmp = NULL; cairo_surface_t* dummy_surf = NULL; cairo_surface_t* norm_surf = NULL; cairo_surface_t* blur_surf = NULL; raico_blur_t* blur = NULL; tile_t* tile = NULL; // create tmp. surface for scratch cr_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE); status = cairo_surface_status (cr_surf); if (status != CAIRO_STATUS_SUCCESS) g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); // create context for that tmp. scratch surface cr = cairo_create (cr_surf); status = cairo_status (cr); if (status != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (cr_surf); g_print ("Error: \"%s\"\n", cairo_status_to_string (status)); } // clear, render drop-shadow and bubble-background in scratch-surface cairo_scale (cr, 1.0f, 1.0f); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); if (g_composited) { draw_shadow (cr, width, height, BUBBLE_SHADOW_SIZE, CORNER_RADIUS); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); draw_round_rect (cr, 1.0f, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) BUBBLE_SHADOW_SIZE, (gdouble) CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f* BUBBLE_SHADOW_SIZE)); cairo_fill (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B, 0.95f); } else cairo_set_source_rgb (cr, BUBBLE_BG_COLOR_R, BUBBLE_BG_COLOR_G, BUBBLE_BG_COLOR_B); draw_round_rect (cr, 1.0f, BUBBLE_SHADOW_SIZE, BUBBLE_SHADOW_SIZE, CORNER_RADIUS, (gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE), (gdouble) (height - 2.0f * BUBBLE_SHADOW_SIZE)); cairo_fill (cr); // create tmp. copy of scratch-surface tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (cr_surf), cairo_image_surface_get_format (cr_surf), 3 * BUBBLE_SHADOW_SIZE, 3 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (cr_surf)); dummy_surf = copy_surface (tmp); cairo_surface_destroy (tmp); // create normal-state surface for tile from copy of scratch-surface tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); norm_surf = copy_surface (tmp); cairo_surface_destroy (tmp); // blur tmp. copy of scratch-surface blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW); raico_blur_set_radius (blur, 6); raico_blur_apply (blur, dummy_surf); raico_blur_destroy (blur); // create blurred-state surface for tile tmp = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (dummy_surf), cairo_image_surface_get_format (dummy_surf), 2 * BUBBLE_SHADOW_SIZE, 2 * BUBBLE_SHADOW_SIZE, cairo_image_surface_get_stride (dummy_surf)); blur_surf = copy_surface (tmp); cairo_surface_destroy (tmp); // actually create the tile with padding in mind tile = tile_new_for_padding (norm_surf, blur_surf); destroy_cloned_surface (norm_surf); destroy_cloned_surface (blur_surf); destroy_cloned_surface (dummy_surf); cairo_destroy (cr); cairo_surface_destroy (cr_surf); norm_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); cr = cairo_create (norm_surf); cairo_scale (cr, 1.0f, 1.0f); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); tile_paint_with_padding (tile, cr, 0.0f, 0.0f, w, h, 1.0f, 0.0f); cairo_destroy (cr); blur_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); cr = cairo_create (blur_surf); cairo_scale (cr, 1.0f, 1.0f); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); tile_paint_with_padding (tile, cr, 0.0f, 0.0f, w, h, 0.0f, 1.0f); cairo_destroy (cr); g_tile = tile_new_for_padding (norm_surf, blur_surf); // clean up tile_destroy (tile); cairo_surface_destroy (norm_surf); cairo_surface_destroy (blur_surf); }
cairo_surface_t* pdf_page_image_get_cairo(zathura_page_t* page, void* data, zathura_image_t* image, zathura_error_t* error) { mupdf_page_t* mupdf_page = data; if (page == NULL || mupdf_page == NULL || image == NULL || image->data == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } goto error_ret; } fz_image* mupdf_image = (fz_image*) image->data; fz_pixmap* pixmap = NULL; cairo_surface_t* surface = NULL; pixmap = fz_get_pixmap_from_image(mupdf_page->ctx, mupdf_image, NULL, NULL, 0, 0); if (pixmap == NULL) { goto error_free; } surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, mupdf_image->w, mupdf_image->h); if (surface == NULL) { goto error_free; } unsigned char* surface_data = cairo_image_surface_get_data(surface); int rowstride = cairo_image_surface_get_stride(surface); unsigned char* s = fz_pixmap_samples(mupdf_page->ctx, pixmap); unsigned int n = fz_pixmap_components(mupdf_page->ctx, pixmap); const int height = fz_pixmap_height(mupdf_page->ctx, pixmap); const int width = fz_pixmap_width(mupdf_page->ctx, pixmap); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { guchar* p = surface_data + y * rowstride + x * 4; // RGB if (n == 4) { p[0] = s[2]; p[1] = s[1]; p[2] = s[0]; // Gray-scale or mask } else { p[0] = s[0]; p[1] = s[0]; p[2] = s[0]; } s += n; } } fz_drop_pixmap(mupdf_page->ctx, pixmap); return surface; error_free: if (pixmap != NULL) { fz_drop_pixmap(mupdf_page->ctx, pixmap); } if (surface != NULL) { cairo_surface_destroy(surface); } error_ret: return NULL; }
static cairo_surface_t* rotate (cairo_surface_t *image, double angle, gboolean high_quality, guchar r0, guchar g0, guchar b0, guchar a0, GthAsyncTask *task) { cairo_surface_t *image_with_background; cairo_surface_t *rotated; double angle_rad; double cos_angle, sin_angle; double src_width, src_height; int new_width, new_height; int src_rowstride, new_rowstride; int xi, yi; double x, y; double x2, y2; int x2min, y2min; int x2max, y2max; double fx, fy; guchar *p_src, *p_new; guchar *p_src2, *p_new2; guchar r00, r01, r10, r11; guchar g00, g01, g10, g11; guchar b00, b01, b10, b11; guchar a00, a01, a10, a11; double half_new_width; double half_new_height; double half_src_width; double half_src_height; int tmp; guchar r, g, b, a; guint32 pixel; angle = CLAMP (angle, -90.0, 90.0); angle_rad = angle / 180.0 * G_PI; cos_angle = cos (angle_rad); sin_angle = sin (angle_rad); src_width = cairo_image_surface_get_width (image); src_height = cairo_image_surface_get_height (image); new_width = GDOUBLE_ROUND_TO_INT ( cos_angle * src_width + fabs(sin_angle) * src_height); new_height = GDOUBLE_ROUND_TO_INT (fabs (sin_angle) * src_width + cos_angle * src_height); if (a0 == 0xff) { /* pre-multiply the background color */ image_with_background = _cairo_image_surface_copy (image); p_src = _cairo_image_surface_flush_and_get_data (image); p_new = _cairo_image_surface_flush_and_get_data (image_with_background); src_rowstride = cairo_image_surface_get_stride (image); new_rowstride = cairo_image_surface_get_stride (image_with_background); cairo_surface_flush (image_with_background); for (yi = 0; yi < src_height; yi++) { p_src2 = p_src; p_new2 = p_new; for (xi = 0; xi < src_width; xi++) { a = p_src2[CAIRO_ALPHA]; r = p_src2[CAIRO_RED] + _cairo_multiply_alpha (r0, 0xff - a); g = p_src2[CAIRO_GREEN] + _cairo_multiply_alpha (g0, 0xff - a); b = p_src2[CAIRO_BLUE] + _cairo_multiply_alpha (b0, 0xff - a); pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff); memcpy (p_new2, &pixel, sizeof (guint32)); p_new2 += 4; p_src2 += 4; } p_src += src_rowstride; p_new += new_rowstride; } cairo_surface_mark_dirty (image_with_background); } else image_with_background = cairo_surface_reference (image); /* create the rotated image */ rotated = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, new_width, new_height); p_src = _cairo_image_surface_flush_and_get_data (image_with_background); p_new = _cairo_image_surface_flush_and_get_data (rotated); src_rowstride = cairo_image_surface_get_stride (image_with_background); new_rowstride = cairo_image_surface_get_stride (rotated); /* * bilinear interpolation * fx * v00------------v01 * | | | * fy |--------v | * | | * | | * | | * v10------------v11 */ #define INTERPOLATE(v, v00, v01, v10, v11, fx, fy) \ tmp = (1.0 - (fy)) * \ ((1.0 - (fx)) * (v00) + (fx) * (v01)) \ + \ (fy) * \ ((1.0 - (fx)) * (v10) + (fx) * (v11)); \ v = CLAMP (tmp, 0, 255); #define GET_VALUES(r, g, b, a, x, y) \ if (x >= 0 && x < src_width && y >= 0 && y < src_height) { \ p_src2 = p_src + src_rowstride * y + 4 * x; \ r = p_src2[CAIRO_RED]; \ g = p_src2[CAIRO_GREEN]; \ b = p_src2[CAIRO_BLUE]; \ a = p_src2[CAIRO_ALPHA]; \ } \ else { \ r = r0; \ g = g0; \ b = b0; \ a = a0; \ } half_new_width = new_width / 2.0; half_new_height = new_height / 2.0; half_src_width = src_width / 2.0; half_src_height = src_height / 2.0; cairo_surface_flush (rotated); y = - half_new_height; for (yi = 0; yi < new_height; yi++) { if (task != NULL) { gboolean cancelled; double progress; gth_async_task_get_data (task, NULL, &cancelled, NULL); if (cancelled) goto out; progress = (double) yi / new_height; gth_async_task_set_data (task, NULL, NULL, &progress); } p_new2 = p_new; x = - half_new_width; for (xi = 0; xi < new_width; xi++) { x2 = cos_angle * x - sin_angle * y + half_src_width; y2 = sin_angle * x + cos_angle * y + half_src_height; if (high_quality) { /* Bilinear interpolation. */ x2min = (int) x2; y2min = (int) y2; x2max = x2min + 1; y2max = y2min + 1; GET_VALUES (r00, g00, b00, a00, x2min, y2min); GET_VALUES (r01, g01, b01, a01, x2max, y2min); GET_VALUES (r10, g10, b10, a10, x2min, y2max); GET_VALUES (r11, g11, b11, a11, x2max, y2max); fx = x2 - x2min; fy = y2 - y2min; INTERPOLATE (r, r00, r01, r10, r11, fx, fy); INTERPOLATE (g, g00, g01, g10, g11, fx, fy); INTERPOLATE (b, b00, b01, b10, b11, fx, fy); INTERPOLATE (a, a00, a01, a10, a11, fx, fy); pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a); memcpy (p_new2, &pixel, sizeof (guint32)); } else { /* Nearest neighbor */ x2min = GDOUBLE_ROUND_TO_INT (x2); y2min = GDOUBLE_ROUND_TO_INT (y2); GET_VALUES (p_new2[CAIRO_RED], p_new2[CAIRO_GREEN], p_new2[CAIRO_BLUE], p_new2[CAIRO_ALPHA], x2min, y2min); } p_new2 += 4; x += 1.0; } p_new += new_rowstride; y += 1.0; } out: cairo_surface_mark_dirty (rotated); cairo_surface_destroy (image_with_background); #undef INTERPOLATE #undef GET_VALUES return rotated; }
/* Retrieve a frame and feed it into the pipeline */ static void recorder_record_frame (ShellRecorder *recorder, gboolean paint) { GstBuffer *buffer; ClutterCapture *captures; int n_captures; cairo_surface_t *image; guint size; uint8_t *data; GstMemory *memory; int i; GstClock *clock; GstClockTime now, base_time; g_return_if_fail (recorder->current_pipeline != NULL); /* If we get into the red zone, stop buffering new frames; 13/16 is * a bit more than the 3/4 threshold for a red indicator to keep the * indicator from flashing between red and yellow. */ if (recorder->memory_used > (recorder->memory_target * 13) / 16) return; /* Drop frames to get down to something like the target frame rate; since frames * are generated with VBlank sync, we don't have full control anyways, so we just * drop frames if the interval since the last frame is less than 75% of the * desired inter-frame interval. */ clock = gst_element_get_clock (recorder->current_pipeline->src); /* If we have no clock yet, the pipeline is not yet in PLAYING */ if (!clock) return; base_time = gst_element_get_base_time (recorder->current_pipeline->src); now = gst_clock_get_time (clock) - base_time; gst_object_unref (clock); if (GST_CLOCK_TIME_IS_VALID (recorder->last_frame_time) && now - recorder->last_frame_time < gst_util_uint64_scale_int (GST_SECOND, 3, 4 * recorder->framerate)) return; recorder->last_frame_time = now; clutter_stage_capture (recorder->stage, paint, &recorder->area, &captures, &n_captures); if (n_captures == 0) return; if (n_captures == 1) image = cairo_surface_reference (captures[0].image); else image = shell_util_composite_capture_images (captures, n_captures, recorder->area.x, recorder->area.y, recorder->area.width, recorder->area.height); data = cairo_image_surface_get_data (image); size = (cairo_image_surface_get_height (image) * cairo_image_surface_get_stride (image)); for (i = 0; i < n_captures; i++) cairo_surface_destroy (captures[i].image); g_free (captures); buffer = gst_buffer_new(); memory = gst_memory_new_wrapped (0, data, size, 0, size, image, (GDestroyNotify) cairo_surface_destroy); gst_buffer_insert_memory (buffer, -1, memory); GST_BUFFER_PTS(buffer) = now; if (recorder->draw_cursor && !g_settings_get_boolean (recorder->a11y_settings, MAGNIFIER_ACTIVE_KEY)) recorder_draw_cursor (recorder, buffer); shell_recorder_src_add_buffer (SHELL_RECORDER_SRC (recorder->current_pipeline->src), buffer); gst_buffer_unref (buffer); /* Reset the timeout that we used to avoid an overlong pause in the stream */ recorder_remove_redraw_timeout (recorder); recorder_add_redraw_timeout (recorder); }
void draw_shadow (cairo_t* cr, gdouble width, gdouble height, gint shadow_radius, gint corner_radius) { cairo_surface_t* tmp_surface = NULL; cairo_surface_t* new_surface = NULL; cairo_pattern_t* pattern = NULL; cairo_t* cr_surf = NULL; cairo_matrix_t matrix; raico_blur_t* blur = NULL; tmp_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 4 * shadow_radius, 4 * shadow_radius); if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS) return; cr_surf = cairo_create (tmp_surface); if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (tmp_surface); return; } cairo_scale (cr_surf, 1.0f, 1.0f); cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR); cairo_paint (cr_surf); cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 0.75f); cairo_arc (cr_surf, 2 * shadow_radius, 2 * shadow_radius, 2.0f * corner_radius, 0.0f, 360.0f * (G_PI / 180.f)); cairo_fill (cr_surf); cairo_destroy (cr_surf); // create and setup blur blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW); raico_blur_set_radius (blur, shadow_radius); // now blur it raico_blur_apply (blur, tmp_surface); // blur no longer needed raico_blur_destroy (blur); new_surface = cairo_image_surface_create_for_data ( cairo_image_surface_get_data (tmp_surface), cairo_image_surface_get_format (tmp_surface), cairo_image_surface_get_width (tmp_surface) / 2, cairo_image_surface_get_height (tmp_surface) / 2, cairo_image_surface_get_stride (tmp_surface)); pattern = cairo_pattern_create_for_surface (new_surface); if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (tmp_surface); cairo_surface_destroy (new_surface); return; } // top left cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_source (cr, pattern); cairo_rectangle (cr, 0.0f, 0.0f, width - 2 * shadow_radius, 2 * shadow_radius); cairo_fill (cr); // bottom left cairo_matrix_init_scale (&matrix, 1.0f, -1.0f); cairo_matrix_translate (&matrix, 0.0f, -height); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, 0.0f, 2 * shadow_radius, 2 * shadow_radius, height - 2 * shadow_radius); cairo_fill (cr); // top right cairo_matrix_init_scale (&matrix, -1.0f, 1.0f); cairo_matrix_translate (&matrix, -width, 0.0f); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, width - 2 * shadow_radius, 0.0f, 2 * shadow_radius, height - 2 * shadow_radius); cairo_fill (cr); // bottom right cairo_matrix_init_scale (&matrix, -1.0f, -1.0f); cairo_matrix_translate (&matrix, -width, -height); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, 2 * shadow_radius, height - 2 * shadow_radius, width - 2 * shadow_radius, 2 * shadow_radius); cairo_fill (cr); // clean up cairo_pattern_destroy (pattern); cairo_surface_destroy (tmp_surface); cairo_surface_destroy (new_surface); }
static void gimp_text_layer_render_layout (GimpTextLayer *layer, GimpTextLayout *layout) { GimpDrawable *drawable = GIMP_DRAWABLE (layer); GimpItem *item = GIMP_ITEM (layer); GimpImage *image = gimp_item_get_image (item); cairo_t *cr; cairo_surface_t *surface; PixelRegion layerPR; const guchar *data; GimpImageType layer_type; gint layer_alpha_byte; gint rowstride; gint width; gint height; gpointer pr; g_return_if_fail (gimp_drawable_has_alpha (drawable)); width = gimp_item_get_width (item); height = gimp_item_get_height (item); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (surface); gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE); cairo_destroy (cr); pixel_region_init (&layerPR, gimp_drawable_get_tiles (drawable), 0, 0, width, height, TRUE); layer_type = gimp_drawable_type (drawable); layer_alpha_byte = layerPR.bytes - 1; cairo_surface_flush (surface); data = cairo_image_surface_get_data (surface); rowstride = cairo_image_surface_get_stride (surface); for (pr = pixel_regions_register (1, &layerPR); pr != NULL; pr = pixel_regions_process (pr)) { const guchar *src = data + layerPR.y * rowstride + layerPR.x * 4; guchar *dest = layerPR.data; gint rows = layerPR.h; while (rows--) { const guchar *s = src; guchar *d = dest; gint w = layerPR.w; while (w--) { guchar color[4]; GIMP_CAIRO_ARGB32_GET_PIXEL (s, color[0], color[1], color[2], color[3]); gimp_image_transform_color (image, layer_type, d, GIMP_RGB, color); d[layer_alpha_byte] = color[3]; s += 4; d += layerPR.bytes; } src += rowstride; dest += layerPR.rowstride; } } cairo_surface_destroy (surface); gimp_drawable_update (drawable, 0, 0, width, height); }
cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* Create decompressor with standard error handling */ jpeg_create_decompress(&cinfo); cinfo.err = jpeg_std_error(&jerr); /* Read JPEG directly from memory buffer */ jpeg_mem_src(&cinfo, data, length); /* Read and validate JPEG header */ if (!jpeg_read_header(&cinfo, TRUE)) { guacenc_log(GUAC_LOG_WARNING, "Invalid JPEG data"); jpeg_destroy_decompress(&cinfo); return NULL; } /* Begin decompression */ cinfo.out_color_space = JCS_RGB; jpeg_start_decompress(&cinfo); /* Pull JPEG dimensions from decompressor */ int width = cinfo.output_width; int height = cinfo.output_height; /* Allocate sufficient buffer space for one JPEG scanline */ unsigned char* jpeg_scanline = malloc(width * 3); /* Create blank Cairo surface (no transparency in JPEG) */ cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); /* Pull underlying buffer and its stride */ int stride = cairo_image_surface_get_stride(surface); unsigned char* row = cairo_image_surface_get_data(surface); /* Read JPEG into surface */ while (cinfo.output_scanline < height) { /* Read single scanline */ unsigned char* buffers[1] = { jpeg_scanline }; jpeg_read_scanlines(&cinfo, buffers, 1); /* Copy scanline to Cairo surface */ guacenc_jpeg_copy_scanline(row, jpeg_scanline, width); /* Advance to next row of Cairo surface */ row += stride; } /* Scanline buffer is no longer needed */ free(jpeg_scanline); /* End decompression */ jpeg_finish_decompress(&cinfo); /* Free decompressor */ jpeg_destroy_decompress(&cinfo); /* JPEG was read successfully */ return surface; }