1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 /* AbiWord
3  * Copyright (C) 1998-2005 AbiSource, Inc.
4  * Copyright (C) 2005 Dom Lachowicz <cinamod@hotmail.com>
5  * Copyright (C) 2008 Robert Staudinger
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA.
21  */
22 
23 #include <string.h>
24 #include "ut_debugmsg.h"
25 #include "ut_string.h"
26 #include "ie_exp_PDF.h"
27 #include "pd_Document.h"
28 #include "gr_CairoPrintGraphics.h"
29 #include "fv_View.h"
30 #include "fl_DocLayout.h"
31 #include "ap_EditMethods.h"
32 #include "xap_App.h"
33 #include "ut_misc.h"
34 
35 #include <cairo-pdf.h>
36 #include <cairo-ps.h>
37 
38 #if 0
39 #include <cairo-svg.h>
40 #endif
41 
42 #include <gsf/gsf-output-memory.h>
43 #include <gsf/gsf-input-stdio.h>
44 #include <glib/gstdio.h>
45 
46 #include <unistd.h>
47 #include <set>
48 
49 /*****************************************************************/
50 /*****************************************************************/
51 
52 static cairo_status_t
ie_exp_cairo_write_func(void * closure,const unsigned char * data,unsigned int length)53 ie_exp_cairo_write_func (void *closure, const unsigned char *data, unsigned int length)
54 {
55 	if (!gsf_output_write((GsfOutput*)closure, length, data))
56 		return CAIRO_STATUS_WRITE_ERROR;
57     return CAIRO_STATUS_SUCCESS;
58 }
59 
60 class ABI_EXPORT IE_Exp_Cairo : public IE_Exp
61 {
62 public:
63   typedef enum
64     {
65       BACKEND_PS,
66       BACKEND_PDF,
67 	  BACKEND_SVG
68     } Format;
69 
70   IE_Exp_Cairo::Format mFormat;
71 
IE_Exp_Cairo(PD_Document * pDocument,IE_Exp_Cairo::Format format)72   IE_Exp_Cairo(PD_Document * pDocument, IE_Exp_Cairo::Format format)
73     : IE_Exp(pDocument), mFormat(format)
74   {
75   }
76 
~IE_Exp_Cairo()77   virtual ~IE_Exp_Cairo()
78   {
79   }
80 
_writeDocument(void)81   virtual UT_Error _writeDocument(void)
82   {
83     cairo_t *cr = NULL;
84     cairo_surface_t *surface = NULL;
85     GR_CairoPrintGraphics *print_graphics = NULL;
86     FL_DocLayout *pDocLayout = NULL;
87     FV_View *printView = NULL;
88 
89     std::set<UT_sint32> pages;
90     const std::string & pages_prop = getProperty ("pages");
91 
92     double width, height;
93 
94     width = getDoc()->m_docPageSize.Width (DIM_IN);
95     height = getDoc()->m_docPageSize.Height (DIM_IN);
96 
97 	// Cairo expects the width/height of the surface in points, with 1 point == 1/72 inch). For details, see
98 	// http://cairographics.org/manual/cairo-pdf-surface.html#cairo-pdf-surface-create-for-stream
99 	// Fixes bug 11343 - export to pdf uses wrong document size
100 	UT_uint32 dpi = 72;
101 	if (BACKEND_PDF == mFormat)
102 		surface = cairo_pdf_surface_create_for_stream(ie_exp_cairo_write_func, getFp(), width * dpi, height * dpi);
103 	else if (BACKEND_PS == mFormat)
104 		surface = cairo_ps_surface_create_for_stream(ie_exp_cairo_write_func, getFp(), width * dpi, height * dpi);
105 	else if (BACKEND_SVG == mFormat)
106 		{
107 			// surface = cairo_svg_surface_create_for_stream(ie_exp_cairo_write_func, getFp(), width * dpi, height * dpi);
108 			return UT_ERROR;
109 		}
110 	else
111 		{
112 			return UT_ERROR;
113 		}
114 
115 	cr = cairo_create(surface);
116 	cairo_surface_destroy(surface), surface = NULL;
117 
118 	print_graphics = new GR_CairoPrintGraphics(cr, dpi);
119     pDocLayout = new FL_DocLayout(getDoc(), print_graphics);
120     printView = new FV_View(XAP_App::getApp(), 0, pDocLayout);
121     printView->getLayout()->fillLayouts();
122     printView->getLayout()->formatAll();
123     printView->getLayout()->recalculateTOCFields();
124 
125 	// TODO lifecycle of "surface" and "cr"?
126 
127     if (!pages_prop.empty())
128       {
129 		  char **page_descriptions = g_strsplit(pages_prop.c_str(), ",", -1);
130 
131 		  int i = 0;
132 		  while (page_descriptions[i] != NULL)
133 			  {
134 				  char *description = page_descriptions[i];
135 				  i++;
136 
137 				  int start_page, end_page;
138 
139 				  if (2 == sscanf(description, "%d-%d", &start_page, &end_page))
140 					  {
141 					  }
142 				  else if (1 == sscanf(description, "%d", &start_page))
143 					  {
144 						  end_page = start_page;
145 					  }
146 				  else
147 					  {
148 						  // invalid page specification
149 						  continue;
150 					  }
151 
152 				  for (int pageno = start_page; pageno <= end_page; pageno++)
153 					  {
154 						  if ((pageno > 0) && (pageno <= (int)pDocLayout->countPages()))
155 							  pages.insert(pageno);
156 					  }
157 			  }
158 
159 		  g_strfreev(page_descriptions);
160       }
161 
162     if (pages.empty())
163       {
164 		  for (UT_sint32 i = 1; i <= pDocLayout->countPages(); i++)
165 			  {
166 				  pages.insert(i);
167 			  }
168       }
169 
170     s_actuallyPrint (getDoc(), print_graphics,
171 					 printView, getFileName(),
172 					 1, true,
173 					 pDocLayout->getWidth(), pDocLayout->getHeight() / pDocLayout->countPages(),
174 					 pages);
175 
176     DELETEP(print_graphics);
177 
178     DELETEP(pDocLayout);
179     DELETEP(printView);
180     DELETEP(print_graphics);
181     return UT_OK;
182   }
183 };
184 
185 /*****************************************************************/
186 /*****************************************************************/
187 
IE_Exp_PS_Sniffer()188 IE_Exp_PS_Sniffer::IE_Exp_PS_Sniffer()
189 : IE_ExpSniffer("application/postscript", false)
190 {
191 }
192 
~IE_Exp_PS_Sniffer()193 IE_Exp_PS_Sniffer::~IE_Exp_PS_Sniffer ()
194 {
195 }
196 
supportsMIME(const char * szMIME)197 UT_Confidence_t IE_Exp_PS_Sniffer::supportsMIME (const char * szMIME)
198 {
199   if(!g_ascii_strcasecmp(szMIME, "application/postscript"))
200     return UT_CONFIDENCE_PERFECT;
201   return UT_CONFIDENCE_ZILCH;
202 }
203 
recognizeSuffix(const char * szSuffix)204 bool IE_Exp_PS_Sniffer::recognizeSuffix (const char * szSuffix)
205 {
206   return !g_ascii_strcasecmp(szSuffix,".ps");
207 }
208 
getDlgLabels(const char ** szDesc,const char ** szSuffixList,IEFileType * ft)209 bool IE_Exp_PS_Sniffer::getDlgLabels (const char ** szDesc,
210 				      const char ** szSuffixList,
211 				      IEFileType * ft)
212 {
213   *szDesc = "Postscript (.ps)";
214   *szSuffixList = "*.ps";
215   *ft = getFileType();
216   return true;
217 }
218 
constructExporter(PD_Document * pDocument,IE_Exp ** ppie)219 UT_Error IE_Exp_PS_Sniffer::constructExporter (PD_Document * pDocument,
220 					       IE_Exp ** ppie)
221 {
222   *ppie = new IE_Exp_Cairo(pDocument, IE_Exp_Cairo::BACKEND_PS);
223   return UT_OK;
224 }
225 
226 /*****************************************************************/
227 /*****************************************************************/
228 
IE_Exp_SVG_Sniffer()229 IE_Exp_SVG_Sniffer::IE_Exp_SVG_Sniffer()
230 : IE_ExpSniffer("image/svg+xml", false)
231 {
232 }
233 
~IE_Exp_SVG_Sniffer()234 IE_Exp_SVG_Sniffer::~IE_Exp_SVG_Sniffer ()
235 {
236 }
237 
supportsMIME(const char * szMIME)238 UT_Confidence_t IE_Exp_SVG_Sniffer::supportsMIME (const char * szMIME)
239 {
240   if(!g_ascii_strcasecmp(szMIME, "image/svg+xml") ||
241 	 !g_ascii_strcasecmp(szMIME, "image/svg") ||
242 	 !g_ascii_strcasecmp(szMIME, "image/svg-xml") ||
243 	 !g_ascii_strcasecmp(szMIME, "image/vnd.adobe.svg+xml") ||
244 	 !g_ascii_strcasecmp(szMIME, "text/xml-svg"))
245     return UT_CONFIDENCE_PERFECT;
246   return UT_CONFIDENCE_ZILCH;
247 }
248 
recognizeSuffix(const char * szSuffix)249 bool IE_Exp_SVG_Sniffer::recognizeSuffix (const char * szSuffix)
250 {
251   return !g_ascii_strcasecmp(szSuffix,".svg");
252 }
253 
getDlgLabels(const char ** szDesc,const char ** szSuffixList,IEFileType * ft)254 bool IE_Exp_SVG_Sniffer::getDlgLabels (const char ** szDesc,
255 				      const char ** szSuffixList,
256 				      IEFileType * ft)
257 {
258   *szDesc = "Scalable Vector Graphics (.svg)";
259   *szSuffixList = "*.svg";
260   *ft = getFileType();
261   return true;
262 }
263 
constructExporter(PD_Document * pDocument,IE_Exp ** ppie)264 UT_Error IE_Exp_SVG_Sniffer::constructExporter (PD_Document * pDocument,
265 					       IE_Exp ** ppie)
266 {
267   *ppie = new IE_Exp_Cairo(pDocument, IE_Exp_Cairo::BACKEND_SVG);
268   return UT_OK;
269 }
270 
271 /*****************************************************************/
272 /*****************************************************************/
273 
IE_Exp_PDF_Sniffer()274 IE_Exp_PDF_Sniffer::IE_Exp_PDF_Sniffer()
275 : IE_ExpSniffer("application/pdf", false)
276 {
277 }
278 
~IE_Exp_PDF_Sniffer()279 IE_Exp_PDF_Sniffer::~IE_Exp_PDF_Sniffer ()
280 {
281 }
282 
supportsMIME(const char * szMIME)283 UT_Confidence_t IE_Exp_PDF_Sniffer::supportsMIME (const char * szMIME)
284 {
285   if(!g_ascii_strcasecmp(szMIME, "application/pdf"))
286     return UT_CONFIDENCE_PERFECT;
287   return UT_CONFIDENCE_ZILCH;
288 }
289 
recognizeSuffix(const char * szSuffix)290 bool IE_Exp_PDF_Sniffer::recognizeSuffix (const char * szSuffix)
291 {
292   return !g_ascii_strcasecmp(szSuffix,".pdf");
293 }
294 
getDlgLabels(const char ** szDesc,const char ** szSuffixList,IEFileType * ft)295 bool IE_Exp_PDF_Sniffer::getDlgLabels (const char ** szDesc,
296 				       const char ** szSuffixList,
297 				      IEFileType * ft)
298 {
299   *szDesc = "Portable Document Format (.pdf)";
300   *szSuffixList = "*.pdf";
301   *ft = getFileType();
302   return true;
303 }
304 
constructExporter(PD_Document * pDocument,IE_Exp ** ppie)305 UT_Error IE_Exp_PDF_Sniffer::constructExporter (PD_Document * pDocument,
306 					       IE_Exp ** ppie)
307 {
308   *ppie = new IE_Exp_Cairo(pDocument, IE_Exp_Cairo::BACKEND_PDF);
309   return UT_OK;
310 }
311 
312 /*****************************************************************/
313 /*****************************************************************/
314