Description: A code that worked in previous versions no longer works in LibreOffice 24 and 25. The method that checks the PDF/A-1 format returns the following errors: Le fichier n'est pas valide PDF/A-1b voici les 1 erreur(s) : 7.2 : Error on MetaData, CreationDate present in the document catalog dictionary doesn't match with XMP information Steps to Reproduce: 1.To generate pdf file from odt file StringBuffer _sbUrl = new StringBuffer( fileDest.startsWith( "file:///" ) ? "" : "file:///" ); _sbUrl.append( fileDest ); PropertyValue[] mediaDescriptorProperties = new PropertyValue[4]; PropertyValue[] filtersProperties = new PropertyValue[4]; // Utiliser la norme A1 filtersProperties[0] = new PropertyValue(); filtersProperties[0].Name = "SelectPdfVersion"; filtersProperties[0].Value = 1; filtersProperties[1] = new PropertyValue(); filtersProperties[1].Name = "UseTaggedPDF"; filtersProperties[1].Value = Boolean.TRUE; filtersProperties[2] = new PropertyValue(); filtersProperties[2].Name = "UseLosslessCompression"; filtersProperties[2].Value = Boolean.TRUE; filtersProperties[3] = new PropertyValue(); filtersProperties[3].Name = "Quality"; filtersProperties[3].Value = 100; PropertyValue[] filterData = null; if (pages != null && pages.length() > 0 && !"All".equals( pages )) { filterData = new PropertyValue[1]; filterData[0] = new PropertyValue(); filterData[0].Name = "PageRange"; filterData[0].Value = pages; } mediaDescriptorProperties[0] = new PropertyValue(); mediaDescriptorProperties[0].Name = "FilterName"; mediaDescriptorProperties[0].Value = "writer_pdf_Export"; mediaDescriptorProperties[1] = new PropertyValue(); mediaDescriptorProperties[1].Name = "FilterData"; mediaDescriptorProperties[1].Value = filtersProperties; mediaDescriptorProperties[3] = new PropertyValue(); mediaDescriptorProperties[3].Name = "Overwrite"; mediaDescriptorProperties[3].Value = new Boolean( true ); if (filterData != null) { mediaDescriptorProperties[2] = new PropertyValue(); mediaDescriptorProperties[2].Name = "FilterData"; mediaDescriptorProperties[2].Value = filterData; } else { mediaDescriptorProperties[2] = new PropertyValue(); mediaDescriptorProperties[2].Name = "PageRange"; mediaDescriptorProperties[2].Value = pages; } String adresseFichier = _sbUrl.toString().replace( ".odt", ".pdf" ).replace( ".rtf", ".pdf" ); try { XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, _xcomponent ); xstorable.storeToURL( adresseFichier, mediaDescriptorProperties );// On enregistre le pdf }catch(Exception e){ e.printStackTrace(); } ******************************************************************************************************************* 2.To control the pdf a1 validity package isc.template.pdf; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; import org.apache.pdfbox.preflight.Format; import org.apache.pdfbox.preflight.PreflightDocument; import org.apache.pdfbox.preflight.ValidationResult; import org.apache.pdfbox.preflight.ValidationResult.ValidationError; import org.apache.pdfbox.preflight.exception.SyntaxValidationException; import org.apache.pdfbox.preflight.parser.PreflightParser; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.PDFAIdentificationSchema; import org.apache.xmpbox.schema.XMPBasicSchema; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.xml.XmpSerializer; import isc.appli.template.ooo.OooWriter; import isc.appli.util.AppliInitializer; import isc.appli.util.AppliToolkit; import isc.appli.web.spring.ServeurSpringConnector; import isc.util.text.TextUtil; public class PdfA1 { public static boolean controleValidite( String fileName ) { ValidationResult result = null; try { PreflightParser parser = new PreflightParser( fileName ); /* * Parse the PDF file with PreflightParser that inherits from the NonSequentialParser. Some additional controls are present to check a set of PDF/A requirements. (Stream length * consistency, EOL after some Keyword...) */ PDDocument pd = parser.parse( Format.PDF_A1A ); /* * Once the syntax validation is done, the parser can provide a PreflightDocument (that inherits from PDDocument) This document process the end of PDF/A validation. */ PreflightDocument document = (PreflightDocument) pd; // Get validation result result = document.validate(); document.close(); } catch (SyntaxValidationException e) { /* * the parse method can throw a SyntaxValidationException if the PDF file can't be parsed. In this case, the exception contains an instance of ValidationResult */ result = e.getResult(); } catch (Exception e) { /* * the parse method can throw a SyntaxValidationException if the PDF file can't be parsed. In this case, the exception contains an instance of ValidationResult */ e.printStackTrace(); return false; } AppliToolkit.afficher( "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤" ); // display validation result if (result.isValid()) { AppliToolkit.afficher( "Le fichier " + fileName + " est valide PDF/A-1b" ); } else { System.out.println( "***************************************************" ); AppliToolkit .afficher( "Le fichier " + fileName + " n'est pas valide PDF/A-1b voici les " + result.getErrorsList().size() + " erreur(s) :" ); for (ValidationError error : result.getErrorsList()) { AppliToolkit.afficher( error.getErrorCode() + " : " + error.getDetails() ); } System.out.println( "***************************************************" ); } AppliToolkit.afficher( "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤" ); return result.isValid(); } private static void createPDF( String file ) { try { // Creating PDF document object PDDocument document = Loader.loadPDF( new File( "c:\\fichiers_travail\\testa1.pdf" ) ); isc.util.log.LogUtil.getLogger().info( "NOMBRE de pages: " + document.getNumberOfPages() ); // Color profile // Create output intent InputStream colorProfile = PdfA1.class.getResourceAsStream( "/pdfbox/pdfa/sRGB.icc" ); PDOutputIntent intent = new PDOutputIntent( document, colorProfile ); intent.setInfo( "sRGB IEC61966-2.1" ); intent.setOutputCondition( "sRGB IEC61966-2.1" ); intent.setOutputConditionIdentifier( "sRGB IEC61966-2.1" ); intent.setRegistryName( "http://www.color.org" ); document.getDocumentCatalog().addOutputIntent( intent ); // load the font as this needs to be embedded InputStream arialFont = PdfA1.class.getResourceAsStream( "/pdfbox/ttf/arial.ttf" ); PDFont font = PDType0Font.load( document, arialFont ); // A PDF/A file needs to have the font embedded if the font is used for text rendering // in rendering modes other than text rendering mode 3. // // This requirement includes the PDF standard fonts, so don't use their static PDFType1Font classes such as // PDFType1Font.HELVETICA. // // As there are many different font licenses it is up to the developer to check if the license terms for the // font loaded allows embedding in the PDF. // if (!font.isEmbedded()) { throw new IllegalStateException( "PDF/A compliance requires that all fonts used for" + " text rendering in rendering modes other than rendering mode 3 are embedded." ); } // add XMP metadata XMPMetadata xmp = XMPMetadata.createXMPMetadata(); try { DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema(); dc.setTitle( file ); // Format A1 PDFAIdentificationSchema id = xmp.createAndAddPDFAIdentificationSchema(); id.setPart( 1 ); id.setConformance( "B" ); // Creation date doit apparaitre si elle est dans les infos du doc, idem pour le producer XMPBasicSchema basicSchema = xmp.createAndAddXMPBasicSchema(); basicSchema.setCreateDate( document.getDocumentInformation().getCreationDate() ); // Le producer gène, soit on le place sur un schéma soit on le retire document.getDocumentInformation().setProducer( null ); XmpSerializer serializer = new XmpSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.serialize( xmp, baos, true ); PDMetadata metadata = new PDMetadata( document ); metadata.importXMPMetadata( baos.toByteArray() ); document.getDocumentCatalog().setMetadata( metadata ); } catch (BadFieldValueException e) { // won't happen here, as the provided value is valid throw new IllegalArgumentException( e ); } // Saving the document document.save( file ); System.out.println( "PDF created" ); // Closing the document document.close(); } catch (Exception e) { e.printStackTrace(); } } private static String getODTAsPDFA1( String file ) { OooWriter ooo = new OooWriter(); ooo.open( "file:///" + file, false, true, false, true, false ); return getWriterAsPDFA1( ooo, file ); } public static String getWriterAsPDFA1( OooWriter ooo, String file ) { try { String fileDest = TextUtil.replace( TextUtil.replace( TextUtil.replace( file, ".odt", ".pdf" ), "ODT", "pdf" ), "\\", "/" ); ooo.saveAsPdf( fileDest, null ); ooo.close(); boolean valide = PdfA1.controleValidite( fileDest ); if (!valide) { return null; } isc.util.log.LogUtil.getLogger().info( "transformation en pdf " ); isc.util.log.LogUtil.getLogger().info( "source " + file ); isc.util.log.LogUtil.getLogger().info( "dest " + fileDest ); return fileDest; } catch (Exception e) { isc.util.log.LogUtil.getLogger().error( e.getMessage(), e ); return null; } } /** * Obtenir un PDF A1 depuis un PDF: utilise le serveur de webservice qui utilise ghostscript en ligne de commande * * @param file * @return */ private static String getPDFAsPDFA1( String file ) { if (controleValidite( file )) { return file; } String fichierConverti = ServeurSpringConnector.pdf2pdfA1Service( file );// Creating PDF document object if (controleValidite( fichierConverti )) { return fichierConverti; } return null; } /** * Méthode pour ODT et PDF qui renvoie dans tous les cas un PDFA1 * * @param file * @return */ public static String getFileAsPDFA1( String file ) { if (file.toUpperCase().endsWith( ".PDF" )) { return getPDFAsPDFA1( file ); } else { return getODTAsPDFA1( file ); } } /** * @param file * Le nom du fichier d'origine qui n'est pas PDF/A1 : courrier_genere_timestamp.pdf * @return Le nom du fichier qui est PDF/A1 et avec une date création ok : courrier_genere_timestamp_corrected.pdf */ public static String correctCreationDateGetPDFA1( String file ) { String adresseFichierPdf = excludeFilePrefixGetPath( file ); String destFile = TextUtil.replace( adresseFichierPdf, ".pdf", "_corrected.pdf" ); Calendar creationDate = null; try (FileInputStream fis = new FileInputStream( adresseFichierPdf ); BufferedReader br = new BufferedReader( new InputStreamReader( fis ) )) { String ligne; while ((creationDate == null) && (ligne = br.readLine()) != null) { String buffer = ligne; if (buffer.trim().startsWith( "<xmp:CreateDate>" )) { String xmpCreateDate = buffer.substring( buffer.indexOf( "<xmp:CreateDate>" ) + "<xmp:CreateDate>".length(), buffer.indexOf( "</xmp:CreateDate>" ) ); System.out.println( "xmp create date trouvée : " + xmpCreateDate ); xmpCreateDate = xmpCreateDate.replace( "-", "" ).replace( "T", "" ).replace( ":", "" ).replace( "+0200", "" ).replace( "+0100", "" ); System.out.println( "xmp create date après replace : " + xmpCreateDate ); Date d = new SimpleDateFormat( "yyyyMMddHHmmss" ).parse( xmpCreateDate ); creationDate = Calendar.getInstance(); creationDate.setTimeInMillis( d.getTime() ); } } } catch (FileNotFoundException e) { isc.util.log.LogUtil.getLogger().error( e.getMessage(), e ); } catch (IOException e) { isc.util.log.LogUtil.getLogger().error( e.getMessage(), e ); } catch (ParseException e) { isc.util.log.LogUtil.getLogger().error( e.getMessage(), e ); } if (creationDate != null) { try { PreflightParser parser = new PreflightParser( adresseFichierPdf ); /* * Parse the PDF file with PreflightParser that inherits from the NonSequentialParser. Some additional controls are present to check a set of PDF/A requirements. (Stream length * consistency, EOL after some Keyword...) */ PDDocument pd = parser.parse( Format.PDF_A1A ); /* * Once the syntax validation is done, the parser can provide a PreflightDocument (that inherits from PDDocument) This document process the end of PDF/A validation. */ PreflightDocument document = (PreflightDocument) pd; PDDocumentInformation info = document.getDocumentInformation(); info.setCreationDate( creationDate ); document.setDocumentInformation( info ); document.save( destFile ); return destFile; } catch (Exception e) { isc.util.log.LogUtil.getLogger().error( e.getMessage(), e ); } } return null; } public static String excludeFilePrefixGetPath( String file ) { return TextUtil.replace( TextUtil.replace( TextUtil.replace( file, "file:///", "" ), "file://", "" ), "file:/", "" ); } // PdfA1.java public static void main( String[] args ) { AppliInitializer.initializeMyApplication(); controleValidite( "C:/temp/courrier_genere_1729858583829_2.pdf" ); System.exit( 0 ); } } Actual Results: Le fichier toto.pdf n'est pas valide PDF/A-1b voici les 1 erreur(s) : 7.2 : Error on MetaData, CreationDate present in the document catalog dictionary doesn't match with XMP information Expected Results: Le fichier toto.pdf est valide PDF/A-1b Reproducible: Always User Profile Reset: No Additional Info: Does not work with the latest version either (Libre office 25.2.4)
Is using Java an important part here? Did you check, if doing this from UI gives the same problem? Because in the current form, your report limits who can reproduce and work on this.
Hello thank you for your reply. Yes, using Java is important because our application relies on this API, but I believe the same issue occurs even with macros. If we use the GUI and export through the menu, the generated PDF file produces the same error. Best regards