/* * #%L * OME library for reading the JPEG XR file format. * %% * Copyright (C) 2013 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package ome.jxr.ifd; import java.io.IOException; import java.util.EnumMap; import java.util.Map; import loci.common.ByteArrayHandle; import loci.common.DataTools; import ome.jxr.JXRException; /** * Provides access to metadata extracted from the IFD part of a JPEG XR file. * Adds simple logic to translate the raw byte data into primitive data types. * The getters don't return primitive language types, so as to allow returning * <code>null</code>. That value indicates a missing metadata element and cannot * be confused with a numerical value (e.g. 0). This class also verifies value * validity on a very basic level (no inferring of metadata value combination * meanings), and where needed - returns a default as dictated by the ITU-T * specification. * * @author Blazej Pindelski bpindelski at dundee.ac.uk * * <dl> */ public class IFDMetadata { // TODO: PTM_COLOR_INFO // TODO: PROFILE_LEVEL_CONTAINER private long fileSizeInBytes; private Map<IFDEntry, byte[]> entries = new EnumMap<IFDEntry, byte[]>(IFDEntry.class); public IFDMetadata(long fileSizeInBytes) { this.fileSizeInBytes = fileSizeInBytes; } public void put(IFDEntry entry, byte[] value) { entries.put(entry, value); } public Integer getBitsPerPixel() throws JXRException { verifyRequiredEntries(); PixelFormat pixelFormat = PixelFormat.findById(entries .get(IFDEntry.PIXEL_FORMAT)); return pixelFormat.getPixelType().getBits(); } public Integer getNumberOfChannels() throws JXRException { verifyRequiredEntries(); PixelFormat pixelFormat = PixelFormat.findById(entries .get(IFDEntry.PIXEL_FORMAT)); return pixelFormat.getNumberOfChannels(); } public Long getImageWidth() throws JXRException { verifyRequiredEntries(); return DataTools.bytesToLong(entries.get(IFDEntry.IMAGE_WIDTH), true); } public Long getImageHeight() throws JXRException { verifyRequiredEntries(); return DataTools.bytesToLong(entries.get(IFDEntry.IMAGE_HEIGHT), true); } public Integer getImageOffset() throws JXRException { verifyRequiredEntries(); return DataTools.bytesToInt(entries.get(IFDEntry.IMAGE_OFFSET), true); } public Long getImageByteCount() throws JXRException { verifyRequiredEntries(); Long value = DataTools.bytesToLong(entries.get(IFDEntry.IMAGE_BYTE_COUNT), true); return value != 0 ? value : fileSizeInBytes-getImageOffset(); } public String getDocumentName() throws IOException { return nullOrString(entries.get(IFDEntry.DOCUMENT_NAME)); } public String getImageDescription() throws IOException { return nullOrString(entries.get(IFDEntry.IMAGE_DESCRIPTION)); } public String getEquipmentMake() throws IOException { return nullOrString(entries.get(IFDEntry.EQUIPMENT_MAKE)); } public String getEquipmentModel() throws IOException { return nullOrString(entries.get(IFDEntry.EQUIPMENT_MODEL)); } public String getPageName() throws IOException { return nullOrString(entries.get(IFDEntry.PAGE_NAME)); } public Short getPageNumber() { return nullOrShort(entries.get(IFDEntry.PAGE_NUMBER)); } public String getSoftwareNameVersion() throws IOException { return nullOrString(entries.get(IFDEntry.SOFTWARE_NAME_VERSION)); } public String getDateTime() throws IOException { return parseDateTime(entries.get(IFDEntry.DATE_TIME)); } public String getArtistName() throws IOException { return nullOrString(entries.get(IFDEntry.ARTIST_NAME)); } public String getHostComputer() throws IOException { return nullOrString(entries.get(IFDEntry.HOST_COMPUTER)); } public String getCopyrightNotice() throws IOException { return nullOrString(entries.get(IFDEntry.COPYRIGHT_NOTICE)); } public Short getColorSpace() { return parseColorSpace(entries.get(IFDEntry.COLOR_SPACE)); } public Long getPrefferedSpatialTransformation() { Long value = nullOrLong(entries.get(IFDEntry.SPATIAL_XFRM_PRIMARY)); return value != null ? value : 0; } public Long getImageType() { return nullOrLong(entries.get(IFDEntry.IMAGE_TYPE)); } public Float getWidthResoulution() { Float value = nullOrFloat(entries.get(IFDEntry.WIDTH_RESOLUTION)); return (value == null || value == 0) ? 96 : value; } public Float getHeightResoulution() { Float value = nullOrFloat(entries.get(IFDEntry.HEIGHT_RESOLUTION)); return (value == null || value == 0) ? 96 : value; } public Long getAlphaOffset() { return nullOrLong(entries.get(IFDEntry.ALPHA_OFFSET)); } public Long getAlphaByteCount() { return nullOrLong(entries.get(IFDEntry.ALPHA_BYTE_COUNT)); } public Short getImageBandPresence() { return nullOrShort(entries.get(IFDEntry.IMAGE_BAND_PRESENCE)); } public Short getAlphaBandPresence() { return nullOrShort(entries.get(IFDEntry.ALPHA_BAND_PRESENCE)); } private String parseDateTime(byte[] value) throws IOException { String date = nullOrString(value); String unknownDate = "[0 ]{4}:[0 ]{2}:[0 ]{2} [0 ]{2}:[0 ]{2}:[0 ]{2}"; if (date == null || date.matches(unknownDate)) { return null; } else { return date; } } private Short parseColorSpace(byte[] value) { Short colorSpace = nullOrShort(value); if (colorSpace == null) { return null; } else { return colorSpace == 1 || colorSpace == 0xffff ? colorSpace : (short) 0xffff; } } private String nullOrString(byte[] value) throws IOException { if (value != null) { return new ByteArrayHandle(value).readUTF(); } else { return null; } } private Short nullOrShort(byte[] value) { if (value != null) { return DataTools.bytesToShort(value, true); } else { return null; } } private Long nullOrLong(byte[] value) { if (value != null) { return DataTools.bytesToLong(value, true); } else { return null; } } private Float nullOrFloat(byte[] value) { if (value != null) { return DataTools.bytesToFloat(value, true); } else { return null; } } private void verifyRequiredEntries() throws JXRException { if (entries.isEmpty() || !entries.keySet().containsAll(IFDEntry.getRequiredEntries())) { throw new JXRException("Metadata object is missing required IFD entries."); } } }