OdfDrawImage.java
/**
* **********************************************************************
*
* <p>DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* <p>Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
* <p>Use is subject to license terms.
*
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
* http://odftoolkit.org/docs/license.txt
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
*
* <p>See the License for the specific language governing permissions and limitations under the
* License.
*
* <p>**********************************************************************
*/
package org.odftoolkit.odfdom.incubator.doc.draw;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.odftoolkit.odfdom.dom.OdfDocumentNamespace;
import org.odftoolkit.odfdom.dom.OdfSchemaDocument;
import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawImageElement;
import org.odftoolkit.odfdom.pkg.OdfFileDom;
import org.odftoolkit.odfdom.pkg.OdfPackage;
import org.odftoolkit.odfdom.pkg.manifest.OdfFileEntry;
import org.odftoolkit.odfdom.type.AnyURI;
import org.odftoolkit.odfdom.type.Length;
import org.odftoolkit.odfdom.type.Length.Unit;
import org.w3c.dom.NodeList;
/** Convenient functionality for the parent ODF OpenDocument element */
public class OdfDrawImage extends DrawImageElement {
private static final long serialVersionUID = 8409319888919451149L;
private URI mImageURI;
// OdfPackage necessary to adapt the manifest referencing the image
private OdfPackage mOdfPackage;
private OdfSchemaDocument mOdfSchemaDocument;
private static final String SLASH = "/";
/**
* Creates a new instance of this class
*
* @param ownerDoc The XML DOM containing the draw:image element
*/
public OdfDrawImage(OdfFileDom ownerDoc) {
super(ownerDoc);
mOdfSchemaDocument = (OdfSchemaDocument) ownerDoc.getDocument();
mOdfPackage = mOdfSchemaDocument.getPackage();
}
/**
* Return the URI for this image
*
* @return the URI of image
*/
public URI getImageUri() {
try {
if (mImageURI == null) {
mImageURI = new URI(AnyURI.encodePath(this.getXlinkHrefAttribute().toString()));
}
} catch (URISyntaxException ex) {
Logger.getLogger(OdfDrawImage.class.getName()).log(Level.SEVERE, null, ex);
}
return mImageURI;
}
/**
* The image path will be stored as URI of the href attribute
*
* @param packagePath The relative path from the package root to the image
*/
public void setImagePath(String packagePath) {
try {
packagePath = packagePath.replaceFirst(mOdfSchemaDocument.getDocumentPath(), "");
URI uri = new URI(AnyURI.encodePath(packagePath).toString());
this.setXlinkHrefAttribute(AnyURI.decodePath(uri.toString()));
mImageURI = uri;
} catch (URISyntaxException ex) {
Logger.getLogger(OdfDrawImage.class.getName()).log(Level.SEVERE, null, ex);
}
}
/* Helper method */
private String getPackagePath(String imageRef) {
if (imageRef.contains(SLASH)) {
imageRef = imageRef.substring(imageRef.lastIndexOf(SLASH) + 1, imageRef.length());
}
String packagePath = OdfPackage.OdfFile.IMAGE_DIRECTORY.getPath() + SLASH + imageRef;
return packagePath = mOdfSchemaDocument.getDocumentPath() + packagePath;
}
/* Helper method */
private void configureInsertedImage(String packagePath) throws Exception {
// Set path to image attribute
setImagePath(packagePath);
// Set mandatory attribute xlink:type
setXlinkTypeAttribute("simple");
// A draw:image is always embedded in a draw:frame
InputStream is = mOdfPackage.getInputStream(packagePath);
DrawFrameElement odfFrame = (DrawFrameElement) this.getParentNode();
if (odfFrame != null) {
if (!odfFrame.hasAttributeNS(OdfDocumentNamespace.SVG.getUri(), "height")
&& !odfFrame.hasAttributeNS(OdfDocumentNamespace.SVG.getUri(), "width")) {
BufferedImage image = ImageIO.read(is);
// some image formats like SVG might not be understood by ImageIO
if (image != null) {
int height = image.getHeight(null);
int width = image.getWidth(null);
odfFrame.setSvgHeightAttribute(
Length.mapToUnit(String.valueOf(height) + "px", Unit.CENTIMETER));
odfFrame.setSvgWidthAttribute(
Length.mapToUnit(String.valueOf(width) + "px", Unit.CENTIMETER));
}
}
}
}
/**
* Inserts the image file from the URI to the ODF package named similar as in the URI. The
* manifest is adapted using the media type according to the suffix. Existing images are replaced.
* Note: Default image seize will only be set, if the draw:image had been added to its draw:frame
* prior.
*
* @param imageUri The URI of the image that will be added as stream to the package in the
* 'Pictures/' graphic directory with the same image file name as in the URI. If the imageURI
* is relative first the user.dir is taken to make it absolute.
* @return Returns the package path of the image, which was created based on the given URI.
* @throws Exception If the image provided by the URI, could not be added as stream to the ODF
* package.
*/
public String newImage(URI imageUri) throws Exception {
String imageRef = imageUri.toString();
String mediaType = OdfFileEntry.getMediaTypeString(imageRef);
String packagePath = getPackagePath(imageRef);
mOdfPackage.insert(imageUri, packagePath, mediaType);
configureInsertedImage(packagePath);
return packagePath;
}
/**
* Inserts the image file from the stream to the ODF package named similar as in the provided
* path.. The manifest is adapted using given media type. Existing images are replaced.
*
* @param is InputStream to be added to the ODF package
* @param packagePath Internal path of the image in the package
* @param mediaType The mediaType of the image. Can be obtained by the OdfFileEntry class
* findMediaType(String fileRef).
* @throws Exception If the given stream could not be added to the ODF package at the packagePatch
*/
public void newImage(InputStream is, String packagePath, String mediaType) throws Exception {
mOdfPackage.insert(is, packagePath, mediaType);
configureInsertedImage(packagePath);
}
/**
* Inserts the image file from the stream to the ODF package named similar as in the provided
* path.. The manifest is adapted using given media type. Existing images are replaced.
*
* @param fileBytes - data of the file stream to be stored in package. If NULL a directory with
* the given media type will be created.
* @param packagePath Internal path of the image in the package
* @param mediaType The mediaType of the image. Can be obtained by the OdfFileEntry class
* findMediaType(String fileRef).
* @throws Exception If the given stream could not be added to the ODF package at the packagePatch
*/
public void newImage(byte[] fileBytes, String packagePath, String mediaType) throws Exception {
mOdfPackage.insert(fileBytes, packagePath, mediaType);
configureInsertedImage(packagePath);
}
/**
* The method returns the specific one or more images by image path since the image may be
* inserted to the document several times.
*
* @param doc the document the image belongs to
* @param imagePath the internal package path of the image.
* @return an Image list that match the given image path if no images is found under the given
* path, return an empty list.
*/
public static List<OdfDrawImage> getImageByPath(OdfSchemaDocument doc, String imagePath) {
ArrayList<OdfDrawImage> imageList = new ArrayList<OdfDrawImage>();
try {
NodeList imageNodes =
doc.getContentDom().getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "image");
for (int i = 0; i < imageNodes.getLength(); i++) {
OdfDrawImage image = (OdfDrawImage) imageNodes.item(i);
if (image.getXlinkHrefAttribute().equals(imagePath)) {
imageList.add(image);
}
}
if (imageList.size() > 0) {
return imageList;
}
} catch (Exception ex) {
Logger.getLogger(OdfDrawImage.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
}
return imageList;
}
/**
* The method deletes one or more images from image container by image path.
*
* @param doc the document the image should be deleted from
* @param imagePath the internal package path of the image.
*/
public static void deleteImageByPath(OdfSchemaDocument doc, String imagePath) {
List<OdfDrawImage> imageList = getImageByPath(doc, imagePath);
if (imageList != null) {
Iterator<OdfDrawImage> it = imageList.iterator();
while (it.hasNext()) {
OdfDrawImage image = it.next();
// remove the inserted picture
String ref = image.getXlinkHrefAttribute().toString();
doc.getPackage().remove(ref);
// remove the draw:frame element in main document
if (image.getParentNode() instanceof OdfDrawFrame) {
OdfDrawFrame frame = (OdfDrawFrame) image.getParentNode();
if (frame.getChildNodes().getLength() == 1) {
frame.getParentNode().removeChild(frame);
} else {
image.getParentNode().removeChild(image);
}
} else {
image.getParentNode().removeChild(image);
}
// remove Pictures/ directory if container does not have images
if (getImageCount(doc) == 0) {
doc.getPackage().remove(OdfPackage.OdfFile.IMAGE_DIRECTORY.getPath() + SLASH);
}
}
}
}
/**
* The method deletes the specified image from image container.
*
* @param doc the document the image should be deleted from
* @param image the image which need to be deleted
*/
public static void deleteImage(OdfSchemaDocument doc, OdfDrawImage image) {
// remove the inserted picture if it does not have reference any more
String ref = image.getXlinkHrefAttribute().toString();
List<OdfDrawImage> imageList = getImageByPath(doc, ref);
if (imageList.size() == 1) {
doc.getPackage().remove(ref);
}
// remove the draw:frame element in main document
if (image.getParentNode() instanceof OdfDrawFrame) {
OdfDrawFrame frame = (OdfDrawFrame) image.getParentNode();
if (frame.getChildNodes().getLength() == 1) {
frame.getParentNode().removeChild(frame);
} else {
image.getParentNode().removeChild(image);
}
} else {
image.getParentNode().removeChild(image);
}
// remove Pictures/ directory if container does not have images
if (getImageCount(doc) == 0) {
doc.getPackage().remove(OdfPackage.OdfFile.IMAGE_DIRECTORY.getPath() + SLASH);
}
}
/**
* Get the count of image objects in the image container.
*
* @param doc the document the image should be counted from
* @return the number of image in this document if no image is found, return zero
*/
public static int getImageCount(OdfSchemaDocument doc) {
try {
NodeList imageNodes =
doc.getContentDom().getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "image");
return imageNodes.getLength();
} catch (Exception ex) {
Logger.getLogger(OdfDrawImage.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
}
return 0;
}
/**
* The method return the image list in the image container.
*
* @param doc the document the list of images should be returned from
* @return an image list in this document if no images is found, return an empty list.
*/
public static List<OdfDrawImage> getImages(OdfSchemaDocument doc) {
ArrayList<OdfDrawImage> imageList = new ArrayList<OdfDrawImage>();
try {
NodeList imageNodes =
doc.getContentDom().getElementsByTagNameNS(OdfDocumentNamespace.DRAW.getUri(), "image");
for (int i = 0; i < imageNodes.getLength(); i++) {
OdfDrawImage image = (OdfDrawImage) imageNodes.item(i);
imageList.add(image);
}
} catch (Exception ex) {
Logger.getLogger(OdfDrawImage.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
}
return imageList;
}
/**
* The method return the set of all the image paths.
*
* @param doc the document the image path set should be obtained from
* @return an image path set in this document
*/
public static Set<String> getImagePathSet(OdfSchemaDocument doc) {
Set<String> paths = new HashSet<String>();
List<OdfDrawImage> imageList = getImages(doc);
Iterator<OdfDrawImage> it = imageList.iterator();
while (it.hasNext()) {
OdfDrawImage image = it.next();
paths.add(image.getXlinkHrefAttribute().toString());
}
return paths;
}
}