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 <fr...@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

_______________________________________________
LibreOffice mailing list
LibreOffice@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice

Reply via email to