/* * ImageI/O-Ext - OpenSource Java Image translation Library * http://www.geo-solutions.it/ * http://java.net/projects/imageio-ext/ * (C) 2008, GeoSolutions * * This library 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 3 of the License, or (at your option) any later version. * * This library 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. */ package it.geosolutions.imageio.plugins.jp2k; import it.geosolutions.imageio.plugins.jp2k.box.BoxUtilities; import java.lang.ref.SoftReference; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.metadata.IIOMetadataNode; import javax.swing.tree.DefaultMutableTreeNode; import kdu_jni.Jp2_family_src; import kdu_jni.Jp2_input_box; import kdu_jni.Jp2_locator; import kdu_jni.KduException; /** * {@link JP2KBox} which is loaded lazily, which means only when the content is * needed. * * @author Simone Giannecchini, GeoSolutions * */ class LazyJP2KBox extends DefaultMutableTreeNode implements JP2KBoxMetadata { @Override public String toString() { final String superString = super.toString(); final StringBuilder builder = new StringBuilder( superString != null ? superString : ""); builder.append("\n"); builder.append("type:").append(type).append("\n"); builder.append("box class:").append(BoxUtilities.getBoxClass(type)) .append("\n"); builder.append("type hex:").append(Integer.toHexString(type).toUpperCase()).append( "\n"); builder.append("box name:").append(BoxUtilities.getBoxName(type)) .append("\n"); return builder.toString(); } /** * */ private static final long serialVersionUID = -3905954214836933636L; private final static Logger LOGGER = Logger.getLogger("LazyJP2Box"); private final Jp2_locator locator; private int type; private SoftReference<? extends JP2KBox> boxRef; private String filename; /** * Build a new {@link LazyJP2KBox}. * * @param filename * the input filename * @param type * the box type * @param locator * the JP2 locator referring this JP2K Box. */ LazyJP2KBox(final String filename, final int type, final Jp2_locator locator) { this.filename = filename; this.locator = locator; this.type = type; } /** * @see it.geosolutions.imageio.plugins.jp2k.box.JP2KBox#getContent() */ public byte[] getContent() { // superbox don't return any content if (!isLeaf()) return null; // paranoid check if (BoxUtilities.SUPERBOX_NAMES.contains(BoxUtilities.getTypeString(type))) return null; final JP2KBox originalBox = loadBox(); return originalBox.getContent(); } private synchronized JP2KBox loadBox() { JP2KBox retVal = this.boxRef == null ? null : this.boxRef.get(); if (retVal == null) { final Jp2_family_src familySource = new Jp2_family_src(); final Jp2_input_box box = new Jp2_input_box(); try { familySource.Open(filename); // // // // Get the required Jp2_input_box using the locator // // // box.Open(familySource, locator); retVal = BoxUtilities.createBox(type, BoxUtilities.getContent(box)); this.boxRef = new SoftReference<JP2KBox>(retVal); } catch (KduException e) { throw new RuntimeException( "Error caused by a Kakadu exception during Box management! ", e); } finally { // clean up try { familySource.Close(); } catch (Exception e) { if (LOGGER.isLoggable(Level.FINEST)) LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e); } try { if (box != null) box.Close(); } catch (Exception e) { if (LOGGER.isLoggable(Level.FINEST)) LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e); } } } return retVal; } /** * @see it.geosolutions.imageio.plugins.jp2k.box.JP2KBox#getExtraLength() */ public long getExtraLength() { final JP2KBox originalBox = loadBox(); return originalBox.getExtraLength(); } /** * @see it.geosolutions.imageio.plugins.jp2k.box.JP2KBox#getLength() */ public int getLength() { final JP2KBox originalBox = loadBox(); return originalBox.getLength(); } /** * @see it.geosolutions.imageio.plugins.jp2k.box.JP2KBox#getType() */ public int getType() { return type; } JP2KBox getOriginalBox() { return loadBox(); } public IIOMetadataNode getNativeNode() { //Delegate the nativeNode creation to the original box return ((JP2KBoxMetadata)getOriginalBox()).getNativeNode(); } /** * Utility method to return the original box related to an input Box. * @param box * @return */ static JP2KBox getAsOriginalBox(JP2KBox box) { JP2KBox returnedBox = null; if (box instanceof LazyJP2KBox) returnedBox = (JP2KBox) ((LazyJP2KBox) box).getOriginalBox(); else if (box instanceof JP2KBox) returnedBox = (JP2KBox) box; else throw new IllegalArgumentException("Not a valid JP2Box"); return returnedBox; } @Override public Object clone() { // LazyJP2KBox newBox = (LazyJP2KBox)super.clone(); Jp2_locator locator = new Jp2_locator(); try { final long filePos = this.locator.Get_file_pos(); locator.Set_file_pos(filePos); // newBox.filename = filename; // newBox.type = type; // newBox.locator = locator; // newBox.boxRef = null; // return newBox; return new LazyJP2KBox(filename, type, locator); } catch (KduException e) { throw new RuntimeException( "Error caused by a Kakadu exception during Box management! ", e); } } }