blob: 1ce290d45e4b5c7e30cafb3cf3e9e4a9d38b0dc6 [file] [log] [blame] [edit]
/*
* Copyright (c) 2014-2021 by Wen Yu
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* or any later version.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
*
* Change History - most recent changes go on top of previous changes
*
* JFIF.java
*
* Who Date Description
* ==== ======= ============================================================
* WY 12Jul2015 Initial creation
*/
package pixy.meta.jpeg;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import android.graphics.Bitmap;
import pixy.meta.Metadata;
import pixy.meta.MetadataEntry;
import pixy.meta.MetadataType;
import pixy.io.IOUtils;
import pixy.util.ArrayUtils;
import pixy.util.MetadataUtils;
public class JFIF extends Metadata {
private static void checkInput(int majorVersion, int minorVersion, int densityUnit, int xDensity, int yDensity) {
if(majorVersion < 0 || majorVersion > 0xff) throw new IllegalArgumentException("Invalid major version number: " + majorVersion);
if(minorVersion < 0 || minorVersion > 0xff) throw new IllegalArgumentException("Invalid minor version number: " + minorVersion);
if(densityUnit < 0 || densityUnit > 2) throw new IllegalArgumentException("Density unit value " + densityUnit + " out of range [0-2]");
if(xDensity < 0 || xDensity > 0xffff) throw new IllegalArgumentException("xDensity value " + xDensity + " out of range (0-0xffff]");
if(yDensity < 0 || yDensity > 0xffff) throw new IllegalArgumentException("yDensity value " + xDensity + " out of range (0-0xffff]");
}
private int majorVersion;
private int minorVersion;
private int densityUnit;
private int xDensity;
private int yDensity;
private int thumbnailWidth;
private int thumbnailHeight;
private boolean containsThumbnail;
private JFIFThumbnail thumbnail;
public JFIF(byte[] data) {
super(MetadataType.JPG_JFIF, data);
ensureDataRead();
}
public JFIF(int majorVersion, int minorVersion, int densityUnit, int xDensity, int yDensity) {
this(majorVersion, minorVersion, densityUnit, xDensity, yDensity, null);
}
public JFIF(int majorVersion, int minorVersion, int densityUnit, int xDensity, int yDensity, JFIFThumbnail thumbnail) {
super(MetadataType.JPG_JFIF);
checkInput(majorVersion, minorVersion, densityUnit, xDensity, yDensity);
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
this.densityUnit = densityUnit;
this.xDensity = xDensity;
this.yDensity = yDensity;
if(thumbnail != null) {
int thumbnailWidth = thumbnail.getWidth();
int thumbnailHeight = thumbnail.getHeight();
if(thumbnailWidth < 0 || thumbnailWidth > 0xff)
throw new IllegalArgumentException("Thumbnail width " + thumbnailWidth + " out of range (0-0xff]");
if(thumbnailHeight < 0 || thumbnailHeight > 0xff)
throw new IllegalArgumentException("Thumbnail height " + thumbnailHeight + " out of range (0-0xff]");
this.thumbnailWidth = thumbnailWidth;
this.thumbnailHeight = thumbnailHeight;
this.thumbnail = thumbnail;
this.containsThumbnail = true;
}
isDataRead = true;
}
public boolean containsThumbnail() {
return containsThumbnail;
}
public int getDensityUnit() {
return densityUnit;
}
public int getMajorVersion() {
return majorVersion;
}
public int getMinorVersion() {
return minorVersion;
}
public JFIFThumbnail getThumbnail() {
return new JFIFThumbnail(thumbnail);
}
public int getThumbnailHeight() {
return thumbnailHeight;
}
public int getThumbnailWidth() {
return thumbnailWidth;
}
public int getXDensity() {
return xDensity;
}
public int getYDensity() {
return yDensity;
}
public Iterator<MetadataEntry> iterator() {
ensureDataRead();
List<MetadataEntry> entries = new ArrayList<MetadataEntry>();
String[] densityUnits = {"No units, aspect ratio only specified", "Dots per inch", "Dots per centimeter"};
entries.add(new MetadataEntry("Version", majorVersion + "." + minorVersion));
entries.add(new MetadataEntry("Density unit", (densityUnit <= 2)?densityUnits[densityUnit]:densityUnit + ""));
entries.add(new MetadataEntry("XDensity", xDensity + ""));
entries.add(new MetadataEntry("YDensity", yDensity + ""));
entries.add(new MetadataEntry("Thumbnail width", thumbnailWidth + ""));
entries.add(new MetadataEntry("Thumbnail height", thumbnailHeight + ""));
return Collections.unmodifiableCollection(entries).iterator();
}
public void read() throws IOException {
if(!isDataRead) {
int expectedLen = 9;
int offset = 0;
if (data.length >= expectedLen) {
majorVersion = data[offset++]&0xff;
minorVersion = data[offset++]&0xff;
densityUnit = data[offset++]&0xff;
xDensity = IOUtils.readUnsignedShortMM(data, offset);
offset += 2;
yDensity = IOUtils.readUnsignedShortMM(data, offset);
offset += 2;
thumbnailWidth = data[offset++]&0xff;
thumbnailHeight = data[offset]&0xff;
if(thumbnailWidth != 0 && thumbnailHeight != 0) {
containsThumbnail = true;
// Extract the thumbnail
//Create a Bitmap
int size = 3*thumbnailWidth*thumbnailHeight;
int[] colors = MetadataUtils.toARGB(ArrayUtils.subArray(data, expectedLen, size));
thumbnail = new JFIFThumbnail(Bitmap.createBitmap(colors, thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888));
}
}
isDataRead = true;
}
}
public void write(OutputStream os) throws IOException {
ensureDataRead();
IOUtils.write(os, majorVersion);
IOUtils.write(os, minorVersion);
IOUtils.write(os, densityUnit);
IOUtils.writeShortMM(os, getXDensity());
IOUtils.writeShortMM(os, getYDensity());
IOUtils.write(os, thumbnailWidth);
IOUtils.write(os, thumbnailHeight);
if(containsThumbnail)
thumbnail.write(os);
}
}