tdf#62728 add PDF/A-2 support, change UI default to use that
There was not much missing to make LibreOffice export valid PDF/A-2, so let's add that, and switch the UI to use that instead of A-1. The old PDF/A-1 feature is still accessible via UNO / filter parameter 'SelectPdfVersion': - 1 gives you PDF/A-1a - 2 gives you PDF/A-2b - 16 gives you PDF 1.6 Change-Id: Iea4262b119bcf33b75f3d1406cc793bdcaec65d1 Reviewed-on: https://gerrit.libreoffice.org/69294 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
This commit is contained in:
@@ -462,7 +462,7 @@ ImpPDFTabGeneralPage::ImpPDFTabGeneralPage(TabPageParent pParent, const SfxItemS
|
||||
, mxNfQuality(m_xBuilder->weld_metric_spin_button("quality", FieldUnit::PERCENT))
|
||||
, mxCbReduceImageResolution(m_xBuilder->weld_check_button("reduceresolution"))
|
||||
, mxCoReduceImageResolution(m_xBuilder->weld_combo_box("resolution"))
|
||||
, mxCbPDFA1b(m_xBuilder->weld_check_button("pdfa"))
|
||||
, mxCbPDFA2b(m_xBuilder->weld_check_button("pdfa"))
|
||||
, mxCbTaggedPDF(m_xBuilder->weld_check_button("tagged"))
|
||||
, mxCbExportFormFields(m_xBuilder->weld_check_button("forms"))
|
||||
, mxFormsFrame(m_xBuilder->weld_widget("formsframe"))
|
||||
@@ -530,16 +530,16 @@ void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent)
|
||||
mxCbWatermark->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleWatermarkHdl ) );
|
||||
mxFtWatermark->set_sensitive(false );
|
||||
mxEdWatermark->set_sensitive( false );
|
||||
mxCbPDFA1b->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleExportPDFAHdl));
|
||||
mxCbPDFA2b->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleExportPDFAHdl));
|
||||
switch( pParent->mnPDFTypeSelection )
|
||||
{
|
||||
default:
|
||||
case 0: mxCbPDFA1b->set_active( false ); // PDF 1.5
|
||||
mxCbPDFA2b->set_active( false ); // PDF 1.5
|
||||
break;
|
||||
case 1: mxCbPDFA1b->set_active(true); // PDF/A-1a
|
||||
case 2: mxCbPDFA2b->set_active(true); // PDF/A-2a
|
||||
break;
|
||||
}
|
||||
ToggleExportPDFAHdl( *mxCbPDFA1b );
|
||||
ToggleExportPDFAHdl( *mxCbPDFA2b );
|
||||
|
||||
mxCbExportFormFields->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl ) );
|
||||
|
||||
@@ -547,7 +547,7 @@ void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent)
|
||||
mbTaggedPDFUserSelection = pParent->mbUseTaggedPDF;
|
||||
mbExportFormFieldsUserSelection = pParent->mbExportFormFields;
|
||||
|
||||
if( !mxCbPDFA1b->get_active() )
|
||||
if( !mxCbPDFA2b->get_active() )
|
||||
{
|
||||
// the value for PDF/A set by the ToggleExportPDFAHdl method called before
|
||||
mxCbTaggedPDF->set_active( mbTaggedPDFUserSelection );
|
||||
@@ -643,9 +643,9 @@ void ImpPDFTabGeneralPage::GetFilterConfigItem( ImpPDFTabDialog* pParent )
|
||||
}
|
||||
|
||||
pParent->mnPDFTypeSelection = 0;
|
||||
if( mxCbPDFA1b->get_active() )
|
||||
if( mxCbPDFA2b->get_active() )
|
||||
{
|
||||
pParent->mnPDFTypeSelection = 1;
|
||||
pParent->mnPDFTypeSelection = 2;
|
||||
pParent->mbUseTaggedPDF = mbTaggedPDFUserSelection;
|
||||
pParent->mbExportFormFields = mbExportFormFieldsUserSelection;
|
||||
}
|
||||
@@ -759,11 +759,11 @@ IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportPDFAHdl, weld::ToggleButton&,
|
||||
ImpPDFTabSecurityPage* pSecPage = mpParent ? mpParent->getSecurityPage() : nullptr;
|
||||
if (pSecPage)
|
||||
{
|
||||
pSecPage->ImplPDFASecurityControl(!mxCbPDFA1b->get_active());
|
||||
pSecPage->ImplPDFASecurityControl(!mxCbPDFA2b->get_active());
|
||||
}
|
||||
|
||||
// PDF/A-1 needs tagged PDF, so force disable the control, will be forced in pdfexport.
|
||||
bool bPDFA1Sel = mxCbPDFA1b->get_active();
|
||||
bool bPDFA1Sel = mxCbPDFA2b->get_active();
|
||||
mxFormsFrame->set_sensitive(bPDFA1Sel);
|
||||
if(bPDFA1Sel)
|
||||
{
|
||||
@@ -784,14 +784,14 @@ IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportPDFAHdl, weld::ToggleButton&,
|
||||
mxCbExportFormFields->set_sensitive(true);
|
||||
}
|
||||
|
||||
// PDF/A-1 doesn't allow launch action, so enable/disable the selection on
|
||||
// PDF/A-2 doesn't allow launch action, so enable/disable the selection on
|
||||
// Link page
|
||||
ImpPDFTabLinksPage* pLinksPage = mpParent ? mpParent->getLinksPage() : nullptr;
|
||||
if (pLinksPage)
|
||||
pLinksPage->ImplPDFALinkControl(!mxCbPDFA1b->get_active());
|
||||
pLinksPage->ImplPDFALinkControl(!mxCbPDFA2b->get_active());
|
||||
|
||||
// if a password was set, inform the user that this will not be used in PDF/A case
|
||||
if( mxCbPDFA1b->get_active() && pSecPage && pSecPage->hasPassword() )
|
||||
if( mxCbPDFA2b->get_active() && pSecPage && pSecPage->hasPassword() )
|
||||
{
|
||||
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
|
||||
VclMessageType::Warning, VclButtonsType::Ok,
|
||||
@@ -1347,11 +1347,11 @@ void ImpPDFTabLinksPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent )
|
||||
|
||||
// now check the status of PDF/A selection
|
||||
// and set the link action accordingly
|
||||
// PDF/A-1 doesn't allow launch action on links
|
||||
// PDF/A-2 doesn't allow launch action on links
|
||||
|
||||
ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage();
|
||||
if (pGeneralPage)
|
||||
ImplPDFALinkControl(!pGeneralPage->mxCbPDFA1b->get_active());
|
||||
ImplPDFALinkControl(!pGeneralPage->mxCbPDFA2b->get_active());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ class ImpPDFTabGeneralPage : public SfxTabPage
|
||||
std::unique_ptr<weld::MetricSpinButton> mxNfQuality;
|
||||
std::unique_ptr<weld::CheckButton> mxCbReduceImageResolution;
|
||||
std::unique_ptr<weld::ComboBox> mxCoReduceImageResolution;
|
||||
std::unique_ptr<weld::CheckButton> mxCbPDFA1b;
|
||||
std::unique_ptr<weld::CheckButton> mxCbPDFA2b;
|
||||
std::unique_ptr<weld::CheckButton> mxCbTaggedPDF;
|
||||
std::unique_ptr<weld::CheckButton> mxCbExportFormFields;
|
||||
std::unique_ptr<weld::Widget> mxFormsFrame;
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
|
||||
void GetFilterConfigItem(ImpPDFTabDialog* paParent);
|
||||
void SetFilterConfigItem(ImpPDFTabDialog* paParent);
|
||||
bool IsPdfaSelected() const { return mxCbPDFA1b->get_active(); }
|
||||
bool IsPdfaSelected() const { return mxCbPDFA2b->get_active(); }
|
||||
};
|
||||
|
||||
/// Class tab page viewer
|
||||
|
||||
@@ -601,6 +601,13 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
|
||||
mbEncrypt = false; // no encryption
|
||||
xEnc.clear();
|
||||
break;
|
||||
case 2:
|
||||
aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_2;
|
||||
mbUseTaggedPDF = true; // force the tagged PDF as well
|
||||
mbRemoveTransparencies = false; // PDF/A-2 does allow transparencies
|
||||
mbEncrypt = false; // no encryption
|
||||
xEnc.clear();
|
||||
break;
|
||||
case 16:
|
||||
aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6;
|
||||
break;
|
||||
|
||||
@@ -463,11 +463,11 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="pdfa">
|
||||
<property name="label" translatable="yes" context="pdfgeneralpage|pdfa">Archive P_DF/A-1a (ISO 19005-1)</property>
|
||||
<property name="label" translatable="yes" context="pdfgeneralpage|pdfa">Archive P_DF/A-2b (ISO 19005-2)</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="tooltip_text" translatable="yes" context="pdfgeneralpage|pdfa|tooltip_text">Creates an ISO 19005-1 compliant PDF file, ideal for long-term document preservation</property>
|
||||
<property name="tooltip_text" translatable="yes" context="pdfgeneralpage|pdfa|tooltip_text">Creates an ISO 19005-2 compliant PDF file, ideal for long-term document preservation</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
enum class Orientation { Portrait, Inherit };
|
||||
|
||||
// in case the below enum is added PDF_1_6 PDF_1_7, please add them just after PDF_1_5
|
||||
enum class PDFVersion { PDF_1_2, PDF_1_3, PDF_1_4, PDF_1_5, PDF_1_6, PDF_A_1 };//i59651, PDF/A-1b & -1a, only -1b implemented for now
|
||||
enum class PDFVersion { PDF_1_2, PDF_1_3, PDF_1_4, PDF_1_5, PDF_1_6, PDF_A_1, PDF_A_2 };//i59651, PDF/A-1b & -1a, only -1b implemented for now
|
||||
// for the meaning of DestAreaType please look at PDF Reference Manual
|
||||
// version 1.4 section 8.2.1, page 475
|
||||
enum class DestAreaType { XYZ, FitRectangle };
|
||||
|
||||
@@ -1699,6 +1699,7 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal
|
||||
m_bEncryptThisStream( false ),
|
||||
m_nAccessPermissions(0),
|
||||
m_bIsPDF_A1( false ),
|
||||
m_bIsPDF_A2( false ),
|
||||
m_rOuterFace( i_rOuterFace )
|
||||
{
|
||||
#ifdef DO_TEST_PDF
|
||||
@@ -1793,6 +1794,10 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal
|
||||
if( m_bIsPDF_A1 )
|
||||
m_aContext.Version = PDFWriter::PDFVersion::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour
|
||||
|
||||
m_bIsPDF_A2 = (m_aContext.Version == PDFWriter::PDFVersion::PDF_A_2);
|
||||
if( m_bIsPDF_A2 )
|
||||
m_aContext.Version = PDFWriter::PDFVersion::PDF_1_6; //we could even use 1.7 features
|
||||
|
||||
if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 )
|
||||
SetReferenceDevice( VirtualDevice::RefDevMode::PDF1 );
|
||||
else
|
||||
@@ -3734,7 +3739,7 @@ bool PDFWriterImpl::emitLinkAnnotations()
|
||||
// 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( "<</Type/Annot" );
|
||||
if( m_bIsPDF_A1 )
|
||||
if( m_bIsPDF_A1 || m_bIsPDF_A2 )
|
||||
aLine.append( "/F 4" );
|
||||
aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
|
||||
|
||||
@@ -3956,7 +3961,7 @@ bool PDFWriterImpl::emitNoteAnnotations()
|
||||
// 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( "<</Type/Annot" );
|
||||
if( m_bIsPDF_A1 )
|
||||
if( m_bIsPDF_A1 || m_bIsPDF_A2 )
|
||||
aLine.append( "/F 4" );
|
||||
aLine.append( "/Subtype/Text/Rect[" );
|
||||
|
||||
@@ -4756,8 +4761,11 @@ bool PDFWriterImpl::emitWidgetAnnotations()
|
||||
}
|
||||
else if( rWidget.m_aListEntries.empty() )
|
||||
{
|
||||
// create a reset form action
|
||||
aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
|
||||
if( !m_bIsPDF_A2 )
|
||||
{
|
||||
// create a reset form action
|
||||
aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
|
||||
}
|
||||
}
|
||||
else if( rWidget.m_bSubmit )
|
||||
{
|
||||
@@ -5176,7 +5184,7 @@ bool PDFWriterImpl::emitCatalog()
|
||||
aLine.append( getResourceDictObj() );
|
||||
aLine.append( " 0 R" );
|
||||
// NeedAppearances must not be used if PDF is signed
|
||||
if( m_bIsPDF_A1
|
||||
if( m_bIsPDF_A1 || m_bIsPDF_A2
|
||||
#if HAVE_FEATURE_NSS
|
||||
|| ( m_nSignatureObject != -1 )
|
||||
#endif
|
||||
@@ -5490,7 +5498,7 @@ sal_Int32 PDFWriterImpl::emitNamedDestinations()
|
||||
// emits the output intent dictionary
|
||||
sal_Int32 PDFWriterImpl::emitOutputIntent()
|
||||
{
|
||||
if( !m_bIsPDF_A1 )
|
||||
if( !m_bIsPDF_A1 && !m_bIsPDF_A2 )
|
||||
return 0;
|
||||
|
||||
//emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1
|
||||
@@ -5597,7 +5605,7 @@ static void escapeStringXML( const OUString& rStr, OUString &rValue)
|
||||
// emits the document metadata
|
||||
sal_Int32 PDFWriterImpl::emitDocumentMetadata()
|
||||
{
|
||||
if( !m_bIsPDF_A1 )
|
||||
if( !m_bIsPDF_A1 && !m_bIsPDF_A2 )
|
||||
return 0;
|
||||
|
||||
//get the object number for all the destinations
|
||||
@@ -5618,8 +5626,14 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
|
||||
//PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
|
||||
aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
|
||||
aMetadataStream.append( " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
|
||||
aMetadataStream.append( " <pdfaid:part>1</pdfaid:part>\n" );
|
||||
aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" );
|
||||
if( m_bIsPDF_A2 )
|
||||
aMetadataStream.append( " <pdfaid:part>2</pdfaid:part>\n" );
|
||||
else
|
||||
aMetadataStream.append( " <pdfaid:part>1</pdfaid:part>\n" );
|
||||
if( m_bIsPDF_A2 )
|
||||
aMetadataStream.append( " <pdfaid:conformance>B</pdfaid:conformance>\n" );
|
||||
else
|
||||
aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" );
|
||||
aMetadataStream.append( " </rdf:Description>\n" );
|
||||
//... Dublin Core properties go here
|
||||
if( !m_aContext.DocumentInfo.Title.isEmpty() ||
|
||||
|
||||
@@ -976,6 +976,8 @@ i12626
|
||||
|
||||
/* true if PDF/A-1a or PDF/A-1b is output */
|
||||
bool m_bIsPDF_A1;
|
||||
/* true if PDF/A-2a is output */
|
||||
bool m_bIsPDF_A2;
|
||||
PDFWriter& m_rOuterFace;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user