Java tutorial
/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.common.impl.content.image; import ch.entwine.weblounge.common.content.image.ImageContent; import ch.entwine.weblounge.common.impl.content.ResourceContentReaderImpl; import ch.entwine.weblounge.common.impl.util.WebloungeDateFormat; import ch.entwine.weblounge.common.language.Language; import ch.entwine.weblounge.common.security.User; import com.sun.media.jai.codec.MemoryCacheSeekableStream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.text.ParseException; import java.util.Date; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; /** * Utility class used to parse <code>Content</code> data for simple files. */ public class ImageContentReader extends ResourceContentReaderImpl<ImageContent> { /** Logging facility */ protected static final Logger logger = LoggerFactory.getLogger(ImageContentReader.class); /** * Creates a new file content reader that will parse serialized XML version of * the file content and store it in the * {@link ch.entwine.weblounge.common.content.ResourceContent} that is * returned by the {@link #read} method. * * @throws ParserConfigurationException * if the SAX parser setup failed * @throws SAXException * if an error occurs while parsing * * @see #createFromXml(InputStream) */ public ImageContentReader() throws ParserConfigurationException, SAXException { parserRef = new WeakReference<SAXParser>(parserFactory.newSAXParser()); } /** * This method is called to parse the serialized XML of a * {@link ch.entwine.weblounge.common.content.ResourceContent}. * * @param is * the content data * @throws ParserConfigurationException * if the SAX parser setup failed * @throws IOException * if reading the input stream fails * @throws SAXException * if an error occurs while parsing */ public ImageContent createFromXml(InputStream is) throws SAXException, IOException, ParserConfigurationException { SAXParser parser = parserRef.get(); if (parser == null) { parser = parserFactory.newSAXParser(); parserRef = new WeakReference<SAXParser>(parser); } parser.parse(is, this); return content; } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.content.ResourceContentReader#createFromContent(java.io.InputStream, * ch.entwine.weblounge.common.language.Language, long, java.lang.String) */ public ImageContent createFromContent(InputStream is, User user, Language language, long size, String fileName, String mimeType) throws IOException { ImageContent content = new ImageContentImpl(fileName, language, mimeType); // Use the logged in user as the author content.setCreator(user); // Set the creation date content.setCreationDate(new Date()); MemoryCacheSeekableStream mcss = new MemoryCacheSeekableStream(is); UnclosableInputStream bis = new UnclosableInputStream(mcss); // Read the Exif metadata (if available) try { readExifMetadata(content, bis); } catch (Throwable t) { logger.warn("Error extracting Exif metadata from {}: {}", fileName, t.getMessage()); } // Read the JAI metadata if (content.getWidth() <= 0 || content.getHeight() <= 0) { try { mcss.seek(0); readJAIMetadata(content, mcss); } catch (Throwable t) { logger.warn("Error extracting metadata using java advanced imaging (jai) from {}: {}", fileName, t.getMessage()); throw new IOException(t); } finally { IOUtils.closeQuietly(is); } } // Close the input stream IOUtils.closeQuietly(mcss); bis = null; return content; } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.impl.content.ResourceContentReaderImpl#createContent() */ @Override protected ImageContent createContent() { return new ImageContentImpl(); } /** * Resets the pagelet parser. */ public void reset() { super.reset(); content = null; } /** * {@inheritDoc} * * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, * java.lang.String, java.lang.String, org.xml.sax.Attributes) */ public void startElement(String uri, String local, String raw, Attributes attrs) throws SAXException { // start of a new content element if ("content".equals(raw)) { logger.debug("Started reading image content {}", content); } // gps position else if ("gps".equals(raw)) { double gpsLat = Double.parseDouble(attrs.getValue("lat")); double gpsLong = Double.parseDouble(attrs.getValue("lng")); content.setGpsPosition(gpsLat, gpsLong); logger.trace("Image's gps lat is '{}'", content.getGpsLat()); logger.trace("Image's gps long is '{}'", content.getGpsLong()); } super.startElement(uri, local, raw, attrs); } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.impl.content.WebloungeContentReader#endElement(java.lang.String, * java.lang.String, java.lang.String) */ public void endElement(String uri, String local, String raw) throws SAXException { // mime type if ("mimetype".equals(raw)) { content.setMimetype(getCharacters()); logger.trace("Images's content mimetype is '{}'", content.getMimetype()); } // size else if ("size".equals(raw)) { content.setSize(Long.parseLong(getCharacters())); logger.trace("Image's content filesize is '{}'", content.getSize()); } // height else if ("height".equals(raw)) { content.setHeight(Integer.parseInt(getCharacters())); logger.trace("Image's height is '{}'", content.getHeight()); } // width else if ("width".equals(raw)) { content.setWidth(Integer.parseInt(getCharacters())); logger.trace("Image's width is '{}'", content.getWidth()); } // date taken else if ("datetaken".equals(raw)) { try { content.setDateTaken(WebloungeDateFormat.parseStatic(getCharacters())); } catch (ParseException e) { throw new IllegalStateException("The date taken '" + getCharacters() + "' cannot be parsed", e); } logger.trace("Image's date taken is '{}'", content.getDateTaken()); } // location else if ("location".equals(raw)) { content.setLocation(getCharacters()); logger.trace("Image's location is '{}'", content.getLocation()); } // filmspeed else if ("filmspeed".endsWith(raw)) { content.setFilmspeed(Integer.parseInt(getCharacters())); logger.trace("Image's filmspeed is '{}'", content.getFilmspeed()); } // fnumber else if ("fnumber".equals(raw)) { content.setFNumber(Float.parseFloat(getCharacters())); logger.trace("Image's fnumber is '{}'", content.getFNumber()); } // focal width else if ("focalwidth".equals(raw)) { content.setFocalWidth(Integer.parseInt(getCharacters())); logger.trace("Image's focalwidth is '{}'", content.getFocalWidth()); } // exposure time else if ("exposuretime".equals(raw)) { content.setExposureTime(Float.parseFloat(getCharacters())); logger.trace("Image's exposuretime is '{}'", content.getExposureTime()); } else { super.endElement(uri, local, raw); } } /** * Extracts the Exif metadata from the image. * * @param content * the resource content * @param is * the input stream * @return the Exif metadata */ protected ImageMetadata readExifMetadata(ImageContent content, InputStream is) { BufferedInputStream bis = new BufferedInputStream(is); ImageMetadata exifMetadata = ImageMetadataUtils.extractMetadata(bis); if (exifMetadata == null) return null; if (exifMetadata.getDateTaken() != null) { content.setDateTaken(exifMetadata.getDateTaken()); } if (!StringUtils.isBlank(exifMetadata.getPhotographer())) { content.setAuthor(exifMetadata.getPhotographer()); } if (!StringUtils.isBlank(exifMetadata.getLocation())) { content.setLocation(exifMetadata.getLocation()); } if (exifMetadata.getGpsLat() != 0 && exifMetadata.getGpsLong() != 0) { content.setGpsPosition(exifMetadata.getGpsLat(), exifMetadata.getGpsLong()); } if (exifMetadata.getFilmspeed() != 0) { content.setFilmspeed(exifMetadata.getFilmspeed()); } if (exifMetadata.getFNumber() != 0) { content.setFNumber(exifMetadata.getFNumber()); } if (exifMetadata.getFocalWidth() != 0) { content.setFocalWidth(exifMetadata.getFocalWidth()); } if (exifMetadata.getExposureTime() != 0) { content.setExposureTime(exifMetadata.getExposureTime()); } return exifMetadata; } /** * Extracts image metadata from the image using Java Advanced Imaging (JAI). * * @param content * the resource content * @param is * the input stream * @return the image metadata */ protected RenderedOp readJAIMetadata(ImageContent content, InputStream is) { MemoryCacheSeekableStream imageInputStream = new MemoryCacheSeekableStream(is); RenderedOp jaiMetadata = JAI.create("stream", imageInputStream); if (jaiMetadata == null) return null; content.setWidth(jaiMetadata.getWidth()); content.setHeight(jaiMetadata.getHeight()); return jaiMetadata; } /** * Implementation of an input stream that ignores calls to * {@link java.io.InputStream#close()}. */ private static class UnclosableInputStream extends BufferedInputStream { /** * Creates a new input stream which will be fully consumed before being * closed. * * @param is * the input stream to be consumed from */ public UnclosableInputStream(InputStream is) { super(is); } /** * {@inheritDoc} * * @see java.io.BufferedInputStream#close() */ @Override public void close() throws IOException { // Don't do anything, we still need this input stream } } }