static void cairo_png_write_data_func (png_structp png_ptr, png_bytep buffer, png_size_t size) { CairoPngData *cairo_png_data; GError *error; cairo_png_data = png_get_io_ptr (png_ptr); if (! gth_buffer_data_write (cairo_png_data->buffer_data, buffer, size, &error)) { png_error (png_ptr, error->message); g_error_free (error); } }
static int cairo_webp_writer_func (const uint8_t *data, size_t data_size, const WebPPicture *picture) { CairoWebpData *cairo_webp_data = picture->custom_ptr; cairo_webp_data->success = gth_buffer_data_write (cairo_webp_data->buffer_data, (void *) data, data_size, cairo_webp_data->error); return cairo_webp_data->success; }
static gboolean rle_write (GthBufferData *buffer_data, guchar *buffer, guint width, guint bytes, GError **error) { int repeat = 0; int direct = 0; guchar *from = buffer; guint x; for (x = 1; x < width; ++x) { if (memcmp (buffer, buffer + bytes, bytes)) { /* next pixel is different */ if (repeat) { gth_buffer_data_putc (buffer_data, 128 + repeat, error); gth_buffer_data_write (buffer_data, from, bytes, error); from = buffer + bytes; /* point to first different pixel */ repeat = 0; direct = 0; } else direct += 1; } else { /* next pixel is the same */ if (direct) { gth_buffer_data_putc (buffer_data, direct - 1, error); gth_buffer_data_write (buffer_data, from, bytes * direct, error); from = buffer; /* point to first identical pixel */ direct = 0; repeat = 1; } else repeat += 1; } if (repeat == 128) { gth_buffer_data_putc (buffer_data, 255, error); gth_buffer_data_write (buffer_data, from, bytes, error); from = buffer + bytes; direct = 0; repeat = 0; } else if (direct == 128) { gth_buffer_data_putc (buffer_data, 127, error); gth_buffer_data_write (buffer_data, from, bytes * direct, error); from = buffer + bytes; direct = 0; repeat = 0; } buffer += bytes; } if (repeat > 0) { gth_buffer_data_putc (buffer_data, 128 + repeat, error); gth_buffer_data_write (buffer_data, from, bytes, error); } else { gth_buffer_data_putc (buffer_data, direct, error); gth_buffer_data_write (buffer_data, from, bytes * (direct + 1), error); } return TRUE; }
static gboolean _cairo_surface_write_as_tga (cairo_surface_t *image, char **buffer, gsize *buffer_size, char **keys, char **values, GError **error) { GthBufferData *buffer_data; int out_bpp = 0; int row; guchar header[18]; guchar footer[26]; gboolean rle_compression; gboolean alpha; guchar *pixels, *ptr, *buf; int width, height; int rowstride; rle_compression = TRUE; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "compression") == 0) { if (*viter == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Must specify a compression type"); return FALSE; } if (strcmp (*viter, "none") == 0) rle_compression = FALSE; else if (strcmp (*viter, "rle") == 0) rle_compression = TRUE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Unsupported compression type passed to the TGA saver"); return FALSE; } } else { g_warning ("Bad option name '%s' passed to the TGA saver", *kiter); return FALSE; } ++kiter; ++viter; } } width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); alpha = _cairo_image_surface_get_has_alpha (image); pixels = _cairo_image_surface_flush_and_get_data (image); rowstride = cairo_image_surface_get_stride (image); buffer_data = gth_buffer_data_new (); /* write the header */ header[0] = 0; /* No image identifier / description */ header[1] = 0; header[2] = rle_compression ? 10 : 2; header[3] = header[4] = header[5] = header[6] = header[7] = 0; header[8] = header[9] = 0; /* xorigin */ header[10] = header[11] = 0; /* yorigin */ header[12] = width % 256; header[13] = width / 256; header[14] = height % 256; header[15] = height / 256; if (alpha) { out_bpp = 4; header[16] = 32; /* bpp */ header[17] = 0x28; /* alpha + orientation */ } else { out_bpp = 3; header[16] = 24; /* bpp */ header[17] = 0x20; /* alpha + orientation */ } gth_buffer_data_write (buffer_data, header, sizeof (header), error); /* allocate a small buffer to convert image data */ buf = g_try_malloc (width * out_bpp * sizeof (guchar)); if (! buf) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Insufficient memory")); return FALSE; } ptr = pixels; for (row = 0; row < height; ++row) { _cairo_copy_line_as_rgba_little_endian (buf, ptr, width, alpha); if (rle_compression) rle_write (buffer_data, buf, width, out_bpp, error); else gth_buffer_data_write (buffer_data, buf, width * out_bpp, error); ptr += rowstride; } g_free (buf); /* write the footer */ memset (footer, 0, 8); /* No extensions, no developer directory */ memcpy (footer + 8, magic, sizeof (magic)); /* magic signature */ gth_buffer_data_write (buffer_data, footer, sizeof (footer), error); gth_buffer_data_get (buffer_data, buffer, buffer_size); gth_buffer_data_free (buffer_data, FALSE); return TRUE; }