chart2/source/controller/sidebar/ChartColorWrapper.cxx | 3 include/vcl/pdfwriter.hxx | 4 + sd/inc/Annotation.hxx | 5 + sd/source/core/annotations/Annotation.cxx | 12 +-- sd/source/filter/pdf/sdpdffilter.cxx | 5 + sd/source/ui/annotations/annotationtag.cxx | 23 ++++-- sd/source/ui/unoidl/unomodel.cxx | 17 +++- vcl/source/filter/ipdf/pdfread.cxx | 1 vcl/source/gdi/pdfwriter_impl.cxx | 64 ++++++++++++++++- vcl/source/pdf/PDFiumLibrary.cxx | 24 ++++-- 10 files changed, 136 insertions(+), 22 deletions(-)
New commits: commit 4142a5aef0d8bfc7ae7506f19873785139694612 Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Thu Jun 8 15:23:04 2023 +0100 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Jun 12 12:26:25 2023 +0200 check for empty model like ObjectIdentifier::getObjectPropertySet a speculative fix for: https://crashreport.libreoffice.org/stats/crash_details/5b3c8597-9ffa-49b8-8cc2-132e69456249 Change-Id: I4f45cf4c7ed51c814d4cb01b8f55709586d7a981 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152755 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/chart2/source/controller/sidebar/ChartColorWrapper.cxx b/chart2/source/controller/sidebar/ChartColorWrapper.cxx index e1011a684787..aee8483cadf4 100644 --- a/chart2/source/controller/sidebar/ChartColorWrapper.cxx +++ b/chart2/source/controller/sidebar/ChartColorWrapper.cxx @@ -39,6 +39,9 @@ namespace { OUString getCID(const css::uno::Reference<css::frame::XModel>& xModel) { + if (!xModel.is()) + return OUString(); + css::uno::Reference<css::frame::XController> xController(xModel->getCurrentController()); css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier(xController, css::uno::UNO_QUERY); if (!xSelectionSupplier.is()) commit b42fec3add3d2ff3b8e470d0c11c29b8b2f4b5d7 Author: Jaume Pujantell <jaume.pujant...@collabora.com> AuthorDate: Mon Jun 5 11:49:41 2023 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Jun 12 12:26:19 2023 +0200 pdfium: better suport for annotations and some fixes Added suport to import FreeText annotations. Added some suport to export graphical annotations. Fixed some color issues to be more inline with the pdfium library. Change-Id: I7371595ebb95594ee765ae532ca7c7d4f0499592 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152606 Tested-by: Jenkins Reviewed-by: Andras Timar <andras.ti...@collabora.com> (cherry picked from commit 53d610786ba8085fcce331174c74294c90c41a20) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152767 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx index 156720fed840..1abd5bf80151 100644 --- a/include/vcl/pdfwriter.hxx +++ b/include/vcl/pdfwriter.hxx @@ -66,6 +66,10 @@ struct PDFNote OUString Title; // optional title for the popup containing the note OUString Contents; // contents of the note css::util::DateTime maModificationDate; + bool isFreeText; + std::vector<basegfx::B2DPolygon> maPolygons; + Color annotColor; + Color interiorColor; }; class VCL_DLLPUBLIC PDFOutputStream diff --git a/sd/inc/Annotation.hxx b/sd/inc/Annotation.hxx index 707f2cdc8e78..00870dc703e8 100644 --- a/sd/inc/Annotation.hxx +++ b/sd/inc/Annotation.hxx @@ -133,6 +133,10 @@ public: return bool(m_pCustomAnnotationMarker); } + void setIsFreeText(bool value) { m_bIsFreeText = value; } + + bool isFreeText() const { return m_bIsFreeText; } + private: // destructor is private and will be called indirectly by the release call virtual ~Annotation() {} @@ -152,6 +156,7 @@ private: rtl::Reference<TextApiObject> m_TextRange; std::unique_ptr<CustomAnnotationMarker> m_pCustomAnnotationMarker; + bool m_bIsFreeText; }; } diff --git a/sd/source/core/annotations/Annotation.cxx b/sd/source/core/annotations/Annotation.cxx index 850f1a973ff1..432d38f9cb32 100644 --- a/sd/source/core/annotations/Annotation.cxx +++ b/sd/source/core/annotations/Annotation.cxx @@ -117,11 +117,13 @@ void createAnnotation(uno::Reference<office::XAnnotation>& xAnnotation, SdPage* sal_uInt32 Annotation::m_nLastId = 1; -Annotation::Annotation( const uno::Reference<uno::XComponentContext>& context, SdPage* pPage ) -: ::cppu::WeakComponentImplHelper<office::XAnnotation>(m_aMutex) -, ::cppu::PropertySetMixin<office::XAnnotation>(context, IMPLEMENTS_PROPERTY_SET, uno::Sequence<OUString>()) -, m_nId( m_nLastId++ ) -, mpPage( pPage ) +Annotation::Annotation(const uno::Reference<uno::XComponentContext>& context, SdPage* pPage) + : ::cppu::WeakComponentImplHelper<office::XAnnotation>(m_aMutex) + , ::cppu::PropertySetMixin<office::XAnnotation>(context, IMPLEMENTS_PROPERTY_SET, + uno::Sequence<OUString>()) + , m_nId(m_nLastId++) + , mpPage(pPage) + , m_bIsFreeText(false) { } diff --git a/sd/source/filter/pdf/sdpdffilter.cxx b/sd/source/filter/pdf/sdpdffilter.cxx index 39c6ada55f4e..35b1bffbcb73 100644 --- a/sd/source/filter/pdf/sdpdffilter.cxx +++ b/sd/source/filter/pdf/sdpdffilter.cxx @@ -189,6 +189,11 @@ bool SdPdfFilter::Import() rCustomAnnotationMarker.maFillColor = COL_TRANSPARENT; } } + else if (rPDFAnnotation.meSubType == vcl::pdf::PDFAnnotationSubType::FreeText) + { + auto* pAnnotation = static_cast<sd::Annotation*>(xAnnotation.get()); + pAnnotation->setIsFreeText(true); + } } } mrDocument.setLock(bWasLocked); diff --git a/sd/source/ui/annotations/annotationtag.cxx b/sd/source/ui/annotations/annotationtag.cxx index 7afe26ee54b0..dbadf4cb6fe1 100644 --- a/sd/source/ui/annotations/annotationtag.cxx +++ b/sd/source/ui/annotations/annotationtag.cxx @@ -524,18 +524,29 @@ BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected ) { ScopedVclPtrInstance< VirtualDevice > pVDev; - OUString sInitials(mxAnnotation->getInitials()); - if (sInitials.isEmpty()) - sInitials = getInitials(mxAnnotation->getAuthor()); + OUString sText; + auto* pAnnotation = dynamic_cast<sd::Annotation*>(mxAnnotation.get()); + if (pAnnotation && pAnnotation->isFreeText()) + { + sText = mxAnnotation->getTextRange()->getString(); + } + else + { + OUString sInitials(mxAnnotation->getInitials()); + if (sInitials.isEmpty()) + { + sInitials = getInitials(mxAnnotation->getAuthor()); + } - OUString sAuthor(sInitials + " " + OUString::number(mnIndex)); + sText = sInitials + " " + OUString::number(mnIndex); + } pVDev->SetFont( mrFont ); const int BORDER_X = 4; // pixels const int BORDER_Y = 4; // pixels - maSize = Size( pVDev->GetTextWidth( sAuthor ) + 2*BORDER_X, pVDev->GetTextHeight() + 2*BORDER_Y ); + maSize = Size(pVDev->GetTextWidth(sText) + 2 * BORDER_X, pVDev->GetTextHeight() + 2 * BORDER_Y); pVDev->SetOutputSizePixel( maSize, false ); Color aBorderColor( maColor ); @@ -563,7 +574,7 @@ BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected ) pVDev->DrawRect( aBorderRect ); pVDev->SetTextColor( maColor.IsDark() ? COL_WHITE : COL_BLACK ); - pVDev->DrawText( Point( BORDER_X, BORDER_Y ), sAuthor ); + pVDev->DrawText(Point(BORDER_X, BORDER_Y), sText); return pVDev->GetBitmapEx( aPos, maSize ); } diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx index 3ff5fd0de266..dd2c897b4930 100644 --- a/sd/source/ui/unoidl/unomodel.cxx +++ b/sd/source/ui/unoidl/unomodel.cxx @@ -1597,15 +1597,28 @@ static void ImplPDFExportComments( const uno::Reference< drawing::XDrawPage >& x uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() ); geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() ); + geometry::RealSize2D aRealSize2D(xAnnotation->getSize()); uno::Reference< text::XText > xText( xAnnotation->getTextRange() ); vcl::PDFNote aNote; aNote.Title = xAnnotation->getAuthor(); aNote.Contents = xText->getString(); aNote.maModificationDate = xAnnotation->getDateTime(); + auto* pAnnotation = dynamic_cast<sd::Annotation*>(xAnnotation.get()); + aNote.isFreeText = pAnnotation && pAnnotation->isFreeText(); + if (pAnnotation && pAnnotation->hasCustomAnnotationMarker()) + { + aNote.maPolygons = pAnnotation->getCustomAnnotationMarker().maPolygons; + aNote.annotColor = pAnnotation->getCustomAnnotationMarker().maLineColor; + aNote.interiorColor = pAnnotation->getCustomAnnotationMarker().maFillColor; + } - rPDFExtOutDevData.CreateNote( ::tools::Rectangle( Point( static_cast< ::tools::Long >( aRealPoint2D.X * 100 ), - static_cast< ::tools::Long >( aRealPoint2D.Y * 100 ) ), Size( 1000, 1000 ) ), aNote ); + rPDFExtOutDevData.CreateNote( + ::tools::Rectangle(Point(static_cast<::tools::Long>(aRealPoint2D.X * 100), + static_cast<::tools::Long>(aRealPoint2D.Y * 100)), + Size(static_cast<::tools::Long>(aRealSize2D.Width * 100), + static_cast<::tools::Long>(aRealSize2D.Height * 100))), + aNote); } } catch (const uno::Exception&) diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx index deb341157137..e3d70f7c0ade 100644 --- a/vcl/source/filter/ipdf/pdfread.cxx +++ b/vcl/source/filter/ipdf/pdfread.cxx @@ -176,6 +176,7 @@ findAnnotations(const std::unique_ptr<vcl::pdf::PDFiumPage>& pPage, basegfx::B2D auto eSubtype = pAnnotation->getSubType(); if (eSubtype == vcl::pdf::PDFAnnotationSubType::Text + || eSubtype == vcl::pdf::PDFAnnotationSubType::FreeText || eSubtype == vcl::pdf::PDFAnnotationSubType::Polygon || eSubtype == vcl::pdf::PDFAnnotationSubType::Circle || eSubtype == vcl::pdf::PDFAnnotationSubType::Square diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 36fa35e0f6a1..718433aafc02 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -58,6 +58,7 @@ #include <tools/stream.hxx> #include <tools/helpers.hxx> #include <tools/urlobj.hxx> +#include <tools/UnitConversion.hxx> #include <tools/zcodec.hxx> #include <unotools/configmgr.hxx> #include <vcl/bitmapex.hxx> @@ -3901,10 +3902,64 @@ void PDFWriterImpl::emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry c { appendObjectID(rNote.m_nObject, aLine); - aLine.append("<</Type /Annot /Subtype /Text "); + aLine.append("<</Type /Annot /Subtype "); + if (rNote.m_aContents.maPolygons.size() == 1) + { + auto const& rPolygon = rNote.m_aContents.maPolygons[0]; + aLine.append(rPolygon.isClosed() ? "/Polygon " : "/Polyline "); + aLine.append("/Vertices ["); + for (sal_uInt32 i = 0; i < rPolygon.count(); ++i) + { + appendDouble(convertMm100ToPoint(rPolygon.getB2DPoint(i).getX()), aLine, nLog10Divisor); + aLine.append(" "); + appendDouble(m_aPages[rNote.m_nPage].getHeight() + - convertMm100ToPoint(rPolygon.getB2DPoint(i).getY()), + aLine, nLog10Divisor); + aLine.append(" "); + } + aLine.append("] "); + aLine.append("/C ["); + appendColor(rNote.m_aContents.annotColor, aLine, false); + aLine.append("] "); + if (rPolygon.isClosed()) + { + aLine.append("/IC ["); + appendColor(rNote.m_aContents.interiorColor, aLine, false); + aLine.append("] "); + } + } + else if (rNote.m_aContents.maPolygons.size() > 1) + { + aLine.append("/Ink /InkList ["); + for (auto const& rPolygon : rNote.m_aContents.maPolygons) + { + aLine.append("["); + for (sal_uInt32 i = 0; i < rPolygon.count(); ++i) + { + appendDouble(convertMm100ToPoint(rPolygon.getB2DPoint(i).getX()), aLine, + nLog10Divisor); + aLine.append(" "); + appendDouble(m_aPages[rNote.m_nPage].getHeight() + - convertMm100ToPoint(rPolygon.getB2DPoint(i).getY()), + aLine, nLog10Divisor); + aLine.append(" "); + } + aLine.append("]"); + aLine.append("/C ["); + appendColor(rNote.m_aContents.annotColor, aLine, false); + aLine.append("] "); + } + aLine.append("] "); + } + else if (rNote.m_aContents.isFreeText) + aLine.append("/FreeText "); + else + aLine.append("/Text "); -// i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should' -// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3 + aLine.append("/BS<</W 0>>"); + + // i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should' + // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3 if (m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3) aLine.append("/F 4 "); @@ -9299,6 +9354,8 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) aStream.append(" re\n"); aStream.append("f*\n"); + // Reset non-stroking color in case the XObject uses the default + aStream.append("0 0 0 rg\n"); // No reference XObject, draw the form XObject containing the original // page streams. aStream.append("/Im"); @@ -10356,6 +10413,7 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN rNoteEntry.m_aPopUpAnnotation.m_nParentObject = rNoteEntry.m_nObject; rNoteEntry.m_aContents = rNote; rNoteEntry.m_aRect = rRect; + rNoteEntry.m_nPage = nPageNr; // convert to default user space now, since the mapmode may change m_aPages[nPageNr].convertRect(rNoteEntry.m_aRect); diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index e0562c4dbf9b..c445e5e5ad98 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -1126,24 +1126,36 @@ basegfx::B2DRectangle PDFiumAnnotationImpl::getRectangle() Color PDFiumAnnotationImpl::getColor() { - Color aColor = COL_TRANSPARENT; unsigned int nR, nG, nB, nA; if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_Color, &nR, &nG, &nB, &nA)) { - aColor = Color(ColorAlpha, nA, nR, nG, nB); + return Color(ColorAlpha, nA, nR, nG, nB); } - return aColor; + // FPDFAnnot_GetColor can return false if there is an appearance stream + // So we search for a color with getStrokeColor + for (int i = 0; i < getObjectCount(); ++i) + { + if (getObject(i)->getType() == PDFPageObjectType::Path) + return getObject(i)->getStrokeColor(); + } + return COL_TRANSPARENT; } Color PDFiumAnnotationImpl::getInteriorColor() { - Color aColor = COL_TRANSPARENT; unsigned int nR, nG, nB, nA; if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_InteriorColor, &nR, &nG, &nB, &nA)) { - aColor = Color(ColorAlpha, nA, nR, nG, nB); + return Color(ColorAlpha, nA, nR, nG, nB); } - return aColor; + // FPDFAnnot_GetColor can return false if there is an appearance stream + // So we search for a color with getFillColor + for (int i = 0; i < getObjectCount(); ++i) + { + if (getObject(i)->getType() == PDFPageObjectType::Path) + return getObject(i)->getFillColor(); + } + return COL_TRANSPARENT; } size_t PDFiumAnnotationImpl::getAttachmentPointsCount()