package org.rr.jeborker.metadata; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import org.apache.jempbox.xmp.Thumbnail; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.apache.jempbox.xmp.XMPSchemaBasic; import org.rr.commons.log.LoggerFactory; import org.rr.commons.mufs.IResourceHandler; import org.rr.commons.mufs.MimeUtils; import org.rr.commons.mufs.ResourceHandlerFactory; import org.rr.commons.utils.Base64; import org.rr.commons.utils.DateConversionUtils; import org.rr.commons.utils.ListUtils; import org.rr.commons.utils.ReflectionUtils; import org.rr.commons.utils.StringUtil; import org.rr.jeborker.app.FileRefreshBackground; import org.rr.jeborker.metadata.pdf.PDFDocument; import org.rr.pm.image.IImageProvider; import org.rr.pm.image.ImageInfo; import org.rr.pm.image.ImageProviderFactory; import org.rr.pm.image.ImageUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; class PDFCommonMetadataWriter extends APDFCommonMetadataHandler implements IMetadataWriter { private IResourceHandler ebookResource; private PDFDocument pdfDoc; PDFCommonMetadataWriter(final IResourceHandler ebookResource) { this.ebookResource = ebookResource; this.pdfDoc = PDFDocument.getPDFCommonDocumentInstance(PDFDocument.ITEXT, ebookResource); } @Override public void writeMetadata(List<MetadataProperty> props) { try { final PDFCommonMetadataReader reader = (PDFCommonMetadataReader) MetadataHandlerFactory.getReader(ebookResource); byte[] fetchXMPThumbnail = reader.fetchXMPThumbnail(ebookResource); HashMap<String, String> info = new HashMap<String, String>(); XMPMetadata blankXMP = new XMPMetadata(); for (MetadataProperty metadataProperty : props) { final String name = metadataProperty.getName(); if (metadataProperty instanceof PDFMetadataProperty) { PDFMetadataProperty pdfMetadataProperty = (PDFMetadataProperty) metadataProperty; String namespace = pdfMetadataProperty.getNamespace(); XMPSchema xmpSchema = getXMPSchema(namespace, blankXMP); if (xmpSchema != null) { Element xmpSchemaElement = xmpSchema.getElement(); Element propertyElement = pdfMetadataProperty.createElement(xmpSchemaElement.getOwnerDocument()); xmpSchemaElement.appendChild(propertyElement); } else { LoggerFactory.logWarning(this, "No schema for " + pdfMetadataProperty.getName() + " witdh namespace " + namespace + " in " + ebookResource, null); } } else { Object firstValue = ListUtils.get(metadataProperty.getValues(), 0); if (ReflectionUtils.equals(metadataProperty.getPropertyClass(), Date.class)) { // date must be formatted to something like D:20061204092842 String dateValue; if(firstValue instanceof Date) { dateValue = DateConversionUtils.toString((Date) firstValue, DateConversionUtils.DATE_FORMATS.PDF); } else if(firstValue instanceof String) { dateValue = DateConversionUtils.toString(DateConversionUtils.toDate((String) firstValue), DateConversionUtils.DATE_FORMATS.PDF); } else { throw new IllegalArgumentException("The value '" + firstValue + "' is no member of the expected class type."); } info.put(name, dateValue); } else { if(IMetadataReader.COMMON_METADATA_TYPES.COVER.getName().equalsIgnoreCase(name) && firstValue instanceof byte[]) { fetchXMPThumbnail = (byte[]) firstValue; } else if(IMetadataReader.COMMON_METADATA_TYPES.COVER.getName().equalsIgnoreCase(name) && firstValue instanceof String) { fetchXMPThumbnail = Base64.decode((String) firstValue); } else { if(info.containsKey(name)) { String oldValue = info.get(name); firstValue = oldValue + ", " + StringUtil.toString(firstValue); } String insValue = StringUtil.toString(firstValue).trim(); if(!insValue.isEmpty()) { info.put(name, insValue); } } } } } if(fetchXMPThumbnail != null) { blankXMP = attachCoverToXmp(fetchXMPThumbnail, blankXMP.getXMPDocument()); } pdfDoc.setInfo(info); pdfDoc.setXMPMetadata(blankXMP.asByteArray()); FileRefreshBackground.setDisabled(true); pdfDoc.write(); } catch (Exception e) { LoggerFactory.logWarning(this, "could not write pdf meta data for " + ebookResource, e); } finally { FileRefreshBackground.setDisabled(false); } } /** * Attaches the given coverData as jpeg to the given document. The image is * converted into jpeg if needed. * * @param coverData The image data to be used as cover. * @param document The xmp document where the cover should be attached to. * @return Metadata created from the given document with the given cover. * @throws IOException */ private XMPMetadata attachCoverToXmp(byte[] coverData, final Document document) throws IOException { final XMPMetadata xmp; if(document != null) { xmp = new XMPMetadata(document); } else { xmp = new XMPMetadata(); } final XMPSchemaBasic xmpSchema = (XMPSchemaBasic) getXMPSchema("xap", xmp); final IResourceHandler coverResourceLoader = ResourceHandlerFactory.getVirtualResourceHandler("PDFMetadataWriterSetCover", coverData); final String coverMimeType = coverResourceLoader.getMimeType(true); Thumbnail thumbnail = xmpSchema.getThumbnail(); if(thumbnail == null) { thumbnail = new Thumbnail(xmp); } if(MimeUtils.isJpegMime(coverMimeType)) { thumbnail.setImage(new String(Base64.encode(coverData))); ImageInfo imageInfo = new ImageInfo(ResourceHandlerFactory.getVirtualResourceHandler("setCover", coverData)); thumbnail.setHeight(imageInfo.getHeight()); thumbnail.setWidth(imageInfo.getWidth()); } else { IImageProvider imageProvider = ImageProviderFactory.getImageProvider(coverResourceLoader); BufferedImage image = imageProvider.getImage(); if(image != null) { byte[] jpegCover = ImageUtils.getImageBytes(image, MimeUtils.MIME_JPEG); thumbnail.setImage(new String(Base64.encode(jpegCover))); thumbnail.setHeight(image.getHeight()); thumbnail.setWidth(image.getWidth()); } else { LoggerFactory.log(Level.INFO, this, "Unknown image format"); } } thumbnail.setFormat(Thumbnail.FORMAT_JPEG); xmpSchema.setThumbnail(thumbnail, "xap"); return xmp; } @Override public void storePlainMetadata(byte[] plainMetadata) { try { pdfDoc.setXMPMetadata(plainMetadata); pdfDoc.write(); } catch(Exception e) { LoggerFactory.logWarning(this, "Could not write metadata to " + ebookResource, e); } } }