Compare commits

...

16 Commits

Author SHA1 Message Date
Harald Kuhr caaececa06 [maven-release-plugin] prepare for next development iteration 2015-08-14 12:11:07 +02:00
Harald Kuhr ffd4731334 [maven-release-plugin] prepare release twelvemonkeys-3.1.2 2015-08-14 12:11:00 +02:00
Harald Kuhr 7c53c5b7b5 TMI-154: Fix for AccessControlException when reading "Generic CMYK.icc" 2015-08-14 11:51:27 +02:00
Harald Kuhr c9cfe04dc9 TMI-JPEG: Reading inverted Adobe JPEGs 2015-07-14 20:50:53 +02:00
Harald Kuhr 9da25168ee TMI-150: Fix for 24 bit images with bitmask. 2015-07-11 13:20:04 +02:00
Harald Kuhr b0c928d278 TMI-146: Now correctly sets ExtraSamples only when there are more components in the raster than color components in the color space. 2015-06-17 13:26:45 +02:00
Harald Kuhr e221c7374b [maven-release-plugin] prepare for next development iteration 2015-06-11 11:53:40 +02:00
Harald Kuhr 258a6cf4f4 [maven-release-plugin] prepare release twelvemonkeys-3.1.1 2015-06-11 11:53:35 +02:00
Harald Kuhr ab5cbb15ed TMI-142: Added missing resource file, now making sure the TIFFImageWriter is registered. 2015-06-08 15:37:20 +02:00
Harald Kuhr 02d65481c5 TMI-140: JPEG with corrupted ICC profile (new kind) can now be read. 2015-06-08 15:35:27 +02:00
Harald Kuhr 081c65b314 Preparing JPEGImageReader for extension. 2015-06-08 15:35:10 +02:00
Harald Kuhr 7a78d398c3 Fixed JavaDoc (you're welcome Sigi ;-)). 2015-06-08 15:31:55 +02:00
Harald Kuhr 493c304722 TM-138: DateUtil doesn't support sub-hour offset timezones. 2015-06-08 15:31:22 +02:00
Harald Kuhr 8d62d74860 TM-138: DateUtil doesn't support sub-hour offset timezones. 2015-06-08 15:31:06 +02:00
Harald Kuhr d51ac8cb83 TMI-134: Cannot read PSD images with PSD Layer Mask data size 28 2015-06-08 15:30:19 +02:00
Harald Kuhr 646ac719c1 Updating POM to version 3.1.1-SNAPSHOT 2015-06-08 14:18:49 +02:00
45 changed files with 531 additions and 201 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<groupId>com.twelvemonkeys.bom</groupId> <groupId>com.twelvemonkeys.bom</groupId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-image</artifactId> <artifactId>common-image</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-io</artifactId> <artifactId>common-io</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-lang</artifactId> <artifactId>common-lang</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@@ -142,7 +142,7 @@ public final class DateUtil {
* @param pTime time * @param pTime time
* @return the time rounded to the closest second. * @return the time rounded to the closest second.
*/ */
public static long roundToSecond(long pTime) { public static long roundToSecond(final long pTime) {
return (pTime / SECOND) * SECOND; return (pTime / SECOND) * SECOND;
} }
@@ -152,7 +152,7 @@ public final class DateUtil {
* @param pTime time * @param pTime time
* @return the time rounded to the closest minute. * @return the time rounded to the closest minute.
*/ */
public static long roundToMinute(long pTime) { public static long roundToMinute(final long pTime) {
return (pTime / MINUTE) * MINUTE; return (pTime / MINUTE) * MINUTE;
} }
@@ -162,9 +162,20 @@ public final class DateUtil {
* @param pTime time * @param pTime time
* @return the time rounded to the closest hour. * @return the time rounded to the closest hour.
*/ */
public static long roundToHour(long pTime) { public static long roundToHour(final long pTime) {
// TODO: What if timezone offset is sub hour? Are there any? I think so... return roundToHour(pTime, TimeZone.getDefault());
return ((pTime / HOUR) * HOUR); }
/**
* Rounds the given time down to the closest hour, using the given timezone.
*
* @param pTime time
* @param pTimeZone the timezone to use when rounding
* @return the time rounded to the closest hour.
*/
public static long roundToHour(final long pTime, final TimeZone pTimeZone) {
int offset = pTimeZone.getOffset(pTime);
return ((pTime / HOUR) * HOUR) - offset;
} }
/** /**
@@ -173,7 +184,7 @@ public final class DateUtil {
* @param pTime time * @param pTime time
* @return the time rounded to the closest day. * @return the time rounded to the closest day.
*/ */
public static long roundToDay(long pTime) { public static long roundToDay(final long pTime) {
return roundToDay(pTime, TimeZone.getDefault()); return roundToDay(pTime, TimeZone.getDefault());
} }
@@ -184,7 +195,7 @@ public final class DateUtil {
* @param pTimeZone the timezone to use when rounding * @param pTimeZone the timezone to use when rounding
* @return the time rounded to the closest day. * @return the time rounded to the closest day.
*/ */
public static long roundToDay(long pTime, TimeZone pTimeZone) { public static long roundToDay(final long pTime, final TimeZone pTimeZone) {
int offset = pTimeZone.getOffset(pTime); int offset = pTimeZone.getOffset(pTime);
return (((pTime + offset) / DAY) * DAY) - offset; return (((pTime + offset) / DAY) * DAY) - offset;
} }
@@ -29,11 +29,15 @@
package com.twelvemonkeys.lang; package com.twelvemonkeys.lang;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
/** /**
* DateUtilTest * DateUtilTest
@@ -42,9 +46,30 @@ import static org.junit.Assert.*;
* @author last modified by $Author: haraldk$ * @author last modified by $Author: haraldk$
* @version $Id: DateUtilTest.java,v 1.0 11.04.12 16:21 haraldk Exp$ * @version $Id: DateUtilTest.java,v 1.0 11.04.12 16:21 haraldk Exp$
*/ */
@RunWith(Parameterized.class)
public class DateUtilTest { public class DateUtilTest {
private static Calendar getCalendar(long time) {
Calendar calendar = Calendar.getInstance(TimeZone.getDefault()); private final TimeZone timeZone;
@Parameterized.Parameters
public static List<Object[]> timeZones() {
return Arrays.asList(new Object[][] {
{TimeZone.getTimeZone("UTC")},
{TimeZone.getTimeZone("CET")},
{TimeZone.getTimeZone("IST")}, // 30 min off
});
}
public DateUtilTest(final TimeZone timeZone) {
this.timeZone = timeZone;
}
private Calendar getCalendar(long time) {
return getCalendar(time, TimeZone.getDefault());
}
private Calendar getCalendar(long time, final TimeZone timeZone) {
Calendar calendar = Calendar.getInstance(timeZone);
calendar.setTimeInMillis(time); calendar.setTimeInMillis(time);
return calendar; return calendar;
@@ -74,6 +99,15 @@ public class DateUtilTest {
assertEquals(0, calendar.get(Calendar.MINUTE)); assertEquals(0, calendar.get(Calendar.MINUTE));
} }
@Test
public void testRoundToHourTZ() {
Calendar calendar = getCalendar(DateUtil.roundToHour(System.currentTimeMillis(), timeZone), timeZone);
assertEquals(0, calendar.get(Calendar.MILLISECOND));
assertEquals(0, calendar.get(Calendar.SECOND));
assertEquals(0, calendar.get(Calendar.MINUTE));
}
@Test @Test
public void testRoundToDay() { public void testRoundToDay() {
Calendar calendar = getCalendar(DateUtil.roundToDay(System.currentTimeMillis())); Calendar calendar = getCalendar(DateUtil.roundToDay(System.currentTimeMillis()));
@@ -84,6 +118,16 @@ public class DateUtilTest {
assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY)); assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY));
} }
@Test
public void testRoundToDayTZ() {
Calendar calendar = getCalendar(DateUtil.roundToDay(System.currentTimeMillis(), timeZone), timeZone);
assertEquals(0, calendar.get(Calendar.MILLISECOND));
assertEquals(0, calendar.get(Calendar.SECOND));
assertEquals(0, calendar.get(Calendar.MINUTE));
assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY));
}
@Test @Test
public void testCurrentTimeSecond() { public void testCurrentTimeSecond() {
Calendar calendar = getCalendar(DateUtil.currentTimeSecond()); Calendar calendar = getCalendar(DateUtil.currentTimeSecond());
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-batik</artifactId> <artifactId>imageio-batik</artifactId>
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name> <name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-bmp</artifactId> <artifactId>imageio-bmp</artifactId>
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name> <name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
@@ -43,6 +43,7 @@ abstract class BitmapDescriptor {
protected final DIBHeader header; protected final DIBHeader header;
protected BufferedImage image; protected BufferedImage image;
protected BitmapMask mask;
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) { public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
Validate.notNull(pEntry, "entry"); Validate.notNull(pEntry, "entry");
@@ -69,4 +70,17 @@ abstract class BitmapDescriptor {
protected final int getBitCount() { protected final int getBitCount() {
return entry.getBitCount() != 0 ? entry.getBitCount() : header.getBitCount(); return entry.getBitCount() != 0 ? entry.getBitCount() : header.getBitCount();
} }
@Override
public String toString() {
return getClass().getSimpleName() + "[" + entry + ", " + header + "]";
}
public final void setMask(final BitmapMask mask) {
this.mask = mask;
}
public final boolean hasMask() {
return header.getHeight() == getHeight() * 2;
}
} }
@@ -28,8 +28,6 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.image.InverseColorMapIndexColorModel;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer; import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel; import java.awt.image.IndexColorModel;
@@ -46,8 +44,6 @@ class BitmapIndexed extends BitmapDescriptor {
protected final int[] bits; protected final int[] bits;
protected final int[] colors; protected final int[] colors;
private BitmapMask mask;
public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) { public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) {
super(pEntry, pHeader); super(pEntry, pHeader);
bits = new int[getWidth() * getHeight()]; bits = new int[getWidth() * getHeight()];
@@ -65,7 +61,7 @@ class BitmapIndexed extends BitmapDescriptor {
// This is slightly obscure, and should probably be moved.. // This is slightly obscure, and should probably be moved..
Hashtable<String, Object> properties = null; Hashtable<String, Object> properties = null;
if (entry instanceof DirectoryEntry.CUREntry) { if (entry instanceof DirectoryEntry.CUREntry) {
properties = new Hashtable<String, Object>(1); properties = new Hashtable<>(1);
properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot()); properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot());
} }
@@ -89,8 +85,6 @@ class BitmapIndexed extends BitmapDescriptor {
raster.setSamples(0, 0, getWidth(), getHeight(), 0, bits); raster.setSamples(0, 0, getWidth(), getHeight(), 0, bits);
//System.out.println("Image: " + image);
return image; return image;
} }
@@ -100,40 +94,40 @@ class BitmapIndexed extends BitmapDescriptor {
IndexColorModel createColorModel() { IndexColorModel createColorModel() {
// NOTE: This is a hack to make room for transparent pixel for mask // NOTE: This is a hack to make room for transparent pixel for mask
int bits = getBitCount(); int bits = getBitCount();
int colors = this.colors.length; int colors = this.colors.length;
int trans = -1; int transparent = -1;
// Try to avoid USHORT transfertype, as it results in BufferedImage TYPE_CUSTOM // Try to avoid USHORT transfertype, as it results in BufferedImage TYPE_CUSTOM
// NOTE: This code assumes icons are small, and is NOT optimized for performance... // NOTE: This code assumes icons are small, and is NOT optimized for performance...
if (colors > (1 << getBitCount())) { if (colors > (1 << getBitCount())) {
int index = findTransIndexMaybeRemap(this.colors, this.bits); int index = findTransparentIndexMaybeRemap(this.colors, this.bits);
if (index == -1) { if (index == -1) {
// No duplicate found, increase bitcount // No duplicate found, increase bitcount
bits++; bits++;
trans = this.colors.length - 1; transparent = this.colors.length - 1;
} }
else { else {
// Found a duplicate, use it as trans // Found a duplicate, use it as transparent
trans = index; transparent = index;
colors--; colors--;
} }
} }
// NOTE: Setting hasAlpha to true, makes things work on 1.2 // NOTE: Setting hasAlpha to true, makes things work on 1.2
return new InverseColorMapIndexColorModel( return new IndexColorModel(
bits, colors, this.colors, 0, true, trans, bits, colors, this.colors, 0, true, transparent,
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT
); );
} }
private static int findTransIndexMaybeRemap(final int[] pColors, final int[] pBits) { private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) {
// Look for unused colors, to use as transparent // Look for unused colors, to use as transparent
final boolean[] used = new boolean[pColors.length - 1]; boolean[] used = new boolean[colors.length - 1];
for (int pBit : pBits) { for (int bit : bits) {
if (!used[pBit]) { if (!used[bit]) {
used[pBit] = true; used[bit] = true;
} }
} }
@@ -144,38 +138,35 @@ class BitmapIndexed extends BitmapDescriptor {
} }
// Try to find duplicates in colormap, and remap // Try to find duplicates in colormap, and remap
int trans = -1; int transparent = -1;
int duplicate = -1; int duplicate = -1;
for (int i = 0; trans == -1 && i < pColors.length - 1; i++) { for (int i = 0; transparent == -1 && i < colors.length - 1; i++) {
for (int j = i + 1; j < pColors.length - 1; j++) { for (int j = i + 1; j < colors.length - 1; j++) {
if (pColors[i] == pColors[j]) { if (colors[i] == colors[j]) {
trans = j; transparent = j;
duplicate = i; duplicate = i;
break; break;
} }
} }
} }
if (trans != -1) { if (transparent != -1) {
// Remap duplicate // Remap duplicate
for (int i = 0; i < pBits.length; i++) { for (int i = 0; i < bits.length; i++) {
if (pBits[i] == trans) { if (bits[i] == transparent) {
pBits[i] = duplicate; bits[i] = duplicate;
} }
} }
} }
return trans; return transparent;
} }
public BufferedImage getImage() { public BufferedImage getImage() {
if (image == null) { if (image == null) {
image = createImageIndexed(); image = createImageIndexed();
} }
return image; return image;
} }
public void setMask(final BitmapMask pMask) {
mask = pMask;
}
} }
@@ -38,19 +38,19 @@ import java.awt.image.BufferedImage;
* @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$ * @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
*/ */
class BitmapMask extends BitmapDescriptor { class BitmapMask extends BitmapDescriptor {
protected final BitmapIndexed mask; protected final BitmapIndexed bitMask;
public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) { public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) {
super(pParent, pHeader); super(pParent, pHeader);
mask = new BitmapIndexed(pParent, pHeader); bitMask = new BitmapIndexed(pParent, pHeader);
} }
boolean isTransparent(final int pX, final int pY) { boolean isTransparent(final int pX, final int pY) {
// NOTE: 1: Fully transparent, 0: Opaque... // NOTE: 1: Fully transparent, 0: Opaque...
return mask.bits[pX + pY * getWidth()] != 0; return bitMask.bits[pX + pY * getWidth()] != 0;
} }
public BufferedImage getImage() { public BufferedImage getImage() {
return mask.getImage(); return bitMask.getImage();
} }
} }
@@ -28,7 +28,9 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
/** /**
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel). * Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
@@ -43,6 +45,38 @@ class BitmapRGB extends BitmapDescriptor {
} }
public BufferedImage getImage() { public BufferedImage getImage() {
// Test is mask != null rather than hasMask(), as 32 bit (w/alpha)
// might still have bitmask, but we don't read or use it.
if (mask != null) {
image = createMaskedImage();
mask = null;
}
return image; return image;
} }
private BufferedImage createMaskedImage() {
BufferedImage masked = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = masked.createGraphics();
try {
graphics.drawImage(image, 0, 0, null);
}
finally {
graphics.dispose();
}
WritableRaster alphaRaster = masked.getAlphaRaster();
byte[] trans = {0x0};
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
if (mask.isTransparent(x, y)) {
alphaRaster.setDataElements(x, y, trans);
}
}
}
return masked;
}
} }
@@ -66,14 +66,15 @@ import java.util.List;
// TODO: Decide whether DirectoryEntry or DIBHeader should be primary source for color count/bit count // TODO: Decide whether DirectoryEntry or DIBHeader should be primary source for color count/bit count
// TODO: Support loading icons from DLLs, see // TODO: Support loading icons from DLLs, see
// <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp">MSDN</a> // <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp">MSDN</a>
// Known issue: 256x256 PNG encoded icons does not have IndexColorModel even if stated in DirectoryEntry (seem impossible as the PNGs are all true color) // Known issue: 256x256 PNG encoded icons does not have IndexColorModel even if stated in DirectoryEntry
// (seem impossible as the PNGs are all true color)
abstract class DIBImageReader extends ImageReaderBase { abstract class DIBImageReader extends ImageReaderBase {
// TODO: Consider moving the reading to inner classes (subclasses of BitmapDescriptor) // TODO: Consider moving the reading to inner classes (subclasses of BitmapDescriptor)
private Directory directory; private Directory directory;
// TODO: Review these, make sure we don't have a memory leak // TODO: Review these, make sure we don't have a memory leak
private Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<DirectoryEntry, DIBHeader>(); private Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
private Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<DirectoryEntry, BitmapDescriptor>(); private Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
private ImageReader pngImageReader; private ImageReader pngImageReader;
@@ -101,7 +102,7 @@ abstract class DIBImageReader extends ImageReaderBase {
return getImageTypesPNG(entry); return getImageTypesPNG(entry);
} }
List<ImageTypeSpecifier> types = new ArrayList<ImageTypeSpecifier>(); List<ImageTypeSpecifier> types = new ArrayList<>();
DIBHeader header = getHeader(entry); DIBHeader header = getHeader(entry);
// Use data from header to create specifier // Use data from header to create specifier
@@ -121,10 +122,13 @@ abstract class DIBImageReader extends ImageReaderBase {
specifier = ImageTypeSpecifiers.createFromIndexColorModel(indexed.createColorModel()); specifier = ImageTypeSpecifiers.createFromIndexColorModel(indexed.createColorModel());
break; break;
case 16: case 16:
// TODO: May have mask?!
specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB); specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB);
break; break;
case 24: case 24:
specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); specifier = new BitmapRGB(entry, header).hasMask()
? ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR)
: ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
break; break;
case 32: case 32:
specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB);
@@ -184,6 +188,7 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
else { else {
Graphics2D g = destination.createGraphics(); Graphics2D g = destination.createGraphics();
try { try {
g.setComposite(AlphaComposite.Src); g.setComposite(AlphaComposite.Src);
g.drawImage(image, 0, 0, null); g.drawImage(image, 0, 0, null);
@@ -316,6 +321,8 @@ abstract class DIBImageReader extends ImageReaderBase {
descriptors.put(pEntry, descriptor); descriptors.put(pEntry, descriptor);
} }
System.err.println("descriptor: " + descriptor);
return descriptor.getImage(); return descriptor.getImage();
} }
@@ -335,7 +342,7 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header); BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
readBitmapIndexed1(mask.mask, true); readBitmapIndexed1(mask.bitMask, true);
pBitmap.setMask(mask); pBitmap.setMask(mask);
} }
@@ -370,7 +377,7 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
} }
// NOTE: If we are reading the mask, we don't abort or progress // NOTE: If we are reading the mask, we don't abort or report progress
if (!pAsMask) { if (!pAsMask) {
if (abortRequested()) { if (abortRequested()) {
processReadAborted(); processReadAborted();
@@ -455,7 +462,7 @@ abstract class DIBImageReader extends ImageReaderBase {
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()]; short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts // TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
// Will create TYPE_USHORT_555; // Will create TYPE_USHORT_555
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F); DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
DataBuffer buffer = new DataBufferShort(pixels, pixels.length); DataBuffer buffer = new DataBufferShort(pixels, pixels.length);
WritableRaster raster = Raster.createPackedRaster( WritableRaster raster = Raster.createPackedRaster(
@@ -480,6 +487,8 @@ abstract class DIBImageReader extends ImageReaderBase {
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) pBitmap.getHeight());
} }
// TODO: Might be mask!?
} }
private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException { private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException {
@@ -494,16 +503,19 @@ abstract class DIBImageReader extends ImageReaderBase {
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
); );
int scanlineStride = pBitmap.getWidth() * 3;
// BMP rows are padded to 4 byte boundary
int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4;
WritableRaster raster = Raster.createInterleavedRaster( WritableRaster raster = Raster.createInterleavedRaster(
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), 3, bOffs, null buffer, pBitmap.getWidth(), pBitmap.getHeight(), scanlineStride, 3, bOffs, null
); );
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
for (int y = 0; y < pBitmap.getHeight(); y++) {
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
imageInput.readFully(pixels, offset, pBitmap.getWidth() * 3);
// TODO: Possibly read padding byte here! for (int y = 0; y < pBitmap.getHeight(); y++) {
int offset = (pBitmap.getHeight() - y - 1) * scanlineStride;
imageInput.readFully(pixels, offset, scanlineStride);
imageInput.skipBytes(rowSizeBytes - scanlineStride);
if (abortRequested()) { if (abortRequested()) {
processReadAborted(); processReadAborted();
@@ -512,6 +524,14 @@ abstract class DIBImageReader extends ImageReaderBase {
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) pBitmap.getHeight());
} }
// 24 bit icons usually have a bit mask
if (pBitmap.hasMask()) {
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
readBitmapIndexed1(mask.bitMask, true);
pBitmap.setMask(mask);
}
} }
private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException { private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException {
@@ -535,6 +555,9 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) pBitmap.getHeight());
} }
// There might be a mask here as well, but we'll ignore it,
// and use the 8 bit alpha channel in the ARGB pixel data
} }
private Directory getDirectory() throws IOException { private Directory getDirectory() throws IOException {
@@ -39,7 +39,9 @@ public class ICOImageReaderTest extends ImageReaderAbstractTest<ICOImageReader>
new Dimension(16, 16), new Dimension(16, 16), new Dimension(32, 32), new Dimension(32, 32), new Dimension(16, 16), new Dimension(16, 16), new Dimension(32, 32), new Dimension(32, 32),
new Dimension(48, 48), new Dimension(48, 48), new Dimension(256, 256), new Dimension(256, 256), new Dimension(48, 48), new Dimension(48, 48), new Dimension(256, 256), new Dimension(256, 256),
new Dimension(16, 16), new Dimension(32, 32), new Dimension(48, 48), new Dimension(256, 256) new Dimension(16, 16), new Dimension(32, 32), new Dimension(48, 48), new Dimension(256, 256)
) ),
// Problematic icon that reports 24 bit in the descriptor, but has separate 1 bit ''mask (height 2 x icon height)!
new TestData(getClassLoaderResource("/ico/rgb24bitmask.ico"), new Dimension(32, 32))
); );
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-clippath</artifactId> <artifactId>imageio-clippath</artifactId>
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name> <name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-core</artifactId> <artifactId>imageio-core</artifactId>
<name>TwelveMonkeys :: ImageIO :: Core</name> <name>TwelveMonkeys :: ImageIO :: Core</name>
@@ -52,7 +52,7 @@ import java.util.Properties;
* <p /> * <p />
* Color profiles may be configured by placing a property-file * Color profiles may be configured by placing a property-file
* {@code com/twelvemonkeys/imageio/color/icc_profiles.properties} * {@code com/twelvemonkeys/imageio/color/icc_profiles.properties}
* on the classpath, specifying the full path to the profile. * on the classpath, specifying the full path to the profiles.
* ICC color profiles are probably already present on your system, or * ICC color profiles are probably already present on your system, or
* can be downloaded from * can be downloaded from
* <a href="http://www.color.org/profiles2.xalter">ICC</a>, * <a href="http://www.color.org/profiles2.xalter">ICC</a>,
@@ -161,6 +161,11 @@ public final class ColorSpaces {
if (cs == null) { if (cs == null) {
cs = new ICC_ColorSpace(profile); cs = new ICC_ColorSpace(profile);
// Validate the color space, to avoid caching bad color spaces
// Will throw IllegalArgumentException or CMMException if the profile is bad
cs.fromRGB(new float[] {1f, 0f, 0f});
cache.put(key, cs); cache.put(key, cs);
} }
@@ -195,7 +200,7 @@ public final class ColorSpaces {
* @return {@code true} if known to be offending, {@code false} otherwise * @return {@code true} if known to be offending, {@code false} otherwise
* @throws IllegalArgumentException if {@code profile} is {@code null} * @throws IllegalArgumentException if {@code profile} is {@code null}
*/ */
public static boolean isOffendingColorProfile(final ICC_Profile profile) { static boolean isOffendingColorProfile(final ICC_Profile profile) {
Validate.notNull(profile, "profile"); Validate.notNull(profile, "profile");
// NOTE: // NOTE:
@@ -213,6 +218,26 @@ public final class ColorSpaces {
return data[ICC_Profile.icHdrRenderingIntent] != 0; return data[ICC_Profile.icHdrRenderingIntent] != 0;
} }
/**
* Tests whether an ICC color profile is valid.
* Invalid profiles are known to cause problems for {@link java.awt.image.ColorConvertOp}.
* <p />
* <em>
* Note that this method only tests if a color conversion using this profile is known to fail.
* There's no guarantee that the color conversion will succeed even if this method returns {@code false}.
* </em>
*
* @param profile the ICC color profile. May not be {@code null}.
* @return {@code profile} if valid.
* @throws IllegalArgumentException if {@code profile} is {@code null}
* @throws java.awt.color.CMMException if {@code profile} is invalid.
*/
public static ICC_Profile validateProfile(final ICC_Profile profile) {
createColorSpace(profile); // Creating a color space will fail if the profile is bad
return profile;
}
/** /**
* Returns the color space specified by the given color space constant. * Returns the color space specified by the given color space constant.
* <p /> * <p />
@@ -317,7 +342,7 @@ public final class ColorSpaces {
try { try {
return ICC_Profile.getInstance(profilePath); return ICC_Profile.getInstance(profilePath);
} }
catch (IOException ignore) { catch (SecurityException | IOException ignore) {
if (DEBUG) { if (DEBUG) {
ignore.printStackTrace(); ignore.printStackTrace();
} }
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-icns</artifactId> <artifactId>imageio-icns</artifactId>
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name> <name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-iff</artifactId> <artifactId>imageio-iff</artifactId>
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name> <name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-jpeg</artifactId> <artifactId>imageio-jpeg</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name> <name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
@@ -28,7 +28,6 @@
package com.twelvemonkeys.imageio.plugins.jpeg; package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase; import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.color.ColorSpaces; import com.twelvemonkeys.imageio.color.ColorSpaces;
import com.twelvemonkeys.imageio.metadata.CompoundDirectory; import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
@@ -152,10 +151,10 @@ public class JPEGImageReader extends ImageReaderBase {
/** Cached list of JPEG segments we filter from the underlying stream */ /** Cached list of JPEG segments we filter from the underlying stream */
private List<JPEGSegment> segments; private List<JPEGSegment> segments;
JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) { protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
super(provider); super(provider);
this.delegate = Validate.notNull(delegate);
this.delegate = Validate.notNull(delegate);
progressDelegator = new ProgressDelegator(); progressDelegator = new ProgressDelegator();
} }
@@ -298,7 +297,9 @@ public class JPEGImageReader extends ImageReaderBase {
super.setInput(input, seekForwardOnly, ignoreMetadata); super.setInput(input, seekForwardOnly, ignoreMetadata);
// JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments // JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments
delegate.setInput(imageInput != null ? new JPEGSegmentImageInputStream(imageInput) : null, seekForwardOnly, ignoreMetadata); delegate.setInput(imageInput != null
? new JPEGSegmentImageInputStream(imageInput)
: null, seekForwardOnly, ignoreMetadata);
} }
@Override @Override
@@ -408,6 +409,7 @@ public class JPEGImageReader extends ImageReaderBase {
if (DEBUG) { if (DEBUG) {
System.err.println("Converting from " + intendedCS + " to " + (image.getColorModel().getColorSpace().isCS_sRGB() ? "sRGB" : image.getColorModel().getColorSpace())); System.err.println("Converting from " + intendedCS + " to " + (image.getColorModel().getColorSpace().isCS_sRGB() ? "sRGB" : image.getColorModel().getColorSpace()));
} }
convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null); convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
} }
// Else, pass through with no conversion // Else, pass through with no conversion
@@ -469,12 +471,11 @@ public class JPEGImageReader extends ImageReaderBase {
YCbCrConverter.convertYCbCr2RGB(raster); YCbCrConverter.convertYCbCr2RGB(raster);
} }
else if (csType == JPEGColorSpace.YCCK) { else if (csType == JPEGColorSpace.YCCK) {
YCbCrConverter.convertYCCK2CMYK(raster); // TODO: Need to rethink this (non-) inversion, see #147
// TODO: Allow param to specify inversion, or possibly the PDF decode array
// flag0 bit 15, blend = 1 see http://graphicdesign.stackexchange.com/questions/12894/cmyk-jpegs-extracted-from-pdf-appear-inverted // flag0 bit 15, blend = 1 see http://graphicdesign.stackexchange.com/questions/12894/cmyk-jpegs-extracted-from-pdf-appear-inverted
if ((getAdobeDCT().flags0 & 0x8000) != 0) { boolean invert = true;// || (adobeDCT.flags0 & 0x8000) == 0;
/// TODO: Better yet would be to not inverting in the first place, add flag to convertYCCK2CMYK YCbCrConverter.convertYCCK2CMYK(raster, invert);
invertCMYK(raster);
}
} }
else if (csType == JPEGColorSpace.CMYK) { else if (csType == JPEGColorSpace.CMYK) {
invertCMYK(raster); invertCMYK(raster);
@@ -629,7 +630,7 @@ public class JPEGImageReader extends ImageReaderBase {
} }
} }
private ICC_Profile ensureDisplayProfile(final ICC_Profile profile) { protected ICC_Profile ensureDisplayProfile(final ICC_Profile profile) {
// NOTE: This is probably not the right way to do it... :-P // NOTE: This is probably not the right way to do it... :-P
// TODO: Consider moving method to ColorSpaces class or new class in imageio.color package // TODO: Consider moving method to ColorSpaces class or new class in imageio.color package
@@ -835,7 +836,7 @@ public class JPEGImageReader extends ImageReaderBase {
return data; return data;
} }
ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException { protected ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException {
// ICC v 1.42 (2006) annex B: // ICC v 1.42 (2006) annex B:
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination) // APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
// + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments) // + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments)
@@ -857,7 +858,7 @@ public class JPEGImageReader extends ImageReaderBase {
return null; return null;
} }
return readICCProfileSafe(stream); return readICCProfileSafe(stream, allowBadIndexes);
} }
else if (!segments.isEmpty()) { else if (!segments.isEmpty()) {
// NOTE: This is probably over-complicated, as I've never encountered ICC_PROFILE chunks out of order... // NOTE: This is probably over-complicated, as I've never encountered ICC_PROFILE chunks out of order...
@@ -904,15 +905,17 @@ public class JPEGImageReader extends ImageReaderBase {
streams[badICC ? i : chunkNumber - 1] = stream; streams[badICC ? i : chunkNumber - 1] = stream;
} }
return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams)))); return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams))), allowBadIndexes);
} }
return null; return null;
} }
private ICC_Profile readICCProfileSafe(final InputStream stream) throws IOException { private ICC_Profile readICCProfileSafe(final InputStream stream, final boolean allowBadProfile) throws IOException {
try { try {
return ICC_Profile.getInstance(stream); ICC_Profile profile = ICC_Profile.getInstance(stream);
return allowBadProfile ? profile : ColorSpaces.validateProfile(profile);
} }
catch (RuntimeException e) { catch (RuntimeException e) {
// NOTE: Throws either IllegalArgumentException or CMMException, depending on platform. // NOTE: Throws either IllegalArgumentException or CMMException, depending on platform.
@@ -944,6 +947,11 @@ public class JPEGImageReader extends ImageReaderBase {
delegate.abort(); delegate.abort();
} }
@Override
public ImageReadParam getDefaultReadParam() {
return delegate.getDefaultReadParam();
}
@Override @Override
public boolean readerSupportsThumbnails() { public boolean readerSupportsThumbnails() {
return true; // We support EXIF, JFIF and JFXX style thumbnails return true; // We support EXIF, JFIF and JFXX style thumbnails
@@ -1172,19 +1180,28 @@ public class JPEGImageReader extends ImageReaderBase {
rgb[offset + 2] = clamp(y + Cb_B_LUT[cb]); rgb[offset + 2] = clamp(y + Cb_B_LUT[cb]);
} }
static void convertYCCK2CMYK(final Raster raster) { static void convertYCCK2CMYK(final Raster raster, final boolean invert) {
final int height = raster.getHeight(); final int height = raster.getHeight();
final int width = raster.getWidth(); final int width = raster.getWidth();
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData(); final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
for (int y = 0; y < height; y++) { if (invert) {
for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) {
convertYCCK2CMYK(data, data, (x + y * width) * 4); for (int x = 0; x < width; x++) {
convertYCCK2CMYKInverted(data, data, (x + y * width) * 4);
}
}
}
else {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
convertYCCK2CMYK(data, data, (x + y * width) * 4);
}
} }
} }
} }
private static void convertYCCK2CMYK(byte[] ycck, byte[] cmyk, int offset) { private static void convertYCCK2CMYKInverted(byte[] ycck, byte[] cmyk, int offset) {
// Inverted // Inverted
int y = 255 - ycck[offset ] & 0xff; int y = 255 - ycck[offset ] & 0xff;
int cb = 255 - ycck[offset + 1] & 0xff; int cb = 255 - ycck[offset + 1] & 0xff;
@@ -1201,6 +1218,22 @@ public class JPEGImageReader extends ImageReaderBase {
cmyk[offset + 3] = (byte) k; // K passes through unchanged cmyk[offset + 3] = (byte) k; // K passes through unchanged
} }
private static void convertYCCK2CMYK(byte[] ycck, byte[] cmyk, int offset) {
int y = ycck[offset ] & 0xff;
int cb = ycck[offset + 1] & 0xff;
int cr = ycck[offset + 2] & 0xff;
int k = ycck[offset + 3] & 0xff;
int cmykC = MAXJSAMPLE - (y + Cr_R_LUT[cr]);
int cmykM = MAXJSAMPLE - (y + (Cb_G_LUT[cb] + Cr_G_LUT[cr] >> SCALEBITS));
int cmykY = MAXJSAMPLE - (y + Cb_B_LUT[cb]);
cmyk[offset ] = clamp(cmykC);
cmyk[offset + 1] = clamp(cmykM);
cmyk[offset + 2] = clamp(cmykY);
cmyk[offset + 3] = (byte) k; // K passes through unchanged
}
private static byte clamp(int val) { private static byte clamp(int val) {
return (byte) Math.max(0, Math.min(255, val)); return (byte) Math.max(0, Math.min(255, val));
} }
@@ -1301,7 +1334,68 @@ public class JPEGImageReader extends ImageReaderBase {
} }
public static void main(final String[] args) throws IOException { public static void main(final String[] args) throws IOException {
for (final String arg : args) { ImageIO.setUseCache(false);
int subX = 1;
int subY = 1;
int xOff = 0;
int yOff = 0;
Rectangle roi = null;
boolean metadata = false;
boolean thumbnails = false;
for (int argIdx = 0; argIdx < args.length; argIdx++) {
final String arg = args[argIdx];
if (arg.charAt(0) == '-') {
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx) {
String[] sub = args[++argIdx].split(",");
try {
if (sub.length >= 4) {
subX = Integer.parseInt(sub[0]);
subY = Integer.parseInt(sub[1]);
xOff = Integer.parseInt(sub[2]);
yOff = Integer.parseInt(sub[3]);
}
else {
subX = Integer.parseInt(sub[0]);
subY = sub.length > 1 ? Integer.parseInt(sub[1]) : subX;
}
}
catch (NumberFormatException e) {
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
}
}
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx) {
String[] region = args[++argIdx].split(",");
try {
if (region.length >= 4) {
roi = new Rectangle(Integer.parseInt(region[0]), Integer.parseInt(region[2]), Integer.parseInt(region[2]), Integer.parseInt(region[3]));
}
else {
roi = new Rectangle(Integer.parseInt(region[0]), Integer.parseInt(region[2]));
}
}
catch (IndexOutOfBoundsException | NumberFormatException e) {
System.err.println("Bad source region ([x,y,]w, h): '" + args[argIdx] + "'");
}
}
else if (arg.equals("-m") || arg.equals("--metadata")) {
metadata = true;
}
else if (arg.equals("-t") || arg.equals("--thumbnails")) {
thumbnails = true;
}
else {
System.err.println("Unknown argument: '" + arg + "'");
System.exit(-1);
}
continue;
}
File file = new File(arg); File file = new File(arg);
ImageInputStream input = ImageIO.createImageInputStream(file); ImageInputStream input = ImageIO.createImageInputStream(file);
@@ -1317,15 +1411,15 @@ public class JPEGImageReader extends ImageReaderBase {
continue; continue;
} }
ImageReader reader = readers.next(); final ImageReader reader = readers.next();
// System.err.println("Reading using: " + reader); System.err.println("Reading using: " + reader);
reader.addIIOReadWarningListener(new IIOReadWarningListener() { reader.addIIOReadWarningListener(new IIOReadWarningListener() {
public void warningOccurred(ImageReader source, String warning) { public void warningOccurred(ImageReader source, String warning) {
System.err.println("Warning: " + arg + ": " + warning); System.err.println("Warning: " + arg + ": " + warning);
} }
}); });
reader.addIIOReadProgressListener(new ProgressListenerBase() { final ProgressListenerBase listener = new ProgressListenerBase() {
private static final int MAX_W = 78; private static final int MAX_W = 78;
int lastProgress = 0; int lastProgress = 0;
@@ -1354,29 +1448,35 @@ public class JPEGImageReader extends ImageReaderBase {
System.out.println("]"); System.out.println("]");
} }
}); };
reader.addIIOReadProgressListener(listener);
reader.setInput(input); reader.setInput(input);
// For a tables-only image, we can't read image, but we should get metadata.
if (reader.getNumImages(true) == 0) {
IIOMetadata streamMetadata = reader.getStreamMetadata();
IIOMetadataNode streamNativeTree = (IIOMetadataNode) streamMetadata.getAsTree(streamMetadata.getNativeMetadataFormatName());
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(streamNativeTree, false);
continue;
}
try { try {
// For a tables-only image, we can't read image, but we should get metadata.
if (reader.getNumImages(true) == 0) {
IIOMetadata streamMetadata = reader.getStreamMetadata();
IIOMetadataNode streamNativeTree = (IIOMetadataNode) streamMetadata.getAsTree(streamMetadata.getNativeMetadataFormatName());
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(streamNativeTree, false);
continue;
}
BufferedImage image;
ImageReadParam param = reader.getDefaultReadParam(); ImageReadParam param = reader.getDefaultReadParam();
// if (args.length > 1) { if (subX > 1 || subY > 1 || roi != null) {
// int sub = Integer.parseInt(args[1]); param.setSourceSubsampling(subX, subY, xOff, yOff);
// int sub = 4; param.setSourceRegion(roi);
// param.setSourceSubsampling(sub, sub, 0, 0);
// } image = reader.getImageTypes(0).next().createBufferedImage((reader.getWidth(0) + subX - 1)/ subX, (reader.getHeight(0) + subY - 1) / subY);
BufferedImage image = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0)); }
else {
image = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0));
}
param.setDestination(image); param.setDestination(image);
// long start = System.currentTimeMillis(); long start = DEBUG ? System.currentTimeMillis() : 0;
try { try {
image = reader.read(0, param); image = reader.read(0, param);
} }
@@ -1387,12 +1487,13 @@ public class JPEGImageReader extends ImageReaderBase {
continue; continue;
} }
} }
// System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
// System.err.println("image: " + image);
if (DEBUG) {
System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
System.err.println("image: " + image);
}
// image = new ResampleOp(reader.getWidth(0) / 4, reader.getHeight(0) / 4, ResampleOp.FILTER_LANCZOS).filter(image, null); /*
int maxW = 1280; int maxW = 1280;
int maxH = 800; int maxH = 800;
if (image.getWidth() > maxW || image.getHeight() > maxH) { if (image.getWidth() > maxW || image.getHeight() > maxH) {
@@ -1406,34 +1507,45 @@ public class JPEGImageReader extends ImageReaderBase {
} }
// System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms"); // System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms");
} }
*/
showIt(image, String.format("Image: %s [%d x %d]", file.getName(), reader.getWidth(0), reader.getHeight(0))); showIt(image, String.format("Image: %s [%d x %d]", file.getName(), reader.getWidth(0), reader.getHeight(0)));
try { if (metadata) {
IIOMetadata imageMetadata = reader.getImageMetadata(0); try {
System.out.println("Metadata for File: " + file.getName()); IIOMetadata imageMetadata = reader.getImageMetadata(0);
System.out.println("Metadata for File: " + file.getName());
if (imageMetadata.getNativeMetadataFormatName() != null) { if (imageMetadata.getNativeMetadataFormatName() != null) {
System.out.println("Native:"); System.out.println("Native:");
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(imageMetadata.getNativeMetadataFormatName()), false); new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(imageMetadata.getNativeMetadataFormatName()), false);
}
if (imageMetadata.isStandardMetadataFormatSupported()) {
System.out.println("Standard:");
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName), false);
}
System.out.println();
} }
if (imageMetadata.isStandardMetadataFormatSupported()) { catch (IIOException e) {
System.out.println("Standard:"); System.err.println("Could not read thumbnails: " + arg + ": " + e.getMessage());
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName), false); e.printStackTrace();
}
System.out.println();
int numThumbnails = reader.getNumThumbnails(0);
for (int i = 0; i < numThumbnails; i++) {
BufferedImage thumbnail = reader.readThumbnail(0, i);
// System.err.println("thumbnail: " + thumbnail);
showIt(thumbnail, String.format("Thumbnail: %s [%d x %d]", file.getName(), thumbnail.getWidth(), thumbnail.getHeight()));
} }
} }
catch (IIOException e) {
System.err.println("Could not read thumbnails: " + arg + ": " + e.getMessage()); if (thumbnails) {
e.printStackTrace(); try {
int numThumbnails = reader.getNumThumbnails(0);
for (int i = 0; i < numThumbnails; i++) {
BufferedImage thumbnail = reader.readThumbnail(0, i);
// System.err.println("thumbnail: " + thumbnail);
showIt(thumbnail, String.format("Thumbnail: %s [%d x %d]", file.getName(), thumbnail.getWidth(), thumbnail.getHeight()));
}
}
catch (IIOException e) {
System.err.println("Could not read thumbnails: " + arg + ": " + e.getMessage());
e.printStackTrace();
}
} }
} }
catch (Throwable t) { catch (Throwable t) {
@@ -29,6 +29,7 @@
package com.twelvemonkeys.imageio.plugins.jpeg; package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase; import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
import com.twelvemonkeys.imageio.util.IIOUtil; import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.lang.Validate;
@@ -48,14 +49,14 @@ import java.util.Locale;
* @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$ * @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$
*/ */
public class JPEGImageReaderSpi extends ImageReaderSpiBase { public class JPEGImageReaderSpi extends ImageReaderSpiBase {
private ImageReaderSpi delegateProvider; protected ImageReaderSpi delegateProvider;
/** /**
* Constructor for use by {@link javax.imageio.spi.IIORegistry} only. * Constructor for use by {@link javax.imageio.spi.IIORegistry} only.
* The instance created will not work without being properly registered. * The instance created will not work without being properly registered.
*/ */
public JPEGImageReaderSpi() { public JPEGImageReaderSpi() {
super(new JPEGProviderInfo()); this(new JPEGProviderInfo());
} }
/** /**
@@ -69,6 +70,15 @@ public class JPEGImageReaderSpi extends ImageReaderSpiBase {
this.delegateProvider = Validate.notNull(delegateProvider); this.delegateProvider = Validate.notNull(delegateProvider);
} }
/**
* Constructor for subclasses.
*
* @param info
*/
protected JPEGImageReaderSpi(final ReaderWriterProviderInfo info) {
super(info);
}
static ImageReaderSpi lookupDelegateProvider(final ServiceRegistry registry) { static ImageReaderSpi lookupDelegateProvider(final ServiceRegistry registry) {
Iterator<ImageReaderSpi> providers = registry.getServiceProviders(ImageReaderSpi.class, true); Iterator<ImageReaderSpi> providers = registry.getServiceProviders(ImageReaderSpi.class, true);
@@ -83,7 +93,7 @@ public class JPEGImageReaderSpi extends ImageReaderSpiBase {
return null; return null;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked", "deprecation"})
@Override @Override
public void onRegistration(final ServiceRegistry registry, final Class<?> category) { public void onRegistration(final ServiceRegistry registry, final Class<?> category) {
if (delegateProvider == null) { if (delegateProvider == null) {
@@ -63,8 +63,7 @@ import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.verify;
/** /**
* JPEGImageReaderTest * JPEGImageReaderTest
@@ -75,9 +74,9 @@ import static org.mockito.Mockito.verify;
*/ */
public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> { public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> {
private static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider()); protected static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider());
private static ImageReaderSpi lookupDelegateProvider() { protected static ImageReaderSpi lookupDelegateProvider() {
return JPEGImageReaderSpi.lookupDelegateProvider(IIORegistry.getDefaultInstance()); return JPEGImageReaderSpi.lookupDelegateProvider(IIORegistry.getDefaultInstance());
} }
@@ -87,6 +86,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
return Arrays.asList( return Arrays.asList(
new TestData(getClassLoaderResource("/jpeg/cmm-exception-adobe-rgb.jpg"), new Dimension(626, 76)), new TestData(getClassLoaderResource("/jpeg/cmm-exception-adobe-rgb.jpg"), new Dimension(626, 76)),
new TestData(getClassLoaderResource("/jpeg/cmm-exception-srgb.jpg"), new Dimension(1800, 1200)), new TestData(getClassLoaderResource("/jpeg/cmm-exception-srgb.jpg"), new Dimension(1800, 1200)),
new TestData(getClassLoaderResource("/jpeg/corrupted-icc-srgb.jpg"), new Dimension(1024, 685)),
new TestData(getClassLoaderResource("/jpeg/gray-sample.jpg"), new Dimension(386, 396)), new TestData(getClassLoaderResource("/jpeg/gray-sample.jpg"), new Dimension(386, 396)),
new TestData(getClassLoaderResource("/jpeg/cmyk-sample.jpg"), new Dimension(160, 227)), new TestData(getClassLoaderResource("/jpeg/cmyk-sample.jpg"), new Dimension(160, 227)),
new TestData(getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), new Dimension(2707, 3804)), new TestData(getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), new Dimension(2707, 3804)),
@@ -370,7 +370,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
assertEquals(1772, image.getWidth()); assertEquals(1772, image.getWidth());
assertEquals(8, image.getHeight()); assertEquals(8, image.getHeight());
verify(warningListener).warningOccurred(eq(reader), anyString()); verify(warningListener, atLeast(1)).warningOccurred(eq(reader), anyString());
} }
@Test @Test
Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

+1 -1
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>imageio-metadata</artifactId> <artifactId>imageio-metadata</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pcx</artifactId> <artifactId>imageio-pcx</artifactId>
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name> <name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pdf</artifactId> <artifactId>imageio-pdf</artifactId>
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name> <name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pict</artifactId> <artifactId>imageio-pict</artifactId>
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name> <name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pnm</artifactId> <artifactId>imageio-pnm</artifactId>
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name> <name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-psd</artifactId> <artifactId>imageio-psd</artifactId>
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name> <name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
@@ -74,7 +74,7 @@ final class PSDLayerInfo {
long extraDataSize = pInput.readUnsignedInt(); long extraDataSize = pInput.readUnsignedInt();
// Layer mask/adjustment layer data // Layer mask/adjustment layer data
int layerMaskDataSize = pInput.readInt(); // May be 0, 20 or 36 bytes... int layerMaskDataSize = pInput.readInt(); // May be 0, 20 or variable (up to 55) bytes...
if (layerMaskDataSize != 0) { if (layerMaskDataSize != 0) {
layerMaskData = new PSDLayerMaskData(pInput, layerMaskDataSize); layerMaskData = new PSDLayerMaskData(pInput, layerMaskDataSize);
} }
@@ -47,42 +47,90 @@ final class PSDLayerMaskData {
private int defaultColor; private int defaultColor;
private int flags; private int flags;
private boolean large; private int maskParams;
private int realFlags; private int userMaskDensity;
private int realUserBackground; private double userMaskFeather;
private int realTop; private int vectorMaskDensity;
private int realLeft; private double vectorMaskFeather;
private int realBottom;
private int realRight;
PSDLayerMaskData(final ImageInputStream pInput, final int pSize) throws IOException { PSDLayerMaskData(final ImageInputStream pInput, final int pSize) throws IOException {
if (pSize != 20 && pSize != 36) { if (pSize < 20 || pSize > 55) {
throw new IIOException("Illegal PSD Layer Mask data size: " + pSize + " (expected 20 or 36)"); throw new IIOException("Illegal PSD Layer Mask data size: " + pSize + " (expected between 20 and 55)");
} }
// Rectangle enclosing layer mask: Top, left, bottom, right.
top = pInput.readInt(); top = pInput.readInt();
left = pInput.readInt(); left = pInput.readInt();
bottom = pInput.readInt(); bottom = pInput.readInt();
right = pInput.readInt(); right = pInput.readInt();
// Default color. 0 or 255
defaultColor = pInput.readUnsignedByte(); defaultColor = pInput.readUnsignedByte();
// Flags.
// bit 0 = position relative to layer
// bit 1 = layer mask disabled
// bit 2 = invert layer mask when blending (Obsolete)
// bit 3 = indicates that the user mask actually came from rendering other data
// bit 4 = indicates that the user and/or vector masks have parameters applied to them
flags = pInput.readUnsignedByte(); flags = pInput.readUnsignedByte();
if (pSize == 20) { int dataLeft = pSize - 18;
if ((flags & 0x10) != 0) {
// Mask Parameters. Only present if bit 4 of Flags set above.
maskParams = pInput.readUnsignedByte();
dataLeft--;
// Mask Parameters bit flags present as follows:
// bit 0 = user mask density, 1 byte
// bit 1 = user mask feather, 8 byte, double
// bit 2 = vector mask density, 1 byte
// bit 3 = vector mask feather, 8 bytes, double
if ((maskParams & 0x01) != 0) {
userMaskDensity = pInput.readByte();
dataLeft--;
}
if ((maskParams & 0x02) != 0) {
userMaskFeather = pInput.readDouble();
dataLeft -= 8;
}
if ((maskParams & 0x04) != 0) {
vectorMaskDensity = pInput.readByte();
dataLeft--;
}
if ((maskParams & 0x08) != 0) {
vectorMaskFeather = pInput.readDouble();
dataLeft -= 8;
}
}
// Padding. Only present if size = 20. Otherwise the following is present
if (pSize == 20 && dataLeft == 2) {
pInput.readShort(); // Pad pInput.readShort(); // Pad
dataLeft -= 2;
} }
else { else {
// TODO: What to make out of this? if (dataLeft >= 2) {
large = true; // Real Flags. Same as Flags information above.
flags = pInput.readUnsignedByte();
dataLeft--;
// Real user mask background. 0 or 255.
defaultColor = pInput.readUnsignedByte();
dataLeft--;
}
if (dataLeft >= 16) {
// Rectangle enclosing layer mask: Top, left, bottom, right.
top = pInput.readInt();
left = pInput.readInt();
bottom = pInput.readInt();
right = pInput.readInt();
dataLeft -= 16;
}
}
realFlags = pInput.readUnsignedByte(); if (dataLeft > 0) {
realUserBackground = pInput.readUnsignedByte(); pInput.skipBytes(dataLeft);
realTop = pInput.readInt();
realLeft = pInput.readInt();
realBottom = pInput.readInt();
realRight = pInput.readInt();
} }
} }
@@ -97,40 +145,54 @@ final class PSDLayerMaskData {
builder.append(", default color: ").append(defaultColor); builder.append(", default color: ").append(defaultColor);
builder.append(", flags: ").append(Integer.toBinaryString(flags)); builder.append(", flags: ").append(Integer.toBinaryString(flags));
// TODO: Maybe the flag bits have oposite order?
builder.append(" ("); builder.append(" (");
if ((flags & 0x01) != 0) { if ((flags & 0x01) != 0) {
builder.append("Pos. rel. to layer"); builder.append("relative");
} }
else { else {
builder.append("Pos. abs."); builder.append("absolute");
} }
if ((flags & 0x02) != 0) { if ((flags & 0x02) != 0) {
builder.append(", Mask disabled"); builder.append(", disabled");
} }
else { else {
builder.append(", Mask enabled"); builder.append(", enabled");
} }
if ((flags & 0x04) != 0) { if ((flags & 0x04) != 0) {
builder.append(", Invert mask"); builder.append(", inverted");
} }
if ((flags & 0x08) != 0) { if ((flags & 0x08) != 0) {
builder.append(", Unknown bit 3"); builder.append(", from rendered data");
} }
if ((flags & 0x10) != 0) { if ((flags & 0x10) != 0) {
builder.append(", Unknown bit 4"); builder.append(", has parameters");
} }
if ((flags & 0x20) != 0) { if ((flags & 0x20) != 0) {
builder.append(", Unknown bit 5"); builder.append(", unknown flag (bit 5)");
} }
if ((flags & 0x40) != 0) { if ((flags & 0x40) != 0) {
builder.append(", Unknown bit 6"); builder.append(", unknown flag (bit 6)");
} }
if ((flags & 0x80) != 0) { if ((flags & 0x80) != 0) {
builder.append(", Unknown bit 7"); builder.append(", unknown flag (bit 7)");
} }
builder.append(")"); builder.append(")");
if ((flags & 0x10) != 0) {
if ((maskParams & 0x01) != 0) {
builder.append(", userMaskDensity: ").append(userMaskDensity);
}
if ((maskParams & 0x02) != 0) {
builder.append(", userMaskFeather: ").append(userMaskFeather);
}
if ((maskParams & 0x04) != 0) {
builder.append(", vectorMaskDensity: ").append(vectorMaskDensity);
}
if ((maskParams & 0x08) != 0) {
builder.append(", vectorMaskFeather: ").append(vectorMaskFeather);
}
}
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-reference</artifactId> <artifactId>imageio-reference</artifactId>
<name>TwelveMonkeys :: ImageIO :: reference test cases</name> <name>TwelveMonkeys :: ImageIO :: reference test cases</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-sgi</artifactId> <artifactId>imageio-sgi</artifactId>
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name> <name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-tga</artifactId> <artifactId>imageio-tga</artifactId>
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name> <name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-thumbsdb</artifactId> <artifactId>imageio-thumbsdb</artifactId>
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name> <name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-tiff</artifactId> <artifactId>imageio-tiff</artifactId>
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name> <name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
@@ -36,7 +36,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* CCITT Modified Huffman RLE, Group 3 (T4) and Group 4 (T6) fax compression. * CCITT Modified Huffman RLE<!--, and hopefully soon: Group 3 (T4) and Group 4 (T6) fax compression-->.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$ * @author last modified by $Author: haraldk$
@@ -145,9 +145,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, renderedImage.getHeight())); entries.add(new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, renderedImage.getHeight()));
// entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, 1)); // (optional) // entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, 1)); // (optional)
entries.add(new TIFFEntry(TIFF.TAG_BITS_PER_SAMPLE, asShortArray(sampleModel.getSampleSize()))); entries.add(new TIFFEntry(TIFF.TAG_BITS_PER_SAMPLE, asShortArray(sampleModel.getSampleSize())));
// If numComponents > 3, write ExtraSamples // If numComponents > numColorComponents, write ExtraSamples
if (numComponents > 3) { if (numComponents > colorModel.getNumColorComponents()) {
// TODO: Write per component > 3 // TODO: Write per component > numColorComponents
if (colorModel.hasAlpha()) { if (colorModel.hasAlpha()) {
entries.add(new TIFFEntry(TIFF.TAG_EXTRA_SAMPLES, colorModel.isAlphaPremultiplied() ? TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA : TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA)); entries.add(new TIFFEntry(TIFF.TAG_EXTRA_SAMPLES, colorModel.isAlphaPremultiplied() ? TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA : TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA));
} }
@@ -169,6 +169,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
default: default:
} }
// TODO: We might want to support CMYK in JPEG as well...
int photometric = compression == TIFFExtension.COMPRESSION_JPEG ? int photometric = compression == TIFFExtension.COMPRESSION_JPEG ?
TIFFExtension.PHOTOMETRIC_YCBCR : TIFFExtension.PHOTOMETRIC_YCBCR :
getPhotometricInterpretation(colorModel); getPhotometricInterpretation(colorModel);
@@ -684,7 +685,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
// BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_BGR); // BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_BGR);
// BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_3BYTE_BGR); // BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
BufferedImage image; BufferedImage image;
if (type < 0 || type == original.getType()) { if (type <= 0 || type == original.getType()) {
image = original; image = original;
} }
else if (type == BufferedImage.TYPE_BYTE_INDEXED) { else if (type == BufferedImage.TYPE_BYTE_INDEXED) {
@@ -0,0 +1 @@
com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriterSpi
+1 -1
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
+1 -1
View File
@@ -8,7 +8,7 @@
</parent> </parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Twelvemonkeys</name> <name>Twelvemonkeys</name>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.1.0</version> <version>3.1.3-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>