public static final String DEFAULT_GALLERY_TITLE = "Gallery";
- public static final String METADATA_FILE_NAME = "metadata_7.dat";
+ public static final String METADATA_FILE_NAME = "metadata_8.dat";
public static final String THUMBNAILS_DIRECTORY_NAME = ".thumbnails";
public static final String[] SUPPORTED_VIDEO_EXTENSIONS = {
"avi", "mp4", "mpeg", "mpg", "mkv", "flv", "ogv"};
- public static final String THUMBNAIL_VERSION = "3";
+ public static final String THUMBNAIL_VERSION = "4";
}
import static org.openimaj.image.ImageUtilities.readMBF;
public class Utils {
+ /**
+ * Read-ahead limit (in bytes) hard-coded inside OpenIMAJ's
+ * {@code ExtendedImageIO.read()} stream mark. Apache Sanselan scans the
+ * whole file while sniffing the image format, so for files larger than
+ * this limit the stream mark gets invalidated and every subsequent
+ * {@code reset()} throws {@code IOException: Resetting to invalid mark}.
+ */
+ private static final long OPENIMAJ_STREAM_MARK_LIMIT = 104857600L;
+
private static File lastLoadedFile;
private static BufferedImage lastLoadedBufferedImage;
if ("jxl".equals(extension)) {
lastLoadedBufferedImage = loadJxlImage(file);
} else {
- lastLoadedBufferedImage = createBufferedImage(readMBF(file));
+ lastLoadedBufferedImage = loadWithOpenImaj(file);
}
lastLoadedFile = file;
return lastLoadedBufferedImage;
}
+ /**
+ * Decode an image with OpenIMAJ (which handles CMYK JPEGs and other
+ * exotic variants that plain JDK ImageIO chokes on).
+ *
+ * Files larger than {@link #OPENIMAJ_STREAM_MARK_LIMIT} are decoded
+ * directly with JDK {@link ImageIO#read(File)}, because OpenIMAJ cannot
+ * handle them: its {@code ExtendedImageIO.read()} marks the input stream
+ * with a 100 MB read-ahead limit, Apache Sanselan then scans the entire
+ * file while sniffing the format, the mark gets invalidated and every
+ * subsequent {@code reset()} fails with
+ * {@code IOException: Resetting to invalid mark}.
+ * {@code ImageIO.read(File)} uses a random-access
+ * {@code FileImageInputStream} instead of mark/reset on the raw stream,
+ * so it decodes such files without trouble.
+ *
+ * For smaller files OpenIMAJ stays the primary decoder, with the same
+ * JDK ImageIO fallback in case it still fails.
+ */
+ private static BufferedImage loadWithOpenImaj(final File file)
+ throws IOException {
+ if (file.length() > OPENIMAJ_STREAM_MARK_LIMIT)
+ return ImageIO.read(file);
+
+ try {
+ return createBufferedImage(readMBF(file));
+ } catch (final IOException e) {
+ System.out.println("OpenIMAJ failed to decode \""
+ + file.getName() + "\" (" + e.getMessage()
+ + "), retrying with JDK ImageIO.");
+ return ImageIO.read(file);
+ }
+ }
+
/**
* Load a JPEG XL (.jxl) image by converting it to PNG using the djxl decoder
* from libjxl-tools, since Java's ImageIO and OpenIMAJ do not natively