blob: 555f797edac6f7b6b5269b154ee04a13119c1152 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
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. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.odftoolkit.simple.draw;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
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.OdfElement;
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.odftoolkit.simple.Component;
import org.odftoolkit.simple.Document;
import org.odftoolkit.simple.style.StyleTypeDefinitions;
import org.odftoolkit.simple.style.StyleTypeDefinitions.AnchorType;
import org.odftoolkit.simple.style.StyleTypeDefinitions.FrameHorizontalPosition;
import org.odftoolkit.simple.style.StyleTypeDefinitions.FrameVerticalPosition;
import org.odftoolkit.simple.text.AbstractParagraphContainer;
import org.odftoolkit.simple.text.Paragraph;
import org.w3c.dom.DOMException;
/**
* This class provides method to add/remove/get images.
*
* @since 0.5.5
*/
public class Image extends Component {
private static final String SLASH = "/";
DrawImageElement mImageElement;
Frame mFrame;
URI mImageURI = null;
DrawFrameElement mElement;
Document mOwnerDocument;
FrameStyleHandler mStyleHandler;
private Image(DrawImageElement drawElement) {
mOwnerDocument = (Document) ((OdfFileDom) drawElement.getOwnerDocument()).getDocument();
mElement = (DrawFrameElement) drawElement.getParentNode();
if (mElement == null) {
Logger.getLogger(Image.class.getName()).log(Level.WARNING,
"The image has no parent frame. A new frame will be created as its parent");
OdfFileDom ownerDom = (OdfFileDom) drawElement.getOwnerDocument();
mElement = ownerDom.newOdfElement(DrawFrameElement.class);
mElement.appendChild(drawElement);
}
mFrame = Frame.getInstanceof(mElement);
mImageElement = drawElement;
}
/**
* Get a image instance by an instance of <code>DrawImageElement</code>.
*
* @param imageElement
* - the instance of DrawImageElement
* @return an instance of image
*/
public static Image getInstanceof(DrawImageElement imageElement) {
if (imageElement == null)
return null;
Image image = null;
image = (Image) Component.getComponentByElement(imageElement);
if (image != null)
return image;
Image myImage = new Image(imageElement);
Component.registerComponent(myImage, imageElement);
return myImage;
}
/**
* Add a hypertext reference to this image.
*
* @param linkto
* the hyperlink
* @since 0.6.5
*
*/
public void setHyperlink(URI linkto) {
mFrame.setHyperlink(linkto);
}
/**
* Return the URI of hypertext reference if exists, or else, return null.
*
* @return the URI of hyperlink if exists
*/
public URI getHyperlink() {
return mFrame.getHyperlink();
}
/**
* Get the owner document of this image
*
* @return the document who owns this image
*/
public Document getOwnerDocument() {
return mOwnerDocument;
}
/**
* Return style handler for this frame
*
* @return the style handler
*/
public FrameStyleHandler getStyleHandler() {
if (mStyleHandler == null)
mStyleHandler = new FrameStyleHandler(mFrame);
return mStyleHandler;
}
/**
* Return the instance of "draw:image" element
*
* @return the instance of "draw:image" element
*/
public DrawImageElement getOdfElement() {
return mImageElement;
}
/**
* Return the frame who contains this image.
*
* @return - the frame who contains this image
*/
public Frame getFrame() {
return mFrame;
}
/**
* Create an image and append it at the end of a container element.
*
* @param container
* - the frame container element
* @param uri
* - the URI of the image
* @return the instance of Image
*/
public static Image newImage(FrameContainer container, URI uri) {
Image mImage;
try {
OdfElement parent = container.getFrameContainerElement();
OdfFileDom ownerDom = (OdfFileDom) parent.getOwnerDocument();
DrawFrameElement fElement = ownerDom.newOdfElement(DrawFrameElement.class);
parent.appendChild(fElement);
DrawImageElement imageElement = fElement.newDrawImageElement();
// set uri and copy resource
String packagePath = insertImageResourceIntoPackage((OdfSchemaDocument) ownerDom.getDocument(), uri);
packagePath = packagePath.replaceFirst(ownerDom.getDocument().getDocumentPath(), "");
URI newURI = configureInsertedImage((OdfSchemaDocument) ownerDom.getDocument(), imageElement, packagePath,
false);
// create image object
mImage = new Image(imageElement);
mImage.mImageURI = newURI;
Component.registerComponent(mImage, imageElement);
// set default alignment
if (container instanceof Paragraph) {
mImage.getStyleHandler().setAchorType(AnchorType.TO_PARAGRAPH);
}
return mImage;
} catch (Exception e) {
Logger.getLogger(Image.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
return null;
}
/**
* Create an image and add it to a frame.
*
* @param frame
* - the frame which contains this image
* @param uri
* - the URI of the image
* @return the instance of Image
*/
public static Image newImage(Frame frame, URI uri) {
Image mImage;
try {
DrawFrameElement fElement = (DrawFrameElement) frame.getDrawFrameElement();
OdfFileDom ownerDom = (OdfFileDom) fElement.getOwnerDocument();
DrawImageElement imageElement = fElement.newDrawImageElement();
// set uri and copy resource
String packagePath = insertImageResourceIntoPackage((OdfSchemaDocument) ownerDom.getDocument(), uri);
packagePath = packagePath.replaceFirst(ownerDom.getDocument().getDocumentPath(), "");
URI newURI = configureInsertedImage((OdfSchemaDocument) ownerDom.getDocument(), imageElement, packagePath,
true);
// create image object
mImage = new Image(imageElement);
mImage.mImageURI = newURI;
Component.registerComponent(mImage, imageElement);
// set default alignment
FrameContainer container = frame.mFrameContainer;
if (container instanceof Paragraph) {
mImage.getStyleHandler().setAchorType(AnchorType.TO_PARAGRAPH);
}
return mImage;
} catch (Exception e) {
Logger.getLogger(Image.class.getName()).severe(e.getMessage());
}
return null;
}
private static String insertImageResourceIntoPackage(OdfSchemaDocument mOdfSchemaDoc, URI imageUri)
throws Exception {
String imageRef = imageUri.toString();
String mediaType = OdfFileEntry.getMediaTypeString(imageRef);
String packagePath = getPackagePath(mOdfSchemaDoc, imageRef);
mOdfSchemaDoc.getPackage().insert(imageUri, packagePath, mediaType);
return packagePath;
}
/* Helper method */
public static String getPackagePath(OdfSchemaDocument mOdfSchemaDoc, 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 = mOdfSchemaDoc.getDocumentPath() + packagePath;
}
/* Helper method */
public static URI configureInsertedImage(OdfSchemaDocument mOdfSchemaDoc, DrawImageElement imageElement,
String packagePath, boolean isResetSize) throws Exception {
// Set path to image attribute
URI uri = new URI(AnyURI.encodePath(packagePath).toString());
imageElement.setXlinkHrefAttribute(AnyURI.decodePath(uri.toString()));
// Set mandatory attribute xlink:type
imageElement.setXlinkTypeAttribute("simple");
// A draw:image is always embedded in a draw:frame
InputStream is = mOdfSchemaDoc.getPackage().getInputStream(packagePath);
DrawFrameElement odfFrame = (DrawFrameElement) imageElement.getParentNode();
Frame aFrame = Frame.getInstanceof(odfFrame);
FrameRectangle oldRect = aFrame.getRectangle();
if (oldRect.getLinearMeasure() != StyleTypeDefinitions.SupportedLinearMeasure.CM)
oldRect.setLinearMeasure(StyleTypeDefinitions.SupportedLinearMeasure.CM);
if (odfFrame != null) {
BufferedImage image = ImageIO.read(is);
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));
if (isResetSize) {
FrameRectangle newRect = aFrame.getRectangle();
newRect.setX(oldRect.getX()+(oldRect.getWidth()-newRect.getWidth())/2);
newRect.setY(oldRect.getY()+(oldRect.getHeight()-newRect.getHeight())/2);
aFrame.setRectangle(newRect);
}
}
return uri;
}
/**
* Return an iterator of image.
*
* @param container the frame container.
* @return the image iterator.
*/
public static Iterator<Image> imageIterator(FrameContainer container) {
return new SimpleImageIterator(container);
}
/**
* Remove the image from the document.
* <p>
* The resource is removed if it's only used by this object.
*
* @return true if the image object is successfully removed; false if
* otherwise.
*/
public boolean remove() {
OdfElement containerElement = (OdfElement) mElement.getParentNode();
try {
mElement.removeChild(getOdfElement());
if (mElement.hasChildNodes() == false)
containerElement.removeChild(mElement);
mOwnerDocument.removeElementLinkedResource(getOdfElement());
} catch (DOMException exception) {
Logger.getLogger(AbstractParagraphContainer.class.getName()).log(Level.WARNING, exception.getMessage());
return false;
}
return true;
}
/**
* Update the image file with another resource.
*
* @param imageUri
* - the URI of the new image resource
*/
public void updateImage(URI imageUri) {
try {
// remove the old resource
String packagePath = mImageURI.toString();
mOwnerDocument.getPackage().remove(packagePath);
// insert the new resource
String imageRef = imageUri.toString();
String mediaType = OdfFileEntry.getMediaTypeString(imageRef);
mOwnerDocument.getPackage().insert(imageUri, packagePath, mediaType);
} catch (Exception e) {
Logger.getLogger(Image.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
/**
* Get the image resource as an input stream.
*
* @return - the input stream of the image resource
*/
public InputStream getImageInputStream() {
return mOwnerDocument.getPackage().getInputStream(getInternalPath());
}
/**
* Get the internal path within the package of the image resource as a
* string.
*
* @return - the internal path of the image resource
*/
public String getInternalPath() {
try {
if (mImageURI == null)
mImageURI = new URI(mImageElement.getXlinkHrefAttribute());
return mImageURI.toString();
} catch (URISyntaxException e) {
Logger.getLogger(Image.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
return null;
}
/**
* Get the media type of the image resource
*
* @return - the media type of the image resource
*/
public String getMediaTypeString() {
return mOwnerDocument.getPackage().getMediaTypeString(getInternalPath());
}
private static class SimpleImageIterator implements Iterator<Image> {
private OdfElement containerElement;
private Image nextElement = null;
private Image tempElement = null;
private SimpleImageIterator(FrameContainer container) {
containerElement = container.getFrameContainerElement();
}
public boolean hasNext() {
tempElement = findNext(nextElement);
return (tempElement != null);
}
public Image next() {
if (tempElement != null) {
nextElement = tempElement;
tempElement = null;
} else {
nextElement = findNext(nextElement);
}
if (nextElement == null) {
return null;
} else {
return nextElement;
}
}
public void remove() {
if (nextElement == null) {
throw new IllegalStateException("please call next() first.");
}
containerElement.removeChild(nextElement.getOdfElement());
}
private Image findNext(Image thisImage) {
DrawImageElement nextFrame = null;
if (thisImage == null) {
nextFrame = OdfElement.findFirstChildNode(DrawImageElement.class, containerElement);
} else {
nextFrame = OdfElement.findNextChildNode(DrawImageElement.class, thisImage.getOdfElement());
}
if (nextFrame != null) {
return Image.getInstanceof(nextFrame);
}
return null;
}
}
/**
* Set the name of this image.
*
* @param name
* - the name of the image
*/
public void setName(String name) {
mFrame.setName(name);
}
/**
* Get the name of this image.
*
* @return the name of the image
*/
public String getName() {
return mFrame.getName();
}
/**
* Set the rectangle used by this image
*
* @param rectangle
* - the rectangle used by this image
*/
public void setRectangle(FrameRectangle rectangle) {
mFrame.setRectangle(rectangle);
}
/**
* Return the rectangle used by this image
*
* @return - the rectangle
*/
public FrameRectangle getRectangle() {
return mFrame.getRectangle();
}
/**
* Set the title of this image
*
* @param title
* - the title of this image
*/
public void setTitle(String title) {
mFrame.setTitle(title);
}
/**
* Get the title of this image
*
* @return - the title of this image
*/
public String getTitle() {
return mFrame.getTitle();
}
/**
* Get the description of this image
*
* @return - the description of this image
*/
public String getDesciption() {
return mFrame.getDesciption();
}
/**
* Set the description of this image.
*
* @param description
* - the description of this image
*/
public void setDescription(String description) {
mFrame.setDescription(description);
}
/**
* Set the horizontal position
*
* @param horizontalPos
* - the horizontal position
*/
public void setHorizontalPosition(FrameHorizontalPosition horizontalPos) {
getStyleHandler().setHorizontalPosition(horizontalPos);
}
/**
* Set the vertical position
*
* @param verticalPos
* - the vertical position
*/
public void setVerticalPosition(FrameVerticalPosition verticalPos) {
getStyleHandler().setVerticalPosition(verticalPos);
}
/**
* Return the horizontal position
*
* @return the horizontal position
*/
public FrameHorizontalPosition getHorizontalPosition() {
return getStyleHandler().getHorizontalPosition();
}
/**
* Return the vertical position
*
* @return the vertical position
*/
public FrameVerticalPosition getVerticalPosition() {
return getStyleHandler().getVerticalPosition();
}
}