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