227 lines
7.1 KiB
C
227 lines
7.1 KiB
C
/* PIKA - Photo and Image Kooker Application
|
|
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
|
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
|
*
|
|
* Original copyright, applying to most contents (license remains unchanged):
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <libpika/pika.h>
|
|
#include <libpika/pikaui.h>
|
|
|
|
#include "print.h"
|
|
#include "print-draw-page.h"
|
|
|
|
#include "libpika/stdplugins-intl.h"
|
|
|
|
|
|
static cairo_surface_t * print_surface_from_drawable (PikaDrawable *drawable,
|
|
GError **error);
|
|
|
|
static void print_draw_crop_marks (GtkPrintContext *context,
|
|
gdouble x,
|
|
gdouble y,
|
|
gdouble w,
|
|
gdouble h);
|
|
|
|
gboolean
|
|
print_draw_page (GtkPrintContext *context,
|
|
PrintData *data,
|
|
GError **error)
|
|
{
|
|
cairo_t *cr = gtk_print_context_get_cairo_context (context);
|
|
cairo_surface_t *surface;
|
|
|
|
surface = print_surface_from_drawable (data->drawable, error);
|
|
|
|
if (surface)
|
|
{
|
|
gint width;
|
|
gint height;
|
|
gdouble scale_x;
|
|
gdouble scale_y;
|
|
|
|
/* create a white rectangle covering the entire page, just
|
|
* to be safe; see bug #777233.
|
|
*/
|
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
|
|
cairo_paint (cr);
|
|
|
|
width = cairo_image_surface_get_width (surface);
|
|
height = cairo_image_surface_get_height (surface);
|
|
|
|
scale_x = gtk_print_context_get_dpi_x (context) / data->xres;
|
|
scale_y = gtk_print_context_get_dpi_y (context) / data->yres;
|
|
|
|
cairo_translate (cr,
|
|
data->offset_x / 72.0 * gtk_print_context_get_dpi_x (context),
|
|
data->offset_y / 72.0 * gtk_print_context_get_dpi_y (context));
|
|
|
|
if (data->draw_crop_marks)
|
|
print_draw_crop_marks (context,
|
|
0, 0, width * scale_x, height * scale_y);
|
|
|
|
cairo_scale (cr, scale_x, scale_y);
|
|
cairo_rectangle (cr, 0, 0, width, height);
|
|
cairo_set_source_surface (cr, surface, 0, 0);
|
|
cairo_fill (cr);
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
print_surface_from_drawable (PikaDrawable *drawable,
|
|
GError **error)
|
|
{
|
|
GeglBuffer *buffer = pika_drawable_get_buffer (drawable);
|
|
const Babl *format;
|
|
cairo_surface_t *surface;
|
|
cairo_status_t status;
|
|
const gint width = pika_drawable_get_width (drawable);
|
|
const gint height = pika_drawable_get_height (drawable);
|
|
GeglBufferIterator *iter;
|
|
guchar *pixels;
|
|
gint stride;
|
|
guint count = 0;
|
|
guint64 done = 0;
|
|
|
|
if (pika_drawable_has_alpha (drawable))
|
|
format = babl_format ("cairo-ARGB32");
|
|
else
|
|
format = babl_format ("cairo-RGB24");
|
|
|
|
surface = cairo_image_surface_create (pika_drawable_has_alpha (drawable) ?
|
|
CAIRO_FORMAT_ARGB32 :
|
|
CAIRO_FORMAT_RGB24,
|
|
width, height);
|
|
|
|
status = cairo_surface_status (surface);
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
{
|
|
switch (status)
|
|
{
|
|
case CAIRO_STATUS_INVALID_SIZE:
|
|
g_set_error_literal (error,
|
|
PIKA_PLUGIN_PRINT_ERROR,
|
|
PIKA_PLUGIN_PRINT_ERROR_FAILED,
|
|
_("Cannot handle the size (either width or height) of the image."));
|
|
break;
|
|
default:
|
|
g_set_error (error,
|
|
PIKA_PLUGIN_PRINT_ERROR,
|
|
PIKA_PLUGIN_PRINT_ERROR_FAILED,
|
|
"Cairo error: %s",
|
|
cairo_status_to_string (status));
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
pixels = cairo_image_surface_get_data (surface);
|
|
stride = cairo_image_surface_get_stride (surface);
|
|
|
|
iter = gegl_buffer_iterator_new (buffer,
|
|
GEGL_RECTANGLE (0, 0, width, height), 0,
|
|
format,
|
|
GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
|
|
|
|
while (gegl_buffer_iterator_next (iter))
|
|
{
|
|
const guchar *src = iter->items[0].data;
|
|
guchar *dest = pixels + (guint64) iter->items[0].roi.y * stride + iter->items[0].roi.x * 4;
|
|
gint y;
|
|
|
|
for (y = 0; y < iter->items[0].roi.height; y++)
|
|
{
|
|
memcpy (dest, src, iter->items[0].roi.width * 4);
|
|
|
|
src += iter->items[0].roi.width * 4;
|
|
dest += stride;
|
|
}
|
|
|
|
done += (guint64) iter->items[0].roi.height * iter->items[0].roi.width;
|
|
|
|
if (count++ % 16 == 0)
|
|
pika_progress_update ((gdouble) done / ((gdouble) width * height));
|
|
}
|
|
|
|
g_object_unref (buffer);
|
|
|
|
cairo_surface_mark_dirty (surface);
|
|
|
|
pika_progress_update (1.0);
|
|
|
|
return surface;
|
|
}
|
|
|
|
static void
|
|
print_draw_crop_marks (GtkPrintContext *context,
|
|
gdouble x,
|
|
gdouble y,
|
|
gdouble w,
|
|
gdouble h)
|
|
{
|
|
cairo_t *cr = gtk_print_context_get_cairo_context (context);
|
|
gdouble len = MIN (gtk_print_context_get_width (context),
|
|
gtk_print_context_get_height (context)) / 20.0;
|
|
|
|
/* upper left */
|
|
|
|
cairo_move_to (cr, x - len, y);
|
|
cairo_line_to (cr, x - len / 5, y);
|
|
|
|
cairo_move_to (cr, x, y - len);
|
|
cairo_line_to (cr, x, y - len / 5);
|
|
|
|
/* upper right */
|
|
|
|
cairo_move_to (cr, x + w + len / 5, y);
|
|
cairo_line_to (cr, x + w + len, y);
|
|
|
|
cairo_move_to (cr, x + w, y - len);
|
|
cairo_line_to (cr, x + w, y - len / 5);
|
|
|
|
/* lower left */
|
|
|
|
cairo_move_to (cr, x - len, y + h);
|
|
cairo_line_to (cr, x - len / 5, y + h);
|
|
|
|
cairo_move_to (cr, x, y + h + len);
|
|
cairo_line_to (cr, x, y + h + len / 5);
|
|
|
|
/* lower right */
|
|
|
|
cairo_move_to (cr, x + w + len / 5, y + h);
|
|
cairo_line_to (cr, x + w + len, y + h);
|
|
|
|
cairo_move_to (cr, x + w, y + h + len);
|
|
cairo_line_to (cr, x + w, y + h + len / 5);
|
|
|
|
cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
|
|
cairo_set_line_width (cr, 2);
|
|
cairo_stroke (cr);
|
|
}
|