ImageAsset + ReuseableImageAsset

* JAI ersetzt durch ImageIO (#1941)
* ReusableImageAsset ausgeräumt und alle unnötigen Code-Dopplungen entfernt
* ImageAsset umgestellt auf ImageIO. Fehlerhafte guessImageSize durch eine zuverlässiger funktionierende Methode ersetzt.



git-svn-id: https://svn.libreccm.org/ccm/trunk@2461 8810af33-2d31-482b-a856-94f89814c4df
master
quasi 2013-11-26 21:53:31 +00:00
parent e85fde631b
commit c8be91ff92
2 changed files with 237 additions and 349 deletions

View File

@ -21,15 +21,12 @@ package com.arsdigita.cms;
import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.mimetypes.ImageMimeType; import com.arsdigita.mimetypes.ImageMimeType;
import com.arsdigita.mimetypes.MimeType; import com.arsdigita.mimetypes.MimeType;
import com.arsdigita.mimetypes.image.ImageSizer;
import com.arsdigita.mimetypes.image.ImageSizerFactory;
import com.arsdigita.persistence.DataCollection; import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.Filter; import com.arsdigita.persistence.Filter;
import com.arsdigita.persistence.OID; import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.SessionManager;
import com.arsdigita.versioning.VersionedACSObject; import com.arsdigita.versioning.VersionedACSObject;
import java.awt.Dimension;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -42,10 +39,9 @@ import javax.imageio.ImageIO;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* <p>An {@link com.arsdigita.cms.Asset asset} representing an * <p>An {@link com.arsdigita.cms.Asset asset} representing an image. An
* image. An ImageAsset is deleted when its parent content item is * ImageAsset is deleted when its parent content item is deleted and is not
* deleted and is not intended to be reused between content * intended to be reused between content items..</p>
* items..</p>
* *
* @see com.arsdigita.cms.ReusableImageAsset * @see com.arsdigita.cms.ReusableImageAsset
* @see com.arsdigita.cms.BinaryAsset * @see com.arsdigita.cms.BinaryAsset
@ -58,265 +54,276 @@ import org.apache.log4j.Logger;
*/ */
public class ImageAsset extends BinaryAsset { public class ImageAsset extends BinaryAsset {
public static final String BASE_DATA_OBJECT_TYPE = public static final String BASE_DATA_OBJECT_TYPE =
"com.arsdigita.cms.ImageAsset"; "com.arsdigita.cms.ImageAsset";
public static final String CONTENT = "content"; public static final String CONTENT = "content";
public static final String HEIGHT = "height"; public static final String HEIGHT = "height";
public static final String WIDTH = "width"; public static final String WIDTH = "width";
public static final String MIME_JPEG = "image/jpeg"; public static final String MIME_JPEG = "image/jpeg";
public static final String MIME_GIF = "image/gif"; public static final String MIME_GIF = "image/gif";
private static final Logger s_log = Logger.getLogger(ImageAsset.class); private static final Logger s_log = Logger.getLogger(ImageAsset.class);
/** /**
* Default constructor. This creates a new image asset. * Default constructor. This creates a new image asset.
*/ */
public ImageAsset() { public ImageAsset() {
super(BASE_DATA_OBJECT_TYPE); super(BASE_DATA_OBJECT_TYPE);
} }
/** /**
* Constructor. The contained <code>DataObject</code> is retrieved * Constructor. The contained
* from the persistent storage mechanism with an <code>OID</code> * <code>DataObject</code> is retrieved from the persistent storage
* specified by <i>oid</i>. * mechanism with an
* * <code>OID</code> specified by <i>oid</i>.
* @param oid The <code>OID</code> for the retrieved *
* <code>DataObject</code>. * @param oid The <code>OID</code> for the retrieved
*/ * <code>DataObject</code>.
public ImageAsset(OID oid) throws DataObjectNotFoundException { */
super(oid); public ImageAsset(OID oid) throws DataObjectNotFoundException {
} super(oid);
}
/** /**
* Constructor. The contained <code>DataObject</code> is retrieved * Constructor. The contained
* from the persistent storage mechanism with an <code>OID</code> * <code>DataObject</code> is retrieved from the persistent storage
* specified by <i>id</i> and * mechanism with an
* <code>ImageAsset.BASE_DATA_OBJECT_TYPE</code>. * <code>OID</code> specified by <i>id</i> and
* * <code>ImageAsset.BASE_DATA_OBJECT_TYPE</code>.
* @param id The <code>id</code> for the retrieved *
* <code>DataObject</code>. * @param id The <code>id</code> for the retrieved <code>DataObject</code>.
**/ *
public ImageAsset(BigDecimal id) throws DataObjectNotFoundException { */
this(new OID(BASE_DATA_OBJECT_TYPE, id)); public ImageAsset(BigDecimal id) throws DataObjectNotFoundException {
} this(new OID(BASE_DATA_OBJECT_TYPE, id));
}
public ImageAsset(DataObject obj) { public ImageAsset(DataObject obj) {
super(obj); super(obj);
} }
public ImageAsset(String type) { public ImageAsset(String type) {
super(type); super(type);
} }
/** /**
* @return the base PDL object type for this item. Child classes should * @return the base PDL object type for this item. Child classes should
* override this method to return the correct value * override this method to return the correct value
*/ */
public String getBaseDataObjectType() { @Override
return BASE_DATA_OBJECT_TYPE; public String getBaseDataObjectType() {
} return BASE_DATA_OBJECT_TYPE;
}
public BigDecimal getWidth() { public BigDecimal getWidth() {
return (BigDecimal) get(WIDTH); return (BigDecimal) get(WIDTH);
} }
public void setWidth(BigDecimal width) { public void setWidth(BigDecimal width) {
set(WIDTH, width); set(WIDTH, width);
} }
public BigDecimal getHeight() { public BigDecimal getHeight() {
return (BigDecimal) get(HEIGHT); return (BigDecimal) get(HEIGHT);
} }
public void setHeight(BigDecimal height) { public void setHeight(BigDecimal height) {
set(HEIGHT, height); set(HEIGHT, height);
} }
/** /**
* Retrieves the Blob content. * Retrieves the Blob content.
* *
* @return the Blob content * @return the Blob content
*/ */
@Override @Override
protected byte[] getContent() { protected byte[] getContent() {
return (byte[]) get(CONTENT); return (byte[]) get(CONTENT);
} }
/** /**
* Sets the Blob content. * Sets the Blob content.
*/ */
@Override @Override
protected void setContent(byte[] content) { protected void setContent(byte[] content) {
set(CONTENT, content); set(CONTENT, content);
} }
/** /**
* Load the image asset from the specified file. Automatically guesses * Load the image asset from the specified file. Automatically guesses the
* the mime type of the file. If the file is a jpeg, tries to automatically * mime type of the file. If the file is a jpeg, tries to automatically
* determine width and height, as well. * determine width and height, as well.
* *
* @param fileName The original name of the file * @param fileName The original name of the file
* @param file The actual file on the server * @param file The actual file on the server
* @param defaultMimeType The default mime type for the file * @param defaultMimeType The default mime type for the file (ignored)
*/ */
public void loadFromFile(String fileName, File file, String defaultMimeType) public void loadFromFile(String fileName, File file, String defaultMimeType)
throws IOException { throws IOException, IllegalArgumentException {
// Guess mime type BufferedImage image;
MimeType mime = MimeType.guessMimeTypeFromFile(fileName);
if (mime != null && mime instanceof ImageMimeType) { if (file == null) {
guessSize(file, (ImageMimeType) mime); throw new IllegalArgumentException("Parameter file must not be null.");
} else { }
// Set default mime type
mime = MimeType.loadMimeType(defaultMimeType);
}
setMimeType(mime); try {
image = ImageIO.read(file);
} catch (IOException ex) {
throw new IOException("Can't read image format.");
}
// Extract the filename // Guess mime type
int i = fileName.lastIndexOf("/"); MimeType mime = MimeType.guessMimeTypeFromFile(fileName);
if (i > 0) { if (mime == null && !(mime instanceof ImageMimeType)) {
fileName = fileName.substring(i + 1); throw new IOException("Unsupported image format.");
} }
i = fileName.lastIndexOf("\\"); // DOS-style setMimeType(mime);
if (i > 0) {
fileName = fileName.substring(i + 1);
}
setName(fileName); // Image size
readImageSize(image);
FileInputStream in = new FileInputStream(file); // Extract filename
readBytes(in); setName(extractFilename(fileName));
}
/** // Create InputStream
* Write the image asset content to a file. FileInputStream in = new FileInputStream(file);
*
* @param file The file on the server to write to.
*/
@Override
public void writeToFile(File file)
throws IOException {
FileOutputStream fs = new FileOutputStream(file);
try {
fs.write(getContent());
} finally { // Save image data
if (null != fs) { readBytes(in);
fs.close(); }
}
}
}
/** /**
* Guess image size by loading it from file. Set the WIDTH and HEIGHT * Write the image asset content to a file.
* attributes, if possible *
*/ * @param file The file on the server to write to.
protected void guessSize(File file, ImageMimeType mime) { */
BigDecimal width = null, height = null; @Override
ImageSizer sizer = ImageSizerFactory.getImageSizer(mime.getMimeType()); public void writeToFile(File file)
throws IOException {
FileOutputStream fs = new FileOutputStream(file);
try {
fs.write(getContent());
try { } finally {
if (sizer != null) { if (null != fs) {
Dimension d = sizer.computeImageSize(file); fs.close();
if (d != null) { }
width = new BigDecimal((int) d.getWidth()); }
height = new BigDecimal((int) d.getHeight()); }
}
}
} catch (IOException ex) {
s_log.error("IOException guessing file size", ex);
// do nothing
}
setWidth(width); /**
setHeight(height); * Retrieve all images in the database. Extremely expensive !
} *
* @return a collection of ImageAssets
*/
public static ImageAssetCollection getAllImages() {
DataCollection da = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
da.addEqualsFilter(VersionedACSObject.IS_DELETED, new Integer(0));
return new ImageAssetCollection(da);
}
/** /**
* Retrieve all images in the database. Extremely expensive ! * Find all images whose name matches the specified keyword
* *
* @return a collection of ImageAssets * @param keyword a String keyword
*/ * @param context the context for the retrieved items. Should be
public static ImageAssetCollection getAllImages() { * {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
DataCollection da = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); * @return a collection of images whose name matches the keyword
da.addEqualsFilter(VersionedACSObject.IS_DELETED, new Integer(0)); */
return new ImageAssetCollection(da); public static ImageAssetCollection getImagesByKeyword(
} String keyword, String context) {
ImageAssetCollection c = getAllImages();
c.addOrder(Asset.NAME);
Filter f;
f = c.addFilter("name like (\'%\' || :keyword || \'%\')");
f.set("keyword", keyword);
f = c.addFilter("version = :version");
f.set("version", context);
return c;
}
/** /**
* Find all images whose name matches the specified keyword * Find all images whose name matches the specified keyword
* *
* @param keyword a String keyword * @param keyword a String keyword
* @param context the context for the retrieved items. Should be * @return a collection of images whose name matches the keyword
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE} */
* @return a collection of images whose name matches the keyword public static ImageAssetCollection getImagesByKeyword(String keyword) {
*/ return getImagesByKeyword(keyword, ContentItem.DRAFT);
public static ImageAssetCollection getImagesByKeyword( }
String keyword, String context) {
ImageAssetCollection c = getAllImages();
c.addOrder(Asset.NAME);
Filter f;
f = c.addFilter("name like (\'%\' || :keyword || \'%\')");
f.set("keyword", keyword);
f = c.addFilter("version = :version");
f.set("version", context);
return c;
}
/** /**
* Find all images whose name matches the specified keyword * Resize this ImageAsset proportional to maxThumbnailWidth, if this
* * ImageAsset is wider then maxThumbnailWidth. Else just return this
* @param keyword a String keyword * ImageAsset.
* @return a collection of images whose name matches the keyword *
*/ * @param maxThumbnailWidth max image width
public static ImageAssetCollection getImagesByKeyword(String keyword) { * @return
return getImagesByKeyword(keyword, ContentItem.DRAFT); */
} public ImageAsset proportionalResizeToWidth(int maxThumbnailWidth) {
/** if (this.getWidth().intValue() <= maxThumbnailWidth) {
* Resize this ImageAsset proportional to maxThumbnailWidth, if this ImageAsset
* is wider then maxThumbnailWidth. Else just return this ImageAsset.
*
* @param maxThumbnailWidth max image width
* @return
*/
public ImageAsset proportionalResizeToWidth(int maxThumbnailWidth) {
if (this.getWidth().intValue() <= maxThumbnailWidth) { return this;
return this; } else {
} else { ImageAsset imageAsset = new ImageAsset();
imageAsset.setMimeType(this.getMimeType());
imageAsset.setName("Scaled" + this.getName());
ImageAsset imageAsset = new ImageAsset(); ByteArrayInputStream in = new ByteArrayInputStream(this.getContent());
imageAsset.setMimeType(this.getMimeType()); try {
imageAsset.setName("Scaled" + this.getName()); BufferedImage origImage = ImageIO.read(in);
ByteArrayInputStream in = new ByteArrayInputStream(this.getContent()); ByteArrayOutputStream scaledImageBuffer = new ByteArrayOutputStream();
try {
BufferedImage origImage = ImageIO.read(in);
ByteArrayOutputStream scaledImageBuffer = new ByteArrayOutputStream(); java.awt.Image scaledImage = origImage.getScaledInstance(maxThumbnailWidth, -1, java.awt.Image.SCALE_SMOOTH);
java.awt.Image scaledImage = origImage.getScaledInstance(maxThumbnailWidth, -1, java.awt.Image.SCALE_SMOOTH); BufferedImage scaledBufImage = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), origImage.getType());
scaledBufImage.getGraphics().drawImage(scaledImage, 0, 0, null);
BufferedImage scaledBufImage = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), origImage.getType()); ImageIO.write(scaledBufImage, this.getMimeType().getFileExtension(), scaledImageBuffer);
scaledBufImage.getGraphics().drawImage(scaledImage, 0, 0, null);
ImageIO.write(scaledBufImage, this.getMimeType().getFileExtension(), scaledImageBuffer); imageAsset.setContent(scaledImageBuffer.toByteArray());
imageAsset.setWidth(new BigDecimal(scaledImage.getWidth(null)));
imageAsset.setHeight(new BigDecimal(scaledImage.getHeight(null)));
imageAsset.setContent(scaledImageBuffer.toByteArray()); } catch (IOException e) {
imageAsset.setWidth(new BigDecimal(scaledImage.getWidth(null))); imageAsset.setContent(this.getContent());
imageAsset.setHeight(new BigDecimal(scaledImage.getHeight(null))); imageAsset.setWidth(this.getWidth());
imageAsset.setHeight(this.getHeight());
}
} catch (IOException e) { return imageAsset;
imageAsset.setContent(this.getContent()); }
imageAsset.setWidth(this.getWidth()); }
imageAsset.setHeight(this.getHeight());
}
return imageAsset; /**
} * Extract filename from path
} *
* @param fileName
* @return filename
*/
protected String extractFilename(String fileName) {
//
// Extract the filename
int i = fileName.lastIndexOf("/");
if (i > 0) {
fileName = fileName.substring(i + 1);
}
i = fileName.lastIndexOf("\\"); // DOS-style
if (i > 0) {
fileName = fileName.substring(i + 1);
}
return fileName;
}
/**
* Read image size from file.
*/
private void readImageSize(BufferedImage image) {
setWidth(new BigDecimal(image.getWidth()));
setHeight(new BigDecimal(image.getHeight()));
}
} }

View File

@ -20,22 +20,14 @@ package com.arsdigita.cms;
import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.kernel.ACSObject; import com.arsdigita.kernel.ACSObject;
import com.arsdigita.mimetypes.ImageMimeType;
import com.arsdigita.mimetypes.MimeType;
import com.arsdigita.persistence.DataCollection; import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.Filter; import com.arsdigita.persistence.Filter;
import com.arsdigita.persistence.OID; import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.SessionManager;
import com.arsdigita.versioning.VersionedACSObject; import com.arsdigita.versioning.VersionedACSObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.awt.image.RenderedImage;
import javax.media.jai.JAI;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -101,122 +93,11 @@ public class ReusableImageAsset extends ImageAsset {
* @return the base PDL object type for this item. Child classes should * @return the base PDL object type for this item. Child classes should
* override this method to return the correct value * override this method to return the correct value
*/ */
@Override
public String getBaseDataObjectType() { public String getBaseDataObjectType() {
return BASE_DATA_OBJECT_TYPE; return BASE_DATA_OBJECT_TYPE;
} }
public BigDecimal getWidth() {
return (BigDecimal) get(WIDTH);
}
public void setWidth(BigDecimal width) {
set(WIDTH, width);
}
public BigDecimal getHeight() {
return (BigDecimal) get(HEIGHT);
}
public void setHeight(BigDecimal height) {
set(HEIGHT, height);
}
/**
* Retrieves the Blob content.
*
* @return the Blob content
*/
protected byte[] getContent() {
return (byte[]) get(CONTENT);
}
/**
* Sets the Blob content.
*/
protected void setContent(byte[] content) {
set(CONTENT, content);
}
/**
* Load the image asset from the specified file. Automatically guesses
* the mime type of the file. If the file is a jpeg, tries to automatically
* determine width and height, as well.
*
* @param fileName The original name of the file
* @param File The actual file on the server
* @param defaultMimeType The default mime type for the file
*/
public void loadFromFile(String fileName, File file, String defaultMimeType)
throws IOException {
// Guess mime type
MimeType mime = MimeType.guessMimeTypeFromFile(fileName);
if (s_log.isDebugEnabled()) {
s_log.debug("Mime type is " + (null == mime ? "null" : mime.
getMimeType()));
}
RenderedImage image = JAI.create("FileLoad", file.getPath());
int width = image.getWidth();
int height = image.getHeight();
if (s_log.isDebugEnabled()) {
s_log.debug("Width: " + width);
s_log.debug("Height: " + height);
}
if (s_log.isDebugEnabled()) {
String[] props = image.getPropertyNames();
for (int i = 0; i < props.length; i++) {
String prop = props[i];
s_log.debug(prop + ": " + image.getProperty(prop));
}
}
setWidth(new BigDecimal(width));
setHeight(new BigDecimal(height));
if (mime == null || !(mime instanceof ImageMimeType)) {
mime = MimeType.loadMimeType(defaultMimeType);
}
setMimeType(mime);
// Extract the filename
int i = fileName.lastIndexOf("/");
if (i > 0) {
fileName = fileName.substring(i + 1);
}
i = fileName.lastIndexOf("\\"); // DOS-style
if (i > 0) {
fileName = fileName.substring(i + 1);
}
setName(fileName);
FileInputStream in = new FileInputStream(file);
readBytes(in);
}
/**
* Write the image asset content to a file.
*
* @param file The file on the server to write to.
*/
public void writeToFile(File file)
throws IOException {
FileOutputStream fs = new FileOutputStream(file);
try {
fs.write(getContent());
} finally {
if (null != fs) {
fs.close();
}
}
}
/** /**
* Retrieve all images in the database. Expensive operation. * Retrieve all images in the database. Expensive operation.
* *