1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2010 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef WPDF_IMAGE_H_
8 #define WPDF_IMAGE_H_
9 
10 #include <Wt/WFont.h>
11 #include <Wt/WPaintDevice.h>
12 #include <Wt/WResource.h>
13 #ifdef WT_TARGET_JAVA
14 #include <Wt/WTransform.h>
15 #endif //WT_TARGET_JAVA
16 
17 #include <hpdf.h>
18 
19 #include <map>
20 
21 namespace Wt {
22 
23   class FontSupport;
24   class WTransform;
25 
26 /*! \class WPdfImage Wt/WPdfImage.h Wt/WPdfImage.h
27  *  \brief A paint device for rendering to a PDF.
28  *
29  * A %WPdfImage paint device should be used in conjunction with a
30  * WPainter, and can be used to make a PDF version of a
31  * WPaintedWidget's contents.
32  *
33  * The PDF is generated using <a href="http://libharu.org/">The Haru
34  * Free PDF Library</a>, and this class is included in the library
35  * only if <tt>libharu</tt> was found during the build of the library.
36  *
37  * You can use the image as a resource and specialize handleRequest()
38  * to paint the contents on the fly. Alternatively can also use
39  * write() to serialize to a PDF file (std::ostream). The latter usage
40  * is illustrated by the code below:
41  *
42  * \code Wt::Chart::WCartesianChart
43  * *chart = ...
44  *
45  * Wt::WPdfImage pdfImage("4cm", "3cm");
46  * {
47  *   Wt::WPainter p(&pdfImage);
48  *   chart->paint(p);
49  * }
50  * std::ofstream f("chart.pdf", std::ios::out | std::ios::binary);
51  * pdfImage.write(f);
52  * \endcode
53  *
54  * A constructor is provided which allows the generated PDF image to
55  * be embedded directly into a page of a larger <tt>libharu</tt>
56  * document, and this approach is used for example by the WPdfRenderer
57  * to render XHTML to multi-page PDF files.
58  *
59  * Font information is embedded in the PDF. Fonts supported are native
60  * PostScript fonts (Base-14) (only ASCII-7), or true type fonts
61  * (Unicode). See addFontCollection() for more information on how
62  * fonts are located and matched to WFont descriptions.
63  *
64  * This paint device has the following limitations:
65  * - images (WPainter::drawImage()) can only be included from local
66  * files, and only JPG and PNG images are supported.
67  * - drop shadows are not supported.
68  *
69  * \ingroup painting
70  */
71 class WT_API WPdfImage : public WResource, public WPaintDevice
72 {
73 public:
74   /*! \brief Create a PDF resource that represents a single-page PDF document.
75    *
76    * The single page will have a size \p width x \p height.  The PDF
77    * will be using the same DPI (72dpi) as is conventionally used for
78    * the desktop.
79    *
80    * The passed width and height (such as 4 cm by 3 cm) can be specified in
81    * physical units (e.g. 4cm x 3cm), but this will be converted to pixels using
82    * the default DPI used in CSS (96dpi) !
83    *
84    * \sa write()
85    */
86   WPdfImage(const WLength& width, const WLength& height);
87 
88   /*! \brief Create a PDF paint device to paint inside an existing page.
89    *
90    * The image will be drawn in the existing page, as an image with lower-left
91    * point (\p x, \p y) and size (\p width x \p height).
92    */
93   WPdfImage(HPDF_Doc pdf, HPDF_Page page,
94 	    HPDF_REAL x, HPDF_REAL y, HPDF_REAL width, HPDF_REAL height);
95 
96   /*! \brief Destructor.
97    */
98   ~WPdfImage();
99 
100   /*! \brief Adds a font collection.
101    *
102    * If %Wt has been configured to use <tt>libpango</tt>, then font
103    * matching and character selection is done by libpango, which is
104    * seeded with information on installed fonts by fontconfig. In that
105    * case, invocations for this method is ignored. Only TrueType fonts
106    * are supported.
107    *
108    * As of %Wt 3.3.7, only TrueType fonts will be selected by default.
109    * Prior to %Wt 3.3.7, you needed to configure fontconfig (which
110    * is used by pango) to only return TrueType fonts. This can be
111    * done using a fonts.conf configuration %file:
112    *
113    * \code{.xml}
114    * <?xml version='1.0'?>
115    * <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
116    * <fontconfig>
117    *   <selectfont>
118    *     <rejectfont>
119    *       <glob>*.pfb</glob>
120    *     </rejectfont>
121    *   </selectfont>
122    * </fontconfig>
123    * \endcode
124    *
125    * You may need to add more glob patterns to exclude other fonts
126    * than TrueType, and also to exclude TrueType fonts which do not
127    * work properly with libharu.
128    *
129    * If %Wt has not been configured to use <tt>libpango</tt>, then
130    * this method may be used to indicate the location of TrueType
131    * fonts. The main drawback compared to libpango is that font
132    * selection is not steered by the need for particular characters,
133    * i.e. font selection is independent from the text's need for
134    * specific characters. Most TrueType fonts provide only partial
135    * unicode support. The provided \p directory will be searched for
136    * fonts (currently only TrueType ".ttf" or ".ttc" fonts). TrueType
137    * fonts are preferable over Base-14 fonts (which are PDF's default
138    * fonts) since they provide partial (or complete) unicode support.
139    *
140    * When using Base-14 fonts, WString::narrow() will be called on text
141    * which may result in loss of information.
142    */
143   void addFontCollection(const std::string& directory, bool recursive=true);
144 
145 #ifdef WT_TARGET_JAVA
146   void setDeviceTransform(const WTransform& deviceTransform);
147 #endif //WT_TARGET_JAVA
148 
149   virtual WFlags<PaintDeviceFeatureFlag> features() const override;
150   virtual void setChanged(WFlags<PainterChangeFlag> flags) override;
151   virtual void drawArc(const WRectF& rect, double startAngle, double spanAngle)
152     override;
153   virtual void drawImage(const WRectF& rect, const std::string& imgUri,
154 			 int imgWidth, int imgHeight, const WRectF& sourceRect)
155     override;
156   virtual void drawLine(double x1, double y1, double x2, double y2) override;
157   virtual void drawRect(const WRectF& rect) override;
158   virtual void drawPath(const WPainterPath& path) override;
159   virtual void drawText(const WRectF& rect,
160 			WFlags<AlignmentFlag> alignmentFlags, TextFlag textFlag,
161 			const WString& text, const WPointF *clipPoint)
162     override;
163   virtual WTextItem measureText(const WString& text, double maxWidth = -1,
164 				bool wordWrap = false) override;
165   virtual WFontMetrics fontMetrics() override;
166   virtual void init() override;
167   virtual void done() override;
paintActive()168   virtual bool paintActive() const override { return painter_ != nullptr; }
169 
width()170   virtual WLength width() const override { return width_; }
height()171   virtual WLength height() const override { return height_; }
172 
173   void errorHandler(HPDF_STATUS error_no, HPDF_STATUS detail_no);
174 
175   virtual void handleRequest(const Http::Request& request,
176 			     Http::Response& response) override;
177 
178 protected:
painter()179   virtual WPainter *painter() const override { return painter_; }
setPainter(WPainter * painter)180   virtual void setPainter(WPainter *painter) override { painter_ = painter; }
181 
182 private:
183   WLength width_, height_;
184   WPainter *painter_;
185   FontSupport *trueTypeFonts_;
186 
187   HPDF_Doc pdf_;
188   HPDF_Page page_;
189   HPDF_Font font_;
190   bool trueTypeFont_;
191   std::map<std::string, const char *> ttfFonts_;
192   WFont currentFont_;
193   std::string currentTtfFont_;
194   std::map<int, HPDF_ExtGState> alphaStrokeExtGStateMap_;
195   std::map<int, HPDF_ExtGState> alphaFillExtGStateMap_;
196 
197   bool myPdf_;
198   double x_, y_;
199 
200   double fontSize_;
201 
202   void paintPath();
203   void drawPlainPath(const WPainterPath& path);
204   void applyTransform(const WTransform& f);
205   void setStrokeColor(WColor color);
206   void setFillColor(WColor color);
207 };
208 
209 }
210 
211 #endif // WPDF_IMAGE_H_
212