Date: prev next · Thread: first prev next last
2013 Archives by date, by thread · List index


Hi,

this patch adds multicolor gradients to libmspub.
+ fixes pattern colors.

Patch is against git master.

Greetings,
Franz Schmid
From 01af5aef449d1c0d0facd37a75f998657a662c9c Mon Sep 17 00:00:00 2001
From: Franz Schmid <franz@linux-hp-i7.site>
Date: Mon, 8 Apr 2013 22:00:39 +0200
Subject: [PATCH] Added complete multicolor gradient support and fixed pattern colors.

---
 src/lib/EscherContainerType.h |    3 +-
 src/lib/EscherFieldIds.h      |    5 ++
 src/lib/Fill.cpp              |   41 +++++++++++++--
 src/lib/Fill.h                |    9 +++-
 src/lib/MSPUBParser.cpp       |  117 ++++++++++++++++++++++++++++++++---------
 src/lib/MSPUBParser.h         |    2 +-
 src/lib/MSPUBTypes.h          |    3 +-
 src/lib/PolygonUtils.cpp      |    2 +-
 8 files changed, 146 insertions(+), 36 deletions(-)

diff --git a/src/lib/EscherContainerType.h b/src/lib/EscherContainerType.h
index 3332b02..7a8ee19 100644
--- a/src/lib/EscherContainerType.h
+++ b/src/lib/EscherContainerType.h
@@ -38,11 +38,12 @@
 #define OFFICE_ART_CLIENT_ANCHOR      0xF010
 #define OFFICE_ART_BLIP_PNG           0xF01E
 #define OFFICE_ART_BLIP_JPEG          0xF01D
+#define OFFICE_ART_BLIP_JPEGCMYK      0xF02A
 #define OFFICE_ART_BLIP_DIB           0xF01F
 #define OFFICE_ART_BLIP_EMF           0xF01A
 #define OFFICE_ART_BLIP_WMF           0xF01B
 #define OFFICE_ART_BLIP_PICT          0xF01C
-#define OFFICE_ART_BLIP_TIFF          0xF020
+#define OFFICE_ART_BLIP_TIFF          0xF029
 #define OFFICE_ART_FOPT               0xF00B
 #define OFFICE_ART_TERTIARY_FOPT      0xF122
 #define OFFICE_ART_FSP                0xF00A
diff --git a/src/lib/EscherFieldIds.h b/src/lib/EscherFieldIds.h
index b770c38..7c7446e 100644
--- a/src/lib/EscherFieldIds.h
+++ b/src/lib/EscherFieldIds.h
@@ -47,6 +47,11 @@
 #define FIELDID_FILL_TYPE              0x0180
 #define FIELDID_FILL_ANGLE             0x018B
 #define FIELDID_FILL_FOCUS             0x018C
+#define FIELDID_FILL_TO_LEFT           0x018D
+#define FIELDID_FILL_TO_TOP            0x018E
+#define FIELDID_FILL_TO_RIGHT          0x018F
+#define FIELDID_FILL_TO_BOTTOM         0x0190
+#define FIELDID_FILL_SHADE_COMPLEX     0xC197
 #define FIELDID_FIELD_STYLE_BOOL_PROPS 0x01BF
 #define FIELDID_ADJUST_VALUE_1         0x0147
 #define FIELDID_ADJUST_VALUE_2         0x0148
diff --git a/src/lib/Fill.cpp b/src/lib/Fill.cpp
index aeaeb37..329a685 100644
--- a/src/lib/Fill.cpp
+++ b/src/lib/Fill.cpp
@@ -82,14 +82,14 @@ WPXPropertyListVector PatternFill::getProperties(WPXPropertyList *out) const
     if (type == DIB && data->size() >= 0x36 + 8)
     {
       fixedImg.append(data->getDataBuffer(), 0x36);
-      fixedImg.append(bgColor.b);
-      fixedImg.append(bgColor.g);
-      fixedImg.append(bgColor.r);
-      fixedImg.append('\0');
       fixedImg.append(fgColor.b);
       fixedImg.append(fgColor.g);
       fixedImg.append(fgColor.r);
       fixedImg.append('\0');
+      fixedImg.append(bgColor.b);
+      fixedImg.append(bgColor.g);
+      fixedImg.append(bgColor.r);
+      fixedImg.append('\0');
       fixedImg.append(data->getDataBuffer() + 0x36 + 8, data->size() - 0x36 - 8);
       data = &fixedImg;
     }
@@ -116,15 +116,38 @@ WPXPropertyListVector SolidFill::getProperties(WPXPropertyList *out) const
   return WPXPropertyListVector();
 }
 
-GradientFill::GradientFill(const MSPUBCollector *owner, double angle, int type) : Fill(owner), 
m_stops(), m_angle(angle), m_type(type)
+GradientFill::GradientFill(const MSPUBCollector *owner, double angle, int type) : Fill(owner), 
m_stops(), m_angle(angle), m_type(type), m_fillLeftVal(0.0), m_fillTopVal(0.0), 
m_fillRightVal(0.0), m_fillBottomVal(0.0)
 {
 }
 
+void GradientFill::setFillCenter(double left, double top, double right, double bottom)
+{
+  m_fillLeftVal = left;
+  m_fillTopVal = top;
+  m_fillRightVal = right;
+  m_fillBottomVal = bottom;
+}
+
 void GradientFill::addColor(ColorReference c, unsigned offsetPercent, double opacity)
 {
   m_stops.push_back(StopInfo(c, offsetPercent, opacity));
 }
 
+void GradientFill::addColorReverse(ColorReference c, unsigned offsetPercent, double opacity)
+{
+  m_stops.insert(m_stops.begin(), StopInfo(c, offsetPercent, opacity));
+}
+
+void GradientFill::completeComplexFill()
+{
+  unsigned stops = m_stops.size();
+  for (unsigned i = stops; i > 0; i--)
+  {
+    if (m_stops[i-1].m_offsetPercent != 50)
+      m_stops.push_back(StopInfo(m_stops[i-1].m_colorReference, 50 - m_stops[i-1].m_offsetPercent 
+ 50, m_stops[i-1].m_opacity));
+  }
+}
+
 WPXPropertyListVector GradientFill::getProperties(WPXPropertyList *out) const
 {
   WPXPropertyListVector ret;
@@ -139,6 +162,14 @@ WPXPropertyListVector GradientFill::getProperties(WPXPropertyList *out) const
     break;
   case 5:
     out->insert("libmspub:shade", "center");
+    if ((m_fillLeftVal > 0.5) && (m_fillTopVal > 0.5) && (m_fillRightVal > 0.5) && 
(m_fillBottomVal > 0.5))
+         out->insert("libmspub:shade-ref-point", "bottom-right");
+    else if ((m_fillLeftVal < 0.5) && (m_fillTopVal < 0.5) && (m_fillRightVal < 0.5) && 
(m_fillBottomVal < 0.5))
+      out->insert("libmspub:shade-ref-point", "top-left");
+    else if ((m_fillLeftVal > 0.5) && (m_fillTopVal < 0.5) && (m_fillRightVal > 0.5) && 
(m_fillBottomVal < 0.5))
+      out->insert("libmspub:shade-ref-point", "top-right");
+    else if ((m_fillLeftVal < 0.5) && (m_fillTopVal > 0.5) && (m_fillRightVal < 0.5) && 
(m_fillBottomVal > 0.5))
+      out->insert("libmspub:shade-ref-point", "bottom-left");
     break;
   case 6:
     out->insert("libmspub:shade", "shape");
diff --git a/src/lib/Fill.h b/src/lib/Fill.h
index e226a65..7bded34 100644
--- a/src/lib/Fill.h
+++ b/src/lib/Fill.h
@@ -105,12 +105,19 @@ class GradientFill : public Fill
   std::vector<StopInfo> m_stops;
   double m_angle;
   int m_type;
+  double m_fillLeftVal;
+  double m_fillTopVal;
+  double m_fillRightVal;
+  double m_fillBottomVal;
 public:
   GradientFill(const MSPUBCollector *owner, double angle = 0, int type = 7);
+  void setFillCenter(double left, double top, double right, double bottom);
   void addColor(ColorReference c, unsigned offsetPercent, double opacity);
+  void addColorReverse(ColorReference c, unsigned offsetPercent, double opacity);
+  void completeComplexFill();
   WPXPropertyListVector getProperties(WPXPropertyList *out) const;
 private:
-  GradientFill(const GradientFill &) : Fill(NULL), m_stops(), m_angle(0), m_type(7) { }
+  GradientFill(const GradientFill &) : Fill(NULL), m_stops(), m_angle(0), m_type(7), 
m_fillLeftVal(0.0), m_fillTopVal(0.0), m_fillRightVal(0.0), m_fillBottomVal(0.0) { }
   GradientFill &operator=(const GradientFill &);
 };
 }
diff --git a/src/lib/MSPUBParser.cpp b/src/lib/MSPUBParser.cpp
index 584c227..21ade39 100644
--- a/src/lib/MSPUBParser.cpp
+++ b/src/lib/MSPUBParser.cpp
@@ -189,6 +189,8 @@ libmspub::ImgType libmspub::MSPUBParser::imgTypeByBlipType(unsigned short type)
     return PNG;
   case OFFICE_ART_BLIP_JPEG:
     return JPEG;
+  case OFFICE_ART_BLIP_JPEGCMYK:
+    return JPEGCMYK;
   case OFFICE_ART_BLIP_WMF:
     return WMF;
   case OFFICE_ART_BLIP_DIB:
@@ -226,10 +228,18 @@ int libmspub::MSPUBParser::getStartOffset(ImgType type, unsigned short 
initial)
     oneUid = recInstance == 0x46A || recInstance == 0x6E2;
     offset = 0x11;
     break;
+  case JPEGCMYK:
+    oneUid = recInstance == 0x46B || recInstance == 0x6E3;
+    offset = 33;
+    break;
   case DIB:
     oneUid = recInstance == 0x7A8;
     offset = 0x11;
     break;
+  case TIFF:
+    oneUid = recInstance == 0x6E4;
+    offset = 0x11;
+    break;
   default:
     break;
   }
@@ -1545,7 +1555,7 @@ void libmspub::MSPUBParser::parseEscherShape(WPXInputStream *input, const 
Escher
           bool useLine = lineExistsByFlagPointer(
                            ptr_lineFlags, ptr_geomFlags);
           bool skipIfNotBg = false;
-          boost::shared_ptr<Fill> ptr_fill = getNewFill(foptValues.m_scalarValues, skipIfNotBg);
+          boost::shared_ptr<Fill> ptr_fill = getNewFill(foptValues.m_scalarValues, skipIfNotBg, 
foptValues.m_complexValues);
           unsigned lineWidth = 0;
           if (useLine)
           {
@@ -1814,7 +1824,7 @@ void libmspub::MSPUBParser::parseEscherShape(WPXInputStream *input, const 
Escher
 }
 
 boost::shared_ptr<libmspub::Fill> libmspub::MSPUBParser::getNewFill(const std::map<unsigned short, 
unsigned> &foptProperties,
-    bool &skipIfNotBg)
+    bool &skipIfNotBg, std::map<unsigned short, std::vector<unsigned char> > &foptValues)
 {
   const FillType *ptr_fillType = (FillType *)getIfExists_const(foptProperties, FIELDID_FILL_TYPE);
   FillType fillType = ptr_fillType ? *ptr_fillType : SOLID;
@@ -1835,7 +1845,7 @@ boost::shared_ptr<libmspub::Fill> libmspub::MSPUBParser::getNewFill(const 
std::m
   case GRADIENTCENTER:
   case GRADIENTSHAPE:
   case GRADIENTNORMAL:
-  case GRADIENT: //FIXME: The handling of multi-color gradients here is quite bad.
+  case GRADIENT:
   {
     int angle;
     const int *ptr_angle = (const int *)getIfExists_const(foptProperties, FIELDID_FILL_ANGLE);
@@ -1865,29 +1875,86 @@ boost::shared_ptr<libmspub::Fill> libmspub::MSPUBParser::getNewFill(const 
std::m
     default:
       break;
     }
+    double fillLeftVal = 0.0;
+    const unsigned *ptr_fillLeft = getIfExists_const(foptProperties, FIELDID_FILL_TO_LEFT);
+    if (ptr_fillLeft)
+      fillLeftVal = toFixedPoint(*ptr_fillLeft);
+    double fillTopVal = 0.0;
+    const unsigned *ptr_fillTop = getIfExists_const(foptProperties, FIELDID_FILL_TO_TOP);
+    if (ptr_fillTop)
+      fillTopVal = toFixedPoint(*ptr_fillTop);
+    double fillRightVal = 0.0;
+    const unsigned *ptr_fillRight = getIfExists_const(foptProperties, FIELDID_FILL_TO_RIGHT);
+    if (ptr_fillRight)
+      fillRightVal = toFixedPoint(*ptr_fillRight);
+    double fillBottomVal = 0.0;
+    const unsigned *ptr_fillBottom = getIfExists_const(foptProperties, FIELDID_FILL_TO_BOTTOM);
+    if (ptr_fillBottom)
+      fillBottomVal = toFixedPoint(*ptr_fillBottom);
 
     boost::shared_ptr<GradientFill> ret(new GradientFill(m_collector, angle, (int)fillType));
-    if (fillFocus ==  0)
-    {
-      ret->addColor(firstColor, 0, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
-      ret->addColor(secondColor, 100, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
-    }
-    else if (fillFocus == 100)
-    {
-      ret->addColor(secondColor, 0, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 0xFFFF 
: 1);
-      ret->addColor(firstColor, 100, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
-    }
-    else if (fillFocus > 0)
-    {
-      ret->addColor(firstColor, 0, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
-      ret->addColor(secondColor, fillFocus, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
-      ret->addColor(firstColor, 100, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+    ret->setFillCenter(fillLeftVal, fillTopVal, fillRightVal, fillBottomVal);
+       
+    const unsigned *ptr_fillGrad = getIfExists_const(foptProperties, FIELDID_FILL_SHADE_COMPLEX);
+    if (ptr_fillGrad)
+       {
+      const std::vector<unsigned char> gradientData = foptValues[FIELDID_FILL_SHADE_COMPLEX];
+      if (gradientData.size() > 6)
+      {
+        unsigned short numEntries = gradientData[0] | (gradientData[1] << 8);
+        unsigned offs = 6;
+        for (unsigned i = 0; i < numEntries; ++i)
+        {
+          unsigned color = gradientData[offs] | (unsigned(gradientData[offs + 1]) << 8) | 
(unsigned(gradientData[offs + 2]) << 16) | (unsigned(gradientData[offs + 3]) << 24);
+          offs += 4;
+          int posi = (int)(toFixedPoint(gradientData[offs] | (unsigned(gradientData[offs + 1]) << 
8) | (unsigned(gradientData[offs + 2]) << 16) | (unsigned(gradientData[offs + 3]) << 24)) * 100);
+          offs += 4;
+          ColorReference sColor(color, color);
+          if (fillFocus ==  0)
+            ret->addColor(sColor, posi, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+          else if (fillFocus == 100)
+            ret->addColorReverse(sColor, 100 - posi, ptr_fillOpacity ? (double)(*ptr_fillOpacity) 
/ 0xFFFF : 1);
+          else if (fillFocus > 0)
+            ret->addColor(sColor, posi / 2, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF 
: 1);
+          else if (fillFocus < 0)
+            ret->addColorReverse(sColor, (100 - posi) / 2, ptr_fillOpacity ? 
(double)(*ptr_fillOpacity) / 0xFFFF : 1);
+        }
+        if ((fillFocus < 0) || ((fillFocus > 0) && (fillFocus < 100)))
+          ret->completeComplexFill();
+      }
     }
-    else if (fillFocus < 0)
+    else
     {
-      ret->addColor(secondColor, 0, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 0xFFFF 
: 1);
-      ret->addColor(firstColor, 100 + fillFocus, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 
0xFFFF : 1);
-      ret->addColor(secondColor, 100, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+      if (fillFocus ==  0)
+      {
+        ret->addColor(firstColor, 0, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+        ret->addColor(secondColor, 100, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+      }
+      else if (fillFocus == 100)
+      {
+        ret->addColor(secondColor, 0, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+        ret->addColor(firstColor, 100, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+      }
+      else if (fillFocus > 0)
+      {
+        ret->addColor(secondColor, 0, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+        ret->addColor(firstColor, fillFocus, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF 
: 1);
+        ret->addColor(secondColor, 100, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+
+//        ret->addColor(firstColor, 0, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+//        ret->addColor(secondColor, fillFocus, ptr_fillBackOpacity ? 
(double)(*ptr_fillBackOpacity) / 0xFFFF : 1);
+//        ret->addColor(firstColor, 100, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 
1);
+      }
+      else if (fillFocus < 0)
+      {
+        ret->addColor(firstColor, 0, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+        ret->addColor(secondColor, 100 + fillFocus, ptr_fillBackOpacity ? 
(double)(*ptr_fillBackOpacity) / 0xFFFF : 1);
+        ret->addColor(firstColor, 100, ptr_fillOpacity ? (double)(*ptr_fillOpacity) / 0xFFFF : 1);
+
+//        ret->addColor(secondColor, 0, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+//        ret->addColor(firstColor, 100 + fillFocus, ptr_fillOpacity ? (double)(*ptr_fillOpacity) 
/ 0xFFFF : 1);
+//        ret->addColor(secondColor, 100, ptr_fillBackOpacity ? (double)(*ptr_fillBackOpacity) / 
0xFFFF : 1);
+      }
     }
     return ret;
   }
@@ -1898,10 +1965,7 @@ boost::shared_ptr<libmspub::Fill> libmspub::MSPUBParser::getNewFill(const 
std::m
     int rotation = 0;
     const int *ptr_rotation = (const int *)getIfExists_const(foptProperties, FIELDID_ROTATION);
     if (ptr_rotation)
-    {
       rotation = (int)doubleModulo(toFixedPoint(*ptr_rotation), 360);
-      MSPUB_DEBUG_MSG(("Rotation value %d\n", rotation));
-    }
     const unsigned *ptr_bgPxId = getIfExists_const(foptProperties, FIELDID_BG_PXID);
     if (ptr_bgPxId && *ptr_bgPxId <= m_escherDelayIndices.size() && 
m_escherDelayIndices[*ptr_bgPxId - 1] >= 0)
     {
@@ -1915,7 +1979,8 @@ boost::shared_ptr<libmspub::Fill> libmspub::MSPUBParser::getNewFill(const 
std::m
     const unsigned *ptr_fillColor = getIfExists_const(foptProperties, FIELDID_FILL_COLOR);
     const unsigned *ptr_fillBackColor = getIfExists_const(foptProperties, FIELDID_FILL_BACK_COLOR);
     ColorReference fill = ptr_fillColor ? ColorReference(*ptr_fillColor) : 
ColorReference(0x00FFFFFF);
-    ColorReference back = ptr_fillBackColor ? ColorReference(*ptr_fillBackColor) : 
ColorReference(0x08000000);
+//    ColorReference back = ptr_fillBackColor ? ColorReference(*ptr_fillBackColor) : 
ColorReference(0x08000000);
+    ColorReference back = ptr_fillBackColor ? ColorReference(*ptr_fillBackColor) : 
ColorReference(0x00FFFFFF);
     if (ptr_bgPxId && *ptr_bgPxId <= m_escherDelayIndices.size() && 
m_escherDelayIndices[*ptr_bgPxId - 1 ] >= 0)
     {
       return boost::shared_ptr<Fill>(new PatternFill(m_escherDelayIndices[*ptr_bgPxId - 1], 
m_collector, fill, back));
diff --git a/src/lib/MSPUBParser.h b/src/lib/MSPUBParser.h
index 1cc8215..d7f2514 100644
--- a/src/lib/MSPUBParser.h
+++ b/src/lib/MSPUBParser.h
@@ -162,7 +162,7 @@ protected:
   unsigned getFontIndex(WPXInputStream *input, const MSPUBBlockInfo &info);
   CharacterStyle getCharacterStyle(WPXInputStream *input);
   ParagraphStyle getParagraphStyle(WPXInputStream *input);
-  boost::shared_ptr<Fill> getNewFill(const std::map<unsigned short, unsigned> &foptValues, bool 
&skipIfNotBg);
+  boost::shared_ptr<Fill> getNewFill(const std::map<unsigned short, unsigned> &foptValues, bool 
&skipIfNotBg, std::map<unsigned short, std::vector<unsigned char> > &foptVal);
 
   WPXInputStream *m_input;
   MSPUBCollector *m_collector;
diff --git a/src/lib/MSPUBTypes.h b/src/lib/MSPUBTypes.h
index 2950ad5..7884725 100644
--- a/src/lib/MSPUBTypes.h
+++ b/src/lib/MSPUBTypes.h
@@ -203,7 +203,8 @@ enum ImgType
   EMF,
   TIFF,
   DIB,
-  PICT
+  PICT,
+  JPEGCMYK
 };
 
 } // namespace libmspub
diff --git a/src/lib/PolygonUtils.cpp b/src/lib/PolygonUtils.cpp
index ae8f2e4..8fb4c7c 100644
--- a/src/lib/PolygonUtils.cpp
+++ b/src/lib/PolygonUtils.cpp
@@ -5379,7 +5379,7 @@ const CustomShape *libmspub::getCustomShape(ShapeType type)
   case HEART:
     return &CS_HEART;
   case PICTURE_FRAME:
-    return NULL; //FIXME
+    return &CS_RECTANGLE; // treat it as RECTANGLE for now
   case QUAD_ARROW:
     return &CS_QUAD_ARROW;
   case BEVEL:
-- 
1.7.1


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.