From 25d25162c9c97ce04d5f85a0f4576a1963acf38d Mon Sep 17 00:00:00 2001
From: Bruce Toll <btoll@dhsus.com>
Date: Tue, 11 Dec 2018 16:02:46 -0500
Subject: [PATCH 4/7] Add transparency support to WPdfImage

Use two maps to maintain extended gstates for stroke and fill alphas,
respectively. Each unique alpha will only result in one gstate that
will be reused as needed.

NOTE: The setFillColor() call in drawText() needed to be moved prior
to the HPDF_Page_BeginText() call to avoid HPDF_PAGE_INVALID_GMODE
libharu errors.
---
 src/Wt/WPdfImage.C | 61 ++++++++++++++++++++++++++++++++++------------
 src/Wt/WPdfImage.h |  5 ++++
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/src/Wt/WPdfImage.C b/src/Wt/WPdfImage.C
index add16048..55a8ace9 100644
--- a/src/Wt/WPdfImage.C
+++ b/src/Wt/WPdfImage.C
@@ -141,6 +141,46 @@ void WPdfImage::applyTransform(const WTransform& t)
 		   t.m22(), t.dx(), t.dy());
 }
 
+HPDF_ExtGState WPdfImage::setStrokeColor(WColor color)
+{
+  HPDF_Page_SetRGBStroke(page_,
+                         color.red() / 255.,
+                         color.green() / 255.,
+                         color.blue() / 255.);
+
+  auto it = alphaStrokeExtGStateMap_.find(color.alpha());
+  HPDF_ExtGState gstate;
+  if (it == alphaStrokeExtGStateMap_.end()) {
+    gstate = HPDF_CreateExtGState(pdf_);
+    HPDF_ExtGState_SetAlphaStroke (gstate, color.alpha()/255.);
+    alphaStrokeExtGStateMap_[color.alpha()] = gstate;
+  }
+  else {
+    gstate = it->second;
+  }
+  HPDF_Page_SetExtGState (page_, gstate);
+}
+
+HPDF_ExtGState WPdfImage::setFillColor(WColor color)
+{
+  HPDF_Page_SetRGBFill(page_,
+                       color.red() / 255.,
+                       color.green() / 255.,
+                       color.blue() / 255.);
+
+  auto it = alphaFillExtGStateMap_.find(color.alpha());
+  HPDF_ExtGState gstate;
+  if (it == alphaFillExtGStateMap_.end()) {
+    gstate = HPDF_CreateExtGState(pdf_);
+    HPDF_ExtGState_SetAlphaFill (gstate, color.alpha()/255.);
+    alphaFillExtGStateMap_[color.alpha()] = gstate;
+  }
+  else {
+    gstate = it->second;
+  }
+  HPDF_Page_SetExtGState (page_, gstate);
+}
+
 void WPdfImage::setChanged(WFlags<PainterChangeFlag> flags)
 {
   if (!(flags & (PainterChangeFlag::Transform | PainterChangeFlag::Clipping)).empty()) {
@@ -177,10 +217,7 @@ void WPdfImage::setChanged(WFlags<PainterChangeFlag> flags)
     if (pen.style() != PenStyle::None) {
       const WColor& color = pen.color();
 
-      HPDF_Page_SetRGBStroke(page_,
-			     color.red() / 255.,
-			     color.green() / 255.,
-			     color.blue() / 255.);
+      setStrokeColor(color);
 
       WLength w = painter()->normalizedPenWidth(pen.width(), false);
       HPDF_Page_SetLineWidth(page_, w.toPixels());
@@ -245,10 +282,7 @@ void WPdfImage::setChanged(WFlags<PainterChangeFlag> flags)
     if (brush.style() != BrushStyle::None) {
       const WColor& color = painter()->brush().color();
 
-      HPDF_Page_SetRGBFill(page_,
-			   color.red() / 255.,
-			   color.green() / 255.,
-			   color.blue() / 255.);
+      setFillColor(color);
     }
   }
 
@@ -607,18 +641,15 @@ void WPdfImage::drawText(const WRectF& rect,
 
     HPDF_Page_GSave(page_);
 
+    // Need to fill text using pen color
+    const WColor& penColor = painter()->pen().color();
+    setFillColor(penColor);
+
     // Undo the global inversion
     HPDF_Page_Concat(page_, 1, 0, 0, -1, 0, bottom);
 
     HPDF_Page_BeginText(page_);
 
-    // Need to fill text using pen color
-    const WColor& penColor = painter()->pen().color();
-    HPDF_Page_SetRGBFill(page_,
-			 penColor.red() / 255.,
-			 penColor.green() / 255.,
-			 penColor.blue() / 255.);
-
     std::string s = trueTypeFont_ ? text.toUTF8() : text.narrow();
 
     HPDF_Page_TextRect(page_, left, fontSize_, right, 0, s.c_str(),
diff --git a/src/Wt/WPdfImage.h b/src/Wt/WPdfImage.h
index 0c8d370a..a3d0c293 100644
--- a/src/Wt/WPdfImage.h
+++ b/src/Wt/WPdfImage.h
@@ -7,6 +7,7 @@
 #ifndef WPDF_IMAGE_H_
 #define WPDF_IMAGE_H_
 
+#include <unordered_map>
 #include <Wt/WFont.h>
 #include <Wt/WPaintDevice.h>
 #include <Wt/WResource.h>
@@ -190,6 +191,8 @@ private:
   std::map<std::string, const char *> ttfFonts_;
   WFont currentFont_;
   std::string currentTtfFont_;
+  std::unordered_map<int, HPDF_ExtGState> alphaStrokeExtGStateMap_;
+  std::unordered_map<int, HPDF_ExtGState> alphaFillExtGStateMap_;
 
   bool myPdf_;
   double x_, y_;
@@ -199,6 +202,8 @@ private:
   void paintPath();
   void drawPlainPath(const WPainterPath& path);
   void applyTransform(const WTransform& f);
+  HPDF_ExtGState setStrokeColor(WColor color);
+  HPDF_ExtGState setFillColor(WColor color);
 };
 
 }
-- 
2.18.1

