gerbv
export-image.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This file is a part of gerbv.
4  *
5  * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
6  *
7  * Contributed by Dino Ghilardi <dino.ghilardi@ieee.org>
8  *
9  * $Id$
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24  */
25 
31 #include "gerbv.h"
32 #include "common.h"
33 
34 #include <math.h>
35 #include <gdk-pixbuf/gdk-pixbuf.h>
36 #include <png.h>
37 
38 #include "render.h"
39 
40 #include "draw.h"
41 #include "export-svg.h"
42 #include <cairo.h>
43 #include <cairo-pdf.h>
44 #include <cairo-ps.h>
45 #include <cairo-svg.h>
46 #include <glib/gstdio.h>
47 
48 static gchar *
49 exportimage_extract_svg_inner_content (const gchar *svgText) {
50  const gchar *svgOpen;
51  const gchar *svgOpenEnd;
52  const gchar *svgClose;
53 
54  if (svgText == NULL) {
55  return NULL;
56  }
57 
58  svgOpen = strstr (svgText, "<svg");
59  if (svgOpen == NULL) {
60  return NULL;
61  }
62 
63  svgOpenEnd = strchr (svgOpen, '>');
64  if (svgOpenEnd == NULL) {
65  return NULL;
66  }
67 
68  svgClose = g_strrstr (svgOpenEnd, "</svg>");
69  if (svgClose == NULL || svgClose <= svgOpenEnd) {
70  return NULL;
71  }
72 
73  return g_strndup (svgOpenEnd + 1, svgClose - (svgOpenEnd + 1));
74 }
75 
76 static void
77 exportimage_append_svg_background (GString *svgOut, gerbv_project_t *gerbvProject) {
78  GdkColor *bg = &gerbvProject->background;
79 
80  /*
81  * Keep background behavior aligned with existing vector export: we only emit
82  * a background rectangle for non-white/non-black colors, so pure white/black
83  * stay transparent like the non-layered SVG path.
84  */
85  if ((bg->red == 0xffff && bg->green == 0xffff && bg->blue == 0xffff)
86  || (bg->red == 0x0000 && bg->green == 0x0000 && bg->blue == 0x0000)) {
87  return;
88  }
89 
90  g_string_append_printf (svgOut,
91  " <rect x=\"0\" y=\"0\" width=\"100%%\" height=\"100%%\" fill=\"rgb(%u,%u,%u)\" />\n",
92  bg->red / 257, bg->green / 257, bg->blue / 257);
93 }
94 
95 static void
96 exportimage_render_layer_to_svg_file (gerbv_fileinfo_t *fileInfo,
97  gerbv_render_info_t *renderInfo, const gchar *filename) {
98  cairo_surface_t *cSurface = cairo_svg_surface_create (filename,
99  renderInfo->displayWidth, renderInfo->displayHeight);
100  cairo_t *cairoTarget = cairo_create (cSurface);
101 
102  gerbv_render_cairo_set_scale_and_translation (cairoTarget, renderInfo);
103  gerbv_render_layer_to_cairo_target_without_transforming (cairoTarget,
104  fileInfo, renderInfo, FALSE);
105 
106  cairo_destroy (cairoTarget);
107  cairo_surface_destroy (cSurface);
108 }
109 
110 static void
111 exportimage_render_svg_layers_from_project (gerbv_project_t *gerbvProject,
112  gerbv_render_info_t *renderInfo, gchar const *filename) {
113  GString *svgOut = g_string_new (NULL);
114  gboolean hadError = FALSE;
115  int i;
116 
117  g_string_append (svgOut, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
118  g_string_append_printf (svgOut,
119  "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" version=\"1.1\" width=\"%d\" height=\"%d\" viewBox=\"0 0 %d %d\">\n",
120  renderInfo->displayWidth, renderInfo->displayHeight,
121  renderInfo->displayWidth, renderInfo->displayHeight);
122 
123  exportimage_append_svg_background (svgOut, gerbvProject);
124 
125  for (i = gerbvProject->last_loaded; i >= 0; i--) {
126  gerbv_fileinfo_t *fileInfo = gerbvProject->file[i];
127  gchar *tmpSvgName = NULL;
128  gchar *tmpSvgText = NULL;
129  gchar *innerSvg = NULL;
130  gchar *layerLabelEscaped = NULL;
131  gint tmpFd;
132 
133  if (fileInfo == NULL || !fileInfo->isVisible) {
134  continue;
135  }
136 
137  tmpFd = g_file_open_tmp ("gerbv-svg-layer-XXXXXX.svg", &tmpSvgName, NULL);
138  if (tmpFd < 0 || tmpSvgName == NULL) {
139  GERB_COMPILE_ERROR (_("Exporting error to file \"%s\""), filename);
140  hadError = TRUE;
141  g_free (tmpSvgName);
142  break;
143  }
144  close (tmpFd);
145 
146  exportimage_render_layer_to_svg_file (fileInfo, renderInfo, tmpSvgName);
147 
148  if (!g_file_get_contents (tmpSvgName, &tmpSvgText, NULL, NULL)) {
149  GERB_COMPILE_ERROR (_("Exporting error to file \"%s\""), filename);
150  hadError = TRUE;
151  goto cleanup_layer_export;
152  }
153 
154  innerSvg = exportimage_extract_svg_inner_content (tmpSvgText);
155  if (innerSvg == NULL) {
156  GERB_COMPILE_ERROR (_("Exporting error to file \"%s\""), filename);
157  hadError = TRUE;
158  goto cleanup_layer_export;
159  }
160 
161  layerLabelEscaped = g_markup_escape_text (
162  fileInfo->name ? fileInfo->name : _("Unnamed layer"), -1);
163 
164  g_string_append_printf (svgOut,
165  " <g inkscape:groupmode=\"layer\" inkscape:label=\"%s\">\n",
166  layerLabelEscaped);
167  g_string_append (svgOut, innerSvg);
168  g_string_append (svgOut, "\n");
169  g_string_append (svgOut, " </g>\n");
170 
171  cleanup_layer_export:
172  g_free (layerLabelEscaped);
173  g_free (innerSvg);
174  g_free (tmpSvgText);
175  g_unlink (tmpSvgName);
176  g_free (tmpSvgName);
177 
178  if (hadError) {
179  break;
180  }
181  }
182 
183  g_string_append (svgOut, "</svg>\n");
184 
185  if (!hadError && !g_file_set_contents (filename, svgOut->str, svgOut->len, NULL)) {
186  GERB_COMPILE_ERROR (_("Exporting error to file \"%s\""), filename);
187  }
188 
189  g_string_free (svgOut, TRUE);
190 }
191 
192 void exportimage_render_to_surface_and_destroy (gerbv_project_t *gerbvProject,
193  cairo_surface_t *cSurface, gerbv_render_info_t *renderInfo, gchar const* filename) {
194  cairo_t *cairoTarget = cairo_create (cSurface);
195 
196  gerbv_render_all_layers_to_cairo_target_for_vector_output (gerbvProject, cairoTarget, renderInfo);
197  cairo_destroy (cairoTarget);
198  cairo_surface_destroy (cSurface);
199 }
200 
201 gerbv_render_info_t gerbv_export_autoscale_project (gerbv_project_t *gerbvProject) {
203  gerbv_render_get_boundingbox(gerbvProject, &bb);
204  // add a border around the bounding box
205  gfloat tempWidth = bb.right - bb.left;
206  gfloat tempHeight = bb.bottom - bb.top;
207  bb.right += (tempWidth*0.05);
208  bb.left -= (tempWidth*0.05);
209  bb.bottom += (tempHeight*0.05);
210  bb.top -= (tempHeight*0.05);
211  float width = bb.right - bb.left + 0.001; // Plus a little extra to prevent from
212  float height = bb.bottom - bb.top + 0.001; // missing items due to round-off errors
213 
214  gerbv_render_info_t renderInfo = {72, 72, bb.left, bb.top,
215  GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY, width*72, height*72};
216  return renderInfo;
217 }
218 
219 void gerbv_export_png_file_from_project_autoscaled (gerbv_project_t *gerbvProject, int widthInPixels,
220  int heightInPixels, gchar const* filename) {
221  gerbv_render_info_t renderInfo = {1, 1, 0, 0,
223  widthInPixels, heightInPixels};
224 
225  gerbv_render_zoom_to_fit_display (gerbvProject, &renderInfo);
226  gerbv_export_png_file_from_project (gerbvProject, &renderInfo, filename);
227 }
228 
229 void gerbv_export_png_file_from_project (gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const* filename) {
230  cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
231  renderInfo->displayWidth, renderInfo->displayHeight);
232  cairo_t *cairoTarget = cairo_create (cSurface);
233  gerbv_render_all_layers_to_cairo_target (gerbvProject, cairoTarget, renderInfo);
234  if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png (cSurface, filename)) {
235  GERB_COMPILE_ERROR (_("Exporting error to file \"%s\""), filename);
236  }
237  cairo_destroy (cairoTarget);
238  cairo_surface_destroy (cSurface);
239 }
240 
241 void gerbv_export_pdf_file_from_project_autoscaled (gerbv_project_t *gerbvProject, gchar const* filename) {
242  gerbv_render_info_t renderInfo = gerbv_export_autoscale_project(gerbvProject);
243  gerbv_export_pdf_file_from_project (gerbvProject, &renderInfo, filename);
244 }
245 
247  gchar const* filename) {
248  cairo_surface_t *cSurface = cairo_pdf_surface_create (filename, renderInfo->displayWidth,
249  renderInfo->displayHeight);
250 
251  exportimage_render_to_surface_and_destroy (gerbvProject, cSurface, renderInfo, filename);
252 }
253 
254 void gerbv_export_postscript_file_from_project_autoscaled (gerbv_project_t *gerbvProject, gchar const* filename) {
255  gerbv_render_info_t renderInfo = gerbv_export_autoscale_project(gerbvProject);
256  gerbv_export_postscript_file_from_project (gerbvProject, &renderInfo, filename);
257 }
258 
260  gchar const* filename) {
261  cairo_surface_t *cSurface = cairo_ps_surface_create (filename, renderInfo->displayWidth,
262  renderInfo->displayHeight);
263  exportimage_render_to_surface_and_destroy (gerbvProject, cSurface, renderInfo, filename);
264 }
265 
266 void gerbv_export_svg_file_from_project_autoscaled (gerbv_project_t *gerbvProject, gchar const* filename) {
267  gerbv_render_info_t renderInfo = gerbv_export_autoscale_project(gerbvProject);
268  gerbv_export_svg_file_from_project_with_options (gerbvProject, &renderInfo, filename, FALSE);
269 }
270 
272  gchar const* filename) {
273  gerbv_export_svg_file_from_project_with_options (gerbvProject, renderInfo, filename, FALSE);
274 }
275 
277  gchar const* filename, gboolean exportLayersAsSvgLayers) {
278  gerbv_render_info_t renderInfo = gerbv_export_autoscale_project(gerbvProject);
279  gerbv_export_svg_file_from_project_with_options (gerbvProject, &renderInfo, filename,
280  exportLayersAsSvgLayers);
281 }
282 
284  gerbv_render_info_t *renderInfo, gchar const* filename,
285  gboolean exportLayersAsSvgLayers) {
286  /* Use the optimized SVG writer unless Cairo SVG is explicitly requested */
287  if (!gerbvProject->use_cairo_svg) {
288  export_svg_render_project (gerbvProject, renderInfo, filename,
289  exportLayersAsSvgLayers);
290  return;
291  }
292 
293  /* Legacy Cairo SVG path */
294  if (exportLayersAsSvgLayers) {
295  exportimage_render_svg_layers_from_project (gerbvProject, renderInfo, filename);
296  return;
297  }
298 
299  cairo_surface_t *cSurface = cairo_svg_surface_create (filename, renderInfo->displayWidth,
300  renderInfo->displayHeight);
301  exportimage_render_to_surface_and_destroy (gerbvProject, cSurface, renderInfo, filename);
302 }
Header info for the cairo rendering functions and the related selection calculating functions.
void gerbv_export_png_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a PNG file using user-specified render info.
Definition: export-image.c:229
void gerbv_export_postscript_file_from_project_autoscaled(gerbv_project_t *gerbvProject, gchar const *filename)
Render a project to a Postscript file, autoscaling the layers to fit inside the specified image dimen...
Definition: export-image.c:254
void gerbv_export_svg_file_from_project_autoscaled_with_options(gerbv_project_t *gerbvProject, gchar const *filename, gboolean exportLayersAsSvgLayers)
Render a project to a SVG file, optionally exporting visible layers as Inkscape layers.
Definition: export-image.c:276
void gerbv_export_svg_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a file using user-specified render info.
Definition: export-image.c:271
void gerbv_export_postscript_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a Postscript file using user-specified render info.
Definition: export-image.c:259
void gerbv_export_svg_file_from_project_with_options(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename, gboolean exportLayersAsSvgLayers)
Render a project to a SVG file using user-specified render info and export options.
Definition: export-image.c:283
void gerbv_export_png_file_from_project_autoscaled(gerbv_project_t *gerbvProject, int widthInPixels, int heightInPixels, gchar const *filename)
Render a project to a PNG file, autoscaling the layers to fit inside the specified image dimensions.
Definition: export-image.c:219
void gerbv_export_pdf_file_from_project_autoscaled(gerbv_project_t *gerbvProject, gchar const *filename)
Render a project to a PDF file, autoscaling the layers to fit inside the specified image dimensions.
Definition: export-image.c:241
void gerbv_export_pdf_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a PDF file using user-specified render info.
Definition: export-image.c:246
void gerbv_export_svg_file_from_project_autoscaled(gerbv_project_t *gerbvProject, gchar const *filename)
Render a project to a SVG file, autoscaling the layers to fit inside the specified image dimensions.
Definition: export-image.c:266
void export_svg_render_project(gerbv_project_t *project, gerbv_render_info_t *renderInfo, const gchar *filename, gboolean exportLayersAsSvgLayers)
Render the entire project to an optimized SVG file.
Definition: export-svg.c:1531
Header for optimized SVG export that bypasses Cairo's SVG surface.
void gerbv_render_zoom_to_fit_display(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo)
Calculate the zoom and translations to fit the rendered scene inside the given scene size.
Definition: gerbv.c:781
The main header file for the libgerbv library.
@ GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY
Definition: gerbv.h:370
Header info for the rendering support functions for gerbv.
gchar * name
Definition: gerbv.h:742
gboolean isVisible
Definition: gerbv.h:739
gboolean use_cairo_svg
Definition: gerbv.h:762
gerbv_fileinfo_t ** file
Definition: gerbv.h:752
GdkColor background
Definition: gerbv.h:750
int last_loaded
Definition: gerbv.h:754
gint displayHeight
Definition: gerbv.h:781