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
- [PATCH] Adding multicolor gradients to libmspub · Franz Schmid
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.