/** * Create an image part from the provided byte array, attach it to the source part (eg the main * document part, a header part etc), and return it. * * <p>Works for both docx and pptx. * * <p>Knowing the MIME type allows you to avoid ImageInfo, but you'll probably also need to know * the image dimensions * * @param opcPackage * @param sourcePart * @param bytes * @param mime MIME type eg image/png * @return * @throws Exception @Since 3.0.1 */ public static BinaryPartAbstractImage createImagePart( OpcPackage opcPackage, Part sourcePart, byte[] bytes, String mime) throws Exception { String ext = mimeToExt(mime); if (mime == null || ext == null) { log.warn("Null or unknown mime type; image introspection required!"); return createImagePart(opcPackage, sourcePart, bytes); } ContentTypeManager ctm = opcPackage.getContentTypeManager(); // Ensure the relationships part exists if (sourcePart.getRelationshipsPart() == null) { RelationshipsPart.createRelationshipsPartForPart(sourcePart); } String proposedRelId = sourcePart.getRelationshipsPart().getNextId(); BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType( mime, createImageName(opcPackage, sourcePart, proposedRelId, ext), null); log.debug( "created part " + imagePart.getClass().getName() + " with name " + imagePart.getPartName().toString()); imagePart.setBinaryData(bytes); imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId)); return imagePart; }
private OpcPackage process(HashMap<String, ByteArray> partByteArrays) throws Docx4JException { long startTime = System.currentTimeMillis(); // 2. Create a new Package // Eventually, you'll also be able to create an Excel package etc // but only the WordML package exists at present ContentTypeManager ctm = new ContentTypeManager(); try { InputStream is = getInputStreamFromZippedPart(partByteArrays, "[Content_Types].xml"); ctm.parseContentTypesFile(is); } catch (IOException e) { throw new Docx4JException("Couldn't get [Content_Types].xml from ZipFile", e); } catch (NullPointerException e) { throw new Docx4JException("Couldn't get [Content_Types].xml from ZipFile", e); } // .. now find the name of the main part String partName = "_rels/.rels"; RelationshipsPart rp = getRelationshipsPartFromZip(null, partByteArrays, partName); if (rp == null) { throw new Docx4JException("_rels/.rels appears to be missing from this package!"); } String mainPartName = PackageRelsUtil.getNameOfMainPart(rp); String pkgContentType = ctm.getContentType(new PartName("/" + mainPartName)); // 2. Create a new Package; this'll return the appropriate subclass OpcPackage p = ctm.createPackage(pkgContentType); log.info("Instantiated package of type " + p.getClass().getName()); p.setRelationships(rp); rp.setSourceP(p); // // 5. Now recursively // (i) create new Parts for each thing listed // in the relationships // (ii) add the new Part to the package // (iii) cross the PartName off unusedZipEntries addPartsFromRelationships(partByteArrays, p, rp, ctm); // 6. Check unusedZipEntries is empty // if (log.isDebugEnabled()) { // Iterator myVeryOwnIterator = unusedZipEntries.keySet().iterator(); // while(myVeryOwnIterator.hasNext()) { // String key = (String)myVeryOwnIterator.next(); // log.info( key + " " + unusedZipEntries.get(key)); // } // } registerCustomXmlDataStorageParts(p); long endTime = System.currentTimeMillis(); log.info("package read; elapsed time: " + Math.round((endTime - startTime)) + " ms"); return p; }
/* Save a Package as a Zip file in the outputstream provided */ public boolean save(OutputStream realOS) throws Docx4JException { handled = new HashMap<String, String>(); try { ZipOutputStream out = new ZipOutputStream(realOS); // 3. Save [Content_Types].xml ContentTypeManager ctm = p.getContentTypeManager(); out.putNextEntry(new ZipEntry("[Content_Types].xml")); ctm.marshal(out); out.closeEntry(); // 4. Start with _rels/.rels // <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> // <Relationship Id="rId3" // Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/> // <Relationship Id="rId2" // Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/> // <Relationship Id="rId1" // Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" // Target="word/document.xml"/> // </Relationships> String partName = "_rels/.rels"; RelationshipsPart rp = p.getRelationshipsPart(); // deprecatedSaveRawXmlPart(out, partName, rp.getDocument() ); // 2008 06 12 - try this neater method saveRawXmlPart(out, rp, partName); // 5. Now recursively // addPartsFromRelationships(out, "", rp ); addPartsFromRelationships(out, rp); // Complete the ZIP file // Don't forget to do this or everything will appear // to work, but when you open the zip file you'll get an error // "End-of-central-directory signature not found." out.close(); realOS.close(); } catch (Exception e) { e.printStackTrace(); if (e instanceof Docx4JException) { throw (Docx4JException) e; } else { throw new Docx4JException("Failed to save package", e); } } log.info("...Done!"); return true; }
// public static Part getBinaryPart(ZipFile zf, ContentTypeManager ctm, String resolvedPartUri) public static Part getBinaryPart( HashMap<String, ByteArray> partByteArrays, ContentTypeManager ctm, String resolvedPartUri) throws Docx4JException { Part part = null; InputStream in = null; try { // in = zf.getInputStream( zf.getEntry(resolvedPartUri ) ); in = partByteArrays.get(resolvedPartUri).getInputStream(); part = new BinaryPart(new PartName("/" + resolvedPartUri)); // Set content type part.setContentType(new ContentType(ctm.getContentType(new PartName("/" + resolvedPartUri)))); ((BinaryPart) part).setBinaryData(in); log.info("Stored as BinaryData"); } catch (Exception ioe) { ioe.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException exc) { exc.printStackTrace(); } } } return part; }
/** * Create a linked image part, and attach it as a rel of the specified source part (eg a header * part). * * <p>The current behaviour is that the part is added to the package, but since the target mode of * the rel is external, the part is redundant. * * @param wordMLPackage * @param sourcePart * @param url * @return * @throws Exception */ public static BinaryPartAbstractImage createLinkedImagePart( OpcPackage opcPackage, Part sourcePart, URL url) throws Exception { log.debug("Incoming url for linked image: " + url.toString()); ImageInfo info = ensureFormatIsSupported(url, null, null, false); // final param doesn't matter in this case ContentTypeManager ctm = opcPackage.getContentTypeManager(); String proposedRelId = sourcePart.getRelationshipsPart().getNextId(); // In order to ensure unique part name, // idea is to use the relId, which ought to be unique String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1); BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType( info.getMimeType(), createImageName(opcPackage, sourcePart, proposedRelId, ext), null); // NB: contents never populated log.debug( "created part " + imagePart.getClass().getName() + " with name " + imagePart.getPartName().toString()); imagePart.rels.add( sourcePart.addTargetPart( imagePart)); // want to create rel with suitable name; side effect is to add part imagePart.getRelLast().setTargetMode("External"); opcPackage.getExternalResources().put(imagePart.getExternalTarget(), imagePart); // if (!url.getProtocol().equals("file") && new File(url.toString() ).isFile()) { // imagePart.rel.setTarget("file:///" + url); // } else { // imagePart.rel.setTarget(url.toString()); // } imagePart.getRelLast().setTarget(url.toString()); imagePart.setImageInfo(info); return imagePart; }
/** * Create an image part from the provided filePath image, attach it to the source part (eg the * main document part, a header part etc), and return it. * * <p>Works for both docx and pptx. * * @param opcPackage * @param sourcePart * @param filePath * @return * @throws Exception */ public static BinaryPartAbstractImage createImagePart( OpcPackage opcPackage, Part sourcePart, File imageFile) throws Exception { final byte[] locByte = new byte[1]; // We are in the case that image is not load (no byte Array) so isLoad is false ImageInfo info = ensureFormatIsSupported(imageFile, locByte, false); ContentTypeManager ctm = opcPackage.getContentTypeManager(); // Ensure the relationships part exists if (sourcePart.getRelationshipsPart() == null) { RelationshipsPart.createRelationshipsPartForPart(sourcePart); } String proposedRelId = sourcePart.getRelationshipsPart().getNextId(); String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1); BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType( info.getMimeType(), createImageName(opcPackage, sourcePart, proposedRelId, ext), null); log.debug( "created part " + imagePart.getClass().getName() + " with name " + imagePart.getPartName().toString()); FileInputStream fis = new FileInputStream(imageFile); imagePart.setBinaryData(fis); imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId)); imagePart.setImageInfo(info); return imagePart; }
public Part getBinaryPart(ContentTypeManager ctm, String resolvedPartUri) throws Docx4JException { Part part = null; InputStream is = null; try { is = partStore.loadPart(resolvedPartUri); // in = partByteArrays.get(resolvedPartUri).getInputStream(); part = new BinaryPart(new PartName("/" + resolvedPartUri)); // Set content type part.setContentType(new ContentType(ctm.getContentType(new PartName("/" + resolvedPartUri)))); ((BinaryPart) part).setBinaryData(is); log.info("Stored as BinaryData"); } catch (Exception ioe) { ioe.printStackTrace(); } finally { IOUtils.closeQuietly(is); } return part; }
/** * Get a Part (except a relationships part), but not its relationships part or related parts. * Useful if you need quick access to just this part. This can be called directly from outside the * library, in which case the Part will not be owned by a Package until the calling code makes it * so. * * @see To get a Part and all its related parts, and add all to a package, use getPart. * @param partByteArrays * @param ctm * @param resolvedPartUri * @param rel * @return * @throws Docx4JException including if result is null */ public Part getRawPart(ContentTypeManager ctm, String resolvedPartUri, Relationship rel) throws Docx4JException { Part part = null; InputStream is = null; try { try { log.debug("resolved uri: " + resolvedPartUri); // Get a subclass of Part appropriate for this content type // This will throw UnrecognisedPartException in the absence of // specific knowledge. Hence it is important to get the is // first, as we do above. part = ctm.getPart("/" + resolvedPartUri, rel); log.info("ctm returned " + part.getClass().getName()); if (part instanceof org.docx4j.openpackaging.parts.ThemePart || part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart || part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart || part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart || part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart || part instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart || part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) { // Nothing to do here } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) { log.debug("Detected BinaryPart " + part.getClass().getName()); // is = partStore.loadPart( resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) { // ContentTypeManager initially detects them as CustomXmlDataStoragePart; // the below changes as necessary // Is it a part we know? is = partStore.loadPart(resolvedPartUri); try { Unmarshaller u = Context.jc.createUnmarshaller(); Object o = u.unmarshal(is); log.debug(o.getClass().getName()); PartName name = part.getPartName(); if (o instanceof CoverPageProperties) { part = new DocPropsCoverPagePart(name); ((DocPropsCoverPagePart) part).setJaxbElement((CoverPageProperties) o); } else if (o instanceof org.opendope.conditions.Conditions) { part = new ConditionsPart(name); ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o); } else if (o instanceof org.opendope.xpaths.Xpaths) { part = new XPathsPart(name); ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o); } else if (o instanceof org.opendope.questions.Questionnaire) { part = new QuestionsPart(name); ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o); } else if (o instanceof org.opendope.answers.Answers) { part = new StandardisedAnswersPart(name); ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o); } else if (o instanceof org.opendope.components.Components) { part = new ComponentsPart(name); ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o); } else if (o instanceof JAXBElement<?> && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) { part = new BibliographyPart(name); ((BibliographyPart) part) .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o); } else { log.error("TODO: handle known CustomXmlPart part " + o.getClass().getName()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } catch (javax.xml.bind.UnmarshalException ue) { log.warn("No JAXB model for this CustomXmlDataStorage part; " + ue.getMessage()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) { is = partStore.loadPart(resolvedPartUri); // try { ((XmlPart) part).setDocument(is); // Experimental 22/6/2011; don't fall back to binary (which we used to) // } catch (Docx4JException d) { // // This isn't an XML part after all, // // even though ContentTypeManager detected it as such // // So get it as a binary part // part = getBinaryPart(partByteArrays, ctm, resolvedPartUri); // log.warn("Could not parse as XML, so using BinaryPart for " // + resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); // } } else { // Shouldn't happen, since ContentTypeManagerImpl should // return an instance of one of the above, or throw an // Exception. log.error("No suitable part found for: " + resolvedPartUri); part = null; } } catch (PartUnrecognisedException e) { log.error("PartUnrecognisedException shouldn't happen anymore!", e); // Try to get it as a binary part part = getBinaryPart(ctm, resolvedPartUri); log.warn("Using BinaryPart for " + resolvedPartUri); // is = partStore.loadPart( resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); } } catch (Exception ex) { // IOException, URISyntaxException ex.printStackTrace(); throw new Docx4JException("Failed to getPart", ex); } finally { IOUtils.closeQuietly(is); } if (part == null) { throw new Docx4JException( "cannot find part " + resolvedPartUri + " from rel " + rel.getId() + "=" + rel.getTarget()); } return part; }
public OpcPackage get() throws Docx4JException { long startTime = System.currentTimeMillis(); // 1. Get [Content_Types].xml ContentTypeManager ctm = new ContentTypeManager(); InputStream is = null; try { is = partStore.loadPart("[Content_Types].xml"); ctm.parseContentTypesFile(is); } catch (Docx4JException e) { throw new Docx4JException("Couldn't get [Content_Types].xml from ZipFile", e); } catch (NullPointerException e) { throw new Docx4JException("Couldn't get [Content_Types].xml from ZipFile", e); } finally { IOUtils.closeQuietly(is); } // .. now find the name of the main part String partName = "_rels/.rels"; RelationshipsPart rp = getRelationshipsPartFromZip(null, partName); if (rp == null) { throw new Docx4JException("_rels/.rels appears to be missing from this package!"); } String mainPartName = PackageRelsUtil.getNameOfMainPart(rp); PartName mainPartNameObj; if (mainPartName.startsWith("/")) { // OpenXML SDK 2.0 writes Target="/word/document.xml" (note leading "/") mainPartNameObj = new PartName(mainPartName); } else { // Microsoft Word, docx4j etc write Target="word/document.xml" mainPartNameObj = new PartName("/" + mainPartName); } String pkgContentType = ctm.getContentType(mainPartNameObj); // 2. Create a new Package; this'll return the appropriate subclass OpcPackage p = ctm.createPackage(pkgContentType); log.info("Instantiated package of type " + p.getClass().getName()); p.setPartStore(partStore); p.setRelationships(rp); rp.setSourceP(p); // // 5. Now recursively // (i) create new Parts for each thing listed // in the relationships // (ii) add the new Part to the package // (iii) cross the PartName off unusedZipEntries addPartsFromRelationships(p, rp, ctm); // 6. registerCustomXmlDataStorageParts(p); // partStore.finishLoad(); long endTime = System.currentTimeMillis(); log.info("package read; elapsed time: " + Math.round((endTime - startTime)) + " ms"); return p; }
/** * Get a Part (except a relationships part), but not its relationships part or related parts. * Useful if you need quick access to just this part. This can be called directly from outside the * library, in which case the Part will not be owned by a Package until the calling code makes it * so. * * @see To get a Part and all its related parts, and add all to a package, use getPart. * @param zf * @param resolvedPartUri * @return * @throws URISyntaxException * @throws InvalidFormatException */ public static Part getRawPart( ZipFile zf, ContentTypeManager ctm, String resolvedPartUri, Relationship rel) throws Docx4JException { Part part = null; InputStream is = null; try { try { log.debug("resolved uri: " + resolvedPartUri); is = getInputStreamFromZippedPart(zf, resolvedPartUri); // Get a subclass of Part appropriate for this content type // This will throw UnrecognisedPartException in the absence of // specific knowledge. Hence it is important to get the is // first, as we do above. part = ctm.getPart("/" + resolvedPartUri, rel); if (part instanceof org.docx4j.openpackaging.parts.ThemePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcThemePart); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsCore); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsCustom); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsExtended); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcCustomXmlProperties); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcXmlDSig); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) { // MainDocument part, Styles part, Font part etc ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jc); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) { log.debug("Detected BinaryPart " + part.getClass().getName()); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) { // Is it a part we know? try { Unmarshaller u = Context.jc.createUnmarshaller(); Object o = u.unmarshal(is); log.debug(o.getClass().getName()); PartName name = part.getPartName(); if (o instanceof org.opendope.conditions.Conditions) { part = new ConditionsPart(name); ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o); } else if (o instanceof org.opendope.xpaths.Xpaths) { part = new XPathsPart(name); ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o); } else if (o instanceof org.opendope.questions.Questionnaire) { part = new QuestionsPart(name); ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o); } else if (o instanceof org.opendope.answers.Answers) { part = new StandardisedAnswersPart(name); ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o); } else if (o instanceof org.opendope.components.Components) { part = new ComponentsPart(name); ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o); } else if (o instanceof JAXBElement<?> && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) { part = new BibliographyPart(name); ((BibliographyPart) part) .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o); } else { log.warn("No known part after all for CustomXmlPart " + o.getClass().getName()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } catch (javax.xml.bind.UnmarshalException ue) { // No ... CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) { try { ((XmlPart) part).setDocument(is); } catch (Docx4JException d) { // This isn't an XML part after all, // even though ContentTypeManager detected it as such // So get it as a binary part part = getBinaryPart(zf, ctm, resolvedPartUri); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } } else { // Shouldn't happen, since ContentTypeManagerImpl should // return an instance of one of the above, or throw an // Exception. log.error("No suitable part found for: " + resolvedPartUri); part = null; } } catch (PartUnrecognisedException e) { log.warn("PartUnrecognisedException shouldn't happen anymore!"); // Try to get it as a binary part part = getBinaryPart(zf, ctm, resolvedPartUri); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } } catch (Exception ex) { // IOException, URISyntaxException ex.printStackTrace(); throw new Docx4JException("Failed to getPart", ex); } finally { if (is != null) { try { is.close(); } catch (IOException exc) { exc.printStackTrace(); } } } return part; }
public OpcPackage get(File f) throws Docx4JException { log.info("Filepath = " + f.getPath()); ZipFile zf = null; try { if (!f.exists()) { log.info("Couldn't find " + f.getPath()); } zf = new ZipFile(f); } catch (IOException ioe) { ioe.printStackTrace(); throw new Docx4JException("Couldn't get ZipFile", ioe); } // dumpZipFileContents(zf); // 1. The idea is to walk the tree of relationships, getting // everything we need from the zip file. But I'd like to know // whether there are any orphans, so first we make // a HashMap containing the names of all the zip file // entries, so we can tick them off. // unusedZipEntries = new HashMap(); Enumeration entries = zf.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); // unusedZipEntries.put(entry.getName(), new Boolean(true) ); } // 2. Create a new Package // Eventually, you'll also be able to create an Excel package etc // but only the WordML package exists at present ContentTypeManager ctm = new ContentTypeManager(); try { InputStream is = getInputStreamFromZippedPart(zf, "[Content_Types].xml"); ctm.parseContentTypesFile(is); } catch (IOException e) { throw new Docx4JException("Couldn't get [Content_Types].xml from ZipFile", e); } OpcPackage p = ctm.createPackage(); // 3. Get [Content_Types].xml // Once we've got this, then we can look up the content type for // each PartName, and use it in the Part constructor. // p.setContentTypeManager(ctm); - 20080111 - done by ctm.createPackage(); // unusedZipEntries.put("[Content_Types].xml", new Boolean(false)); // 4. Start with _rels/.rels // <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> // <Relationship Id="rId3" // Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/> // <Relationship Id="rId2" // Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" // Target="docProps/core.xml"/> // <Relationship Id="rId1" // Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" // Target="word/document.xml"/> // </Relationships> String partName = "_rels/.rels"; RelationshipsPart rp = getRelationshipsPartFromZip(p, zf, partName); p.setRelationships(rp); // rp.setPackageRelationshipPart(true); // unusedZipEntries.put(partName, new Boolean(false)); log.info("Object created for: " + partName); // log.info( rp.toString()); // 5. Now recursively // (i) create new Parts for each thing listed // in the relationships // (ii) add the new Part to the package // (iii) cross the PartName off unusedZipEntries addPartsFromRelationships(zf, p, rp, ctm); // 6. Check unusedZipEntries is empty // if (log.isDebugEnabled()) { // Iterator myVeryOwnIterator = unusedZipEntries.keySet().iterator(); // while(myVeryOwnIterator.hasNext()) { // String key = (String)myVeryOwnIterator.next(); // log.info( key + " " + unusedZipEntries.get(key)); // } // } try { zf.close(); } catch (IOException exc) { exc.printStackTrace(); } registerCustomXmlDataStorageParts(p); return p; }
public static void apply(WordprocessingMLPackage otherPackage, Alterations alterations) throws Docx4JException, JAXBException { if (alterations.getContentTypes() != null) { log.info("replacing [Content_Types].xml"); ContentTypeManager newCTM = new ContentTypeManager(); newCTM.parseContentTypesFile(new ByteArrayInputStream(alterations.getContentTypes())); otherPackage.setContentTypeManager(newCTM); } if (alterations.isEmpty()) return; // -- Deletions List<PartName> removedParts = new ArrayList<PartName>(); for (Alteration a : alterations.getPartsDeleted()) { org.docx4j.xmlPackage.Part xmlpart = a.getPart(); // These deleted parts are likely to be attached to // to otherPackage, but there is no requirement for // that to be so. In other words, you could try // to apply the alterations to some third docx. // It might have already been deleted as a consequence // of recursive deletion... if (removedParts.contains(xmlpart.getName())) continue; // Design decision: how to find owning rels part? // Since part might not be from this package, can't do: // part.getOwningRelationshipPart().removePart(p.getPartName()) // We could store the info when AlteredParts is run, // but lets try to get away without that... // If a part has been deleted, we know its owning rels will // have been modified or deleted. So look for that. // BUT IT WON'T BE THERE IF ITS BEEN DELETED! DOH! // So we have to store the info when AlteredParts is run // after all. Part parentPart = otherPackage.getParts().get(a.getSourcePartName()); if (a.getPart().getContentType().equals(ContentTypes.RELATIONSHIPS_PART)) { parentPart.setRelationships(null); } else { removedParts.addAll( parentPart.getRelationshipsPart().removePart(new PartName(xmlpart.getName()))); } } // -- Modifications for (Alteration a : alterations.getPartsModified()) { log.info("Applying modifications to part: " + a.getPart().getName()); if (a.getPart().getContentType().equals(ContentTypes.RELATIONSHIPS_PART)) { RelationshipsPart newRP = null; // FlatOpcXmlImporter.createRelationshipsPart(a.getPart()); if (a.getSourcePartName().equals("/")) { newRP = otherPackage.getRelationshipsPart(true); // otherPackage.setRelationships(newRP); // newRP.setSourceP(otherPackage); } else { Part parentPart = otherPackage.getParts().get(a.getSourcePartName()); newRP = parentPart.getRelationshipsPart(true); // parentPart.setRelationships(newRP); // newRP.setSourceP(parentPart); } FlatOpcXmlImporter.populateRelationshipsPart(newRP, a.getPart().getXmlData().getAny()); } else { Part targetPart = otherPackage.getParts().get(new PartName(a.getPart().getName())); if (targetPart == null) { log.error( "Couldn't find " + a.getPart().getName() + " @ " + a.getSourcePartName().getName()); continue; } Part tmpPart = FlatOpcXmlImporter.getRawPart(otherPackage.getContentTypeManager(), a.getPart(), null); if (targetPart instanceof JaxbXmlPart) { ((JaxbXmlPart) targetPart).setJaxbElement(((JaxbXmlPart) tmpPart).getJaxbElement()); } else if (targetPart instanceof XmlPart) { ((XmlPart) targetPart).setDocument(((XmlPart) tmpPart).getDocument()); } else if (targetPart instanceof CustomXmlDataStoragePart) { ((CustomXmlDataStoragePart) targetPart) .setData(((CustomXmlDataStoragePart) tmpPart).getData()); // TODO: check that } else if (targetPart instanceof BinaryPart) { ((BinaryPart) targetPart).setBinaryData(((BinaryPart) tmpPart).getBuffer()); } else { log.error("TODO: handle " + targetPart.getClass().getName()); } } } // -- Additions for (Alteration a : alterations.getPartsAdded()) { log.info("Adding part: " + a.getPart().getName()); if (a.getPart().getContentType().equals(ContentTypes.RELATIONSHIPS_PART)) { RelationshipsPart newRP = null; // FlatOpcXmlImporter.createRelationshipsPart(a.getPart()); if (a.getSourcePartName().equals("/")) { newRP = otherPackage.getRelationshipsPart(true); // otherPackage.setRelationships(newRP); // newRP.setSourceP(otherPackage); } else { Part parentPart = otherPackage.getParts().get(a.getSourcePartName()); newRP = parentPart.getRelationshipsPart(true); // parentPart.setRelationships(newRP); // newRP.setSourceP(parentPart); } FlatOpcXmlImporter.populateRelationshipsPart(newRP, a.getPart().getXmlData().getAny()); } else { Part parentPart = otherPackage.getParts().get(a.getSourcePartName()); Part newPart = FlatOpcXmlImporter.getRawPart(otherPackage.getContentTypeManager(), a.getPart(), null); // There will already be a rel for the new part, // since we will already have modified or added the rels part // so don't do AddTargetPart (which will probably create a new rel id, // which will cause problems) newPart.setOwningRelationshipPart(parentPart.getRelationshipsPart()); newPart .getSourceRelationships() .add(parentPart.getRelationshipsPart().getRel(new PartName(a.getPart().getName()))); otherPackage.getParts().put(newPart); newPart.setPackage(otherPackage); // TODO: add content type if necessary } } }
/** * Create an image part from the provided byte array, attach it to the source part (eg the main * document part, a header part etc), and return it. * * <p>Works for both docx and pptx. * * <p>Note: this method creates a temp file (and attempts to delete it). That's because it uses * org.apache.xmlgraphics * * @param opcPackage * @param sourcePart * @param bytes * @return * @throws Exception */ public static BinaryPartAbstractImage createImagePart( OpcPackage opcPackage, Part sourcePart, byte[] bytes) throws Exception { // Whatever image type this is, we're going to need // to know its dimensions. // For that we use ImageInfo, which can only // load an image from a URI. // So first, write the bytes to a temp file File tmpImageFile = File.createTempFile("img", ".img"); FileOutputStream fos = new FileOutputStream(tmpImageFile); fos.write(bytes); fos.close(); log.debug("created tmp file: " + tmpImageFile.getAbsolutePath()); ImageInfo info = ensureFormatIsSupported(tmpImageFile, bytes, true); // In the absence of an exception, tmpImageFile now contains an image // Word will accept ContentTypeManager ctm = opcPackage.getContentTypeManager(); // Ensure the relationships part exists if (sourcePart.getRelationshipsPart() == null) { RelationshipsPart.createRelationshipsPartForPart(sourcePart); } String proposedRelId = sourcePart.getRelationshipsPart().getNextId(); String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1); // System.out.println(ext); BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType( info.getMimeType(), createImageName(opcPackage, sourcePart, proposedRelId, ext), null); log.debug( "created part " + imagePart.getClass().getName() + " with name " + imagePart.getPartName().toString()); FileInputStream fis = new FileInputStream(tmpImageFile); imagePart.setBinaryData(fis); imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId)); imagePart.setImageInfo(info); // Delete the tmp file // As per http://stackoverflow.com/questions/991489/i-cant-delete-a-file-in-java // the following 3 lines are necessary, at least on Win 7 x64 // Also reported on Win XP, but in my testing, the files were deleting OK anyway. fos = null; fis = null; if (Docx4jProperties.getProperty( "docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.TempFiles.ForceGC", true)) { System.gc(); } if (tmpImageFile.delete()) { log.debug(".. deleted " + tmpImageFile.getAbsolutePath()); } else { log.warn("Couldn't delete tmp file " + tmpImageFile.getAbsolutePath()); tmpImageFile.deleteOnExit(); // If that doesn't work, see "Clean Up Your Mess: Managing Temp Files in Java Apps" // at devx.com } return imagePart; }