/* 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);
}
Example #4
0
/*
 * 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;
}
Example #5
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);
    }
}
Example #6
0
 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 );
 }
Example #7
0
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;
}
Example #9
0
/**
 * 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);

}
Example #10
0
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;
}
Example #11
0
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;

}
Example #12
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;
}
Example #15
0
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);
}
Example #16
0
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);
}
Example #19
0
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;
}
Example #20
0
/* 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);
}
Example #21
0
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;
}
Example #23
0
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);
}
Example #25
0
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;
}
Example #26
0
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;
}
Example #27
0
/* 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);
}
Example #29
0
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);
}
Example #30
-1
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;

}