1 /* Video4Linux2 frame source op for GEGL 2 * 3 * GEGL is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU Lesser General Public 5 * License as published by the Free Software Foundation; either 6 * version 3 of the License, or (at your option) any later version. 7 * 8 * GEGL is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public 14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>. 15 * 16 * Copyright 2019 Øyvind Kolås <pippin@gimp.org> 17 */ 18 19 #include "config.h" 20 #include <glib/gi18n-lib.h> 21 22 #ifdef GEGL_PROPERTIES 23 24 property_file_path (path, _("Path"), "") 25 description (_("file to load")) 26 27 property_uri (uri, _("URI"), "") 28 description (_("uri of file to load")) 29 30 property_int (page, _("Page"), 1) 31 description (_("Page to render")) 32 value_range (1, 10000) 33 34 property_int (pages, _("Pages"), 1) 35 description (_("Total pages, provided as a visual read-only property")) 36 value_range (1, 10000) 37 38 property_double (ppi, _("PPI"), 200.0) 39 description (_("Point/pixels per inch")) 40 ui_range (72.0, 1000.0) 41 value_range (10.0, 2400.0) 42 43 property_string (password, _("Password"), "") 44 description (_("Password to use for decryption of PDF, or blank for none")) 45 46 #else 47 48 #define GEGL_OP_SOURCE 49 #define GEGL_OP_NAME pdf_load 50 #define GEGL_OP_C_SOURCE pdf-load.c 51 52 #include "gegl-op.h" 53 #include <poppler.h> 54 55 typedef struct 56 { 57 char *path; 58 char *uri; 59 60 int page_no; 61 PopplerDocument *document; 62 PopplerPage *page; 63 int width; 64 int height; 65 double scale; 66 double ppi; 67 } Priv; 68 69 static GeglRectangle 70 get_bounding_box (GeglOperation *operation) 71 { 72 GeglRectangle result ={0,0,640,480}; 73 GeglProperties *o = GEGL_PROPERTIES (operation); 74 Priv *p= (Priv*)o->user_data; 75 if (p) 76 { 77 result.width = p->width; 78 result.height = p->height; 79 } 80 return result; 81 } 82 83 static void 84 prepare (GeglOperation *operation) 85 { 86 GeglProperties *o = GEGL_PROPERTIES (operation); 87 Priv *p= (Priv*)o->user_data; 88 if (p == NULL) 89 { 90 p = g_new0 (Priv, 1); 91 o->user_data = (void*) p; 92 } 93 94 if (p->path == NULL || strcmp (p->path, o->path) || 95 p->uri == NULL || strcmp (p->uri, o->uri)) 96 { 97 const char *password = o->password[0]?o->password:NULL; 98 99 if (p->path) 100 g_free (p->path); 101 if (p->uri) 102 g_free (p->uri); 103 if (p->document) 104 g_object_unref (p->document); 105 p->path = g_strdup (o->path); 106 p->uri = g_strdup (o->uri); 107 108 if (p->uri[0]) 109 { 110 p->document = poppler_document_new_from_file (p->uri, password, NULL); 111 } 112 else 113 { 114 GFile *file = g_file_new_for_path (p->path); 115 char *uri = g_file_get_uri (file); 116 p->document = poppler_document_new_from_file (uri, password, NULL); 117 g_free (uri); 118 g_object_unref (file); 119 } 120 p->page = NULL; 121 p->page_no = -1; 122 } 123 124 if (p->page_no != o->page-1 || p->ppi != o->ppi) 125 { 126 double width, height; 127 p->scale = o->ppi / 72.0; 128 p->ppi = o->ppi; 129 p->page_no = o->page -1; 130 if (p->page) 131 g_object_unref (p->page); 132 o->pages = poppler_document_get_n_pages (p->document); 133 if (p->page_no >= 0 && p->page_no < o->pages) 134 p->page = poppler_document_get_page (p->document, p->page_no); 135 else 136 p->page = NULL; 137 138 if (p->page) 139 { 140 poppler_page_get_size (p->page, &width, &height); 141 p->width = width * p->scale; 142 p->height = height * p->scale; 143 } 144 else 145 { 146 p->width = 23 * p->scale; 147 p->height = 42 * p->scale; 148 } 149 } 150 151 gegl_operation_set_format (operation, "output", 152 babl_format ("R'G'B'A u8")); 153 } 154 155 static void 156 finalize (GObject *object) 157 { 158 GeglProperties *o = GEGL_PROPERTIES (object); 159 160 if (o->user_data) 161 { 162 Priv *p = (Priv*)o->user_data; 163 if (p->page) 164 g_object_unref (p->page); 165 if (p->document) 166 g_object_unref (p->document); 167 if (p->path) 168 g_free (p->path); 169 g_clear_pointer (&o->user_data, g_free); 170 } 171 172 G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object); 173 } 174 175 static gboolean 176 process (GeglOperation *operation, 177 GeglBuffer *output, 178 const GeglRectangle *result, 179 gint level) 180 { 181 GeglProperties *o = GEGL_PROPERTIES (operation); 182 Priv *p = (Priv*)o->user_data; 183 184 if (p->page) 185 { 186 cairo_surface_t *surface; 187 cairo_t *cr; 188 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, p->width, p->height); 189 cr = cairo_create (surface); 190 cairo_set_source_rgb (cr, 1,1,1); 191 cairo_paint (cr); 192 cairo_scale (cr, p->scale, p->scale); 193 194 if (p->page) 195 poppler_page_render (p->page, cr); 196 197 cairo_surface_flush (surface); 198 199 gegl_buffer_set (output, 200 GEGL_RECTANGLE (0, 0, p->width, p->height), 201 0, 202 babl_format ("cairo-ARGB32"), 203 cairo_image_surface_get_data (surface), 204 cairo_image_surface_get_stride (surface)); 205 206 cairo_destroy (cr); 207 cairo_surface_destroy (surface); 208 } 209 return TRUE; 210 } 211 212 static GeglRectangle 213 get_cached_region (GeglOperation *operation, 214 const GeglRectangle *roi) 215 { 216 return get_bounding_box (operation); 217 } 218 219 static void 220 gegl_op_class_init (GeglOpClass *klass) 221 { 222 GeglOperationClass *operation_class; 223 GeglOperationSourceClass *source_class; 224 225 G_OBJECT_CLASS (klass)->finalize = finalize; 226 227 operation_class = GEGL_OPERATION_CLASS (klass); 228 source_class = GEGL_OPERATION_SOURCE_CLASS (klass); 229 230 source_class->process = process; 231 operation_class->get_bounding_box = get_bounding_box; 232 operation_class->get_cached_region = get_cached_region; 233 operation_class->prepare = prepare; 234 235 gegl_operation_handlers_register_loader( 236 "application/pdf", "gegl:pdf-load"); 237 gegl_operation_handlers_register_loader( 238 ".pdf", "gegl:pdf-load"); 239 240 gegl_operation_class_set_keys (operation_class, 241 "name", "gegl:pdf-load", 242 "title", _("pdf loader"), 243 "categories", "input", 244 "description", _("PDF page decoder"), 245 NULL); 246 } 247 248 #endif 249