Skip to content

Commit

Permalink
next attempt to fix #38 (gamma correction)
Browse files Browse the repository at this point in the history
  • Loading branch information
yagee-de committed Aug 7, 2024
1 parent 56a4f8c commit e710d38
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 78 deletions.
66 changes: 24 additions & 42 deletions src/main/java/org/mycore/imagetiler/MCRImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@
package org.mycore.imagetiler;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_ProfileGray;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
Expand Down Expand Up @@ -126,8 +122,6 @@ public class MCRImage {

private static final ColorConvertOp COLOR_CONVERT_OP = new ColorConvertOp(null);

public static final float DEFAULT_GAMMA = 1F;

/**
* derivate ID (for output directory calculation).
*/
Expand Down Expand Up @@ -167,6 +161,8 @@ public class MCRImage {

private MCROrientation orientation;

private boolean converTilesToGray = false;

static {
imageWriteParam = new JPEGImageWriteParam(Locale.getDefault());
try {
Expand Down Expand Up @@ -343,8 +339,8 @@ private static ImageReader createImageReader(final ImageInputStream imageInputSt
* @return area of interest
* @throws IOException if source file could not be read
*/
protected static BufferedImage getTileOfFile(final ImageReader reader, final int x, final int y, final int width,
final int height, MCROrientation orientation, final int imageWidth, final int imageHeight) throws IOException {
protected BufferedImage getTileOfFile(final ImageReader reader, final int x, final int y, final int width,
final int height) throws IOException {
final ImageReadParam param = reader.getDefaultReadParam();
final Rectangle srcRegion = new Rectangle(x, y, width, height);
final Rectangle physicalRegion = MCROrientationUtils.toPhysical(imageWidth, imageHeight, srcRegion,
Expand Down Expand Up @@ -373,39 +369,27 @@ protected static int getBufferedImageType(final ImageReader reader) throws IOExc
return imageType == BufferedImage.TYPE_CUSTOM ? BufferedImage.TYPE_INT_RGB : imageType;
}

private static BufferedImage convertIfNeeded(BufferedImage tile) {
private BufferedImage convertIfNeeded(BufferedImage tile) {
ColorModel colorModel = tile.getColorModel();
boolean convertToGray = isFakeGrayScale(colorModel) || colorModel.getNumColorComponents() == 1;
int pixelSize = colorModel.getPixelSize();
int targetType = tile.getType();
if (convertToGray) {
LOGGER.info("Image is gray scale but uses color map. Converting to gray scale");
targetType = BufferedImage.TYPE_BYTE_GRAY;
converTilesToGray = true;
} else if (pixelSize > JPEG_CM_PIXEL_SIZE) {
LOGGER.info("Converting image to 24 bit color depth: Color depth {}", pixelSize);
targetType = BufferedImage.TYPE_INT_RGB;
} else if (tile.getType() == BufferedImage.TYPE_CUSTOM) {
LOGGER.info("Converting image to 24 bit color depth: Image type is 'CUSTOM'");
targetType = BufferedImage.TYPE_INT_RGB;
}
if (targetType == tile.getType()) {
if (!convertToGray && BufferedImage.TYPE_INT_RGB == tile.getType()) {
//no need for conversion
return tile;
}
final BufferedImage newTile = new BufferedImage(tile.getWidth(), tile.getHeight(),
convertToGray ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_INT_RGB);
final BufferedImage newTile = new BufferedImage(tile.getWidth(), tile.getHeight(), BufferedImage.TYPE_INT_RGB);
COLOR_CONVERT_OP.filter(tile, newTile);
return newTile;
}

private static float getGamma(ColorSpace colorSpace) {
if (colorSpace instanceof ICC_ColorSpace iccColorSpace
&& iccColorSpace.getProfile() instanceof ICC_ProfileGray grayProfile) {
return grayProfile.getGamma();
}
return DEFAULT_GAMMA;
}

/**
* @return true, if gray scale image uses color map where every entry uses the same value for each color component
*/
Expand All @@ -427,19 +411,19 @@ private static boolean isFakeGrayScale(ColorModel colorModel) {

/**
* Shrinks the image to 50%.
*
* @param image source image
* @return shrinked image
*/
protected static BufferedImage scaleBufferedImage(final BufferedImage image, boolean useScaledInstance) {
protected static BufferedImage scaleBufferedImage(final BufferedImage image) {
LOGGER.debug("Scaling image...");
final int width = image.getWidth();
final int height = image.getHeight();
final int newWidth = (int) Math.ceil(width / 2d);
final int newHeight = (int) Math.ceil(height / 2d);
Image scaledImage = useScaledInstance ? image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH) : null;
final BufferedImage bicubic = new BufferedImage(newWidth, newHeight, getImageType(image));
Graphics2D graphics = bicubic.createGraphics();
graphics.drawImage(useScaledInstance ? scaledImage : image, 0, 0, newWidth, newHeight, null);
graphics.drawImage(image, 0, 0, newWidth, newHeight, null);
graphics.dispose();
LOGGER.debug("Scaling done: {}x{}", width, height);
return bicubic;
Expand Down Expand Up @@ -590,7 +574,7 @@ public MCRTiledPictureProps tile(MCRTileEventHandler eventHandler) throws IOExce
LOGGER.debug("ImageReader: {}", imageReader.getClass());
try (ZipOutputStream zout = getZipOutputStream()) {
setImageSize(imageReader);
doTile(imageReader, zout, shouldApplyGammaCorrection(imageReader));
doTile(imageReader, zout);
writeMetaData(zout);
} finally {
imageReader.dispose();
Expand All @@ -605,15 +589,6 @@ public MCRTiledPictureProps tile(MCRTileEventHandler eventHandler) throws IOExce
return imageProperties;
}

private boolean shouldApplyGammaCorrection(ImageReader imageReader) throws IOException {
ColorModel colorModel = imageReader.getRawImageType(0).getColorModel();
if (colorModel.getNumColorComponents() == 1) {
float gamma = getGamma(colorModel.getColorSpace());
return (gamma != DEFAULT_GAMMA);
}
return false;
}

private void setOrientation() {
long start = System.nanoTime();
short orientation = 1;
Expand Down Expand Up @@ -642,10 +617,9 @@ protected MCROrientation getOrientation() {
return orientation;
}

protected void doTile(final ImageReader imageReader, final ZipOutputStream zout, boolean shouldApplyGammaCorrection)
protected void doTile(final ImageReader imageReader, final ZipOutputStream zout)
throws IOException {
BufferedImage image = getTileOfFile(imageReader, 0, 0, getImageWidth(), getImageHeight(),
getOrientation(), getImageWidth(), getImageHeight());
BufferedImage image = getTileOfFile(imageReader, 0, 0, getImageWidth(), getImageHeight());
final int zoomLevels = getZoomLevels(getImageWidth(), getImageHeight());
LOGGER.info("Will generate {} zoom levels.", zoomLevels);
for (int z = zoomLevels; z >= 0; z--) {
Expand All @@ -662,7 +636,7 @@ protected void doTile(final ImageReader imageReader, final ZipOutputStream zout,
}
}
if (z > 0) {
image = scaleBufferedImage(image, shouldApplyGammaCorrection && zoomLevels == z);
image = scaleBufferedImage(image);
}
}
}
Expand Down Expand Up @@ -733,14 +707,22 @@ protected void writeTile(final ZipOutputStream zout, final BufferedImage tile, f
String tileName = Integer.toString(z) + '/' + y + '/' + x + ".jpg";
final ZipEntry ze = new ZipEntry(tileName);
zout.putNextEntry(ze);
writeImageIoTile(zout, tile);
writeImageIoTile(zout, converTilesToGray ? toGray(tile) : tile);
imageTilesCount.incrementAndGet();
} finally {
zout.closeEntry();
}
}
}

private BufferedImage toGray(BufferedImage image) {
BufferedImage gray = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics2D graphics = gray.createGraphics();
graphics.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
graphics.dispose();
return gray;
}

private BufferedImage getTile(final BufferedImage image, final int x, final int y) {
int tileWidth = image.getWidth() - TILE_SIZE * x;
int tileHeight = image.getHeight() - TILE_SIZE * y;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ private static void stichTiles(final BufferedImage stitchImage, final BufferedIm
}

@Override
protected void doTile(final ImageReader imageReader, final ZipOutputStream zout, boolean shouldApplyGammaCorrection)
protected void doTile(final ImageReader imageReader, final ZipOutputStream zout)
throws IOException {
final int redWidth = (int) Math.ceil(getImageWidth() / ((double) megaTileSize / TILE_SIZE));
final int redHeight = (int) Math.ceil(getImageHeight() / ((double) megaTileSize / TILE_SIZE));
Expand All @@ -105,21 +105,20 @@ protected void doTile(final ImageReader imageReader, final ZipOutputStream zout,
final int width = Math.min(megaTileSize, getImageWidth() - xpos);
final int ypos = y * megaTileSize;
final int height = Math.min(megaTileSize, getImageHeight() - ypos);
final BufferedImage megaTile = MCRImage.getTileOfFile(imageReader, xpos, ypos, width, height,
getOrientation(), getImageWidth(), getImageHeight());
final BufferedImage megaTile = getTileOfFile(imageReader, xpos, ypos, width, height);
LOGGER.debug("megaTile create - start tiling");
// stitch
final BufferedImage tile = writeTiles(zout, megaTile, x, y, imageZoomLevels, zoomFactor,
stopOnZoomLevel, shouldApplyGammaCorrection);
stopOnZoomLevel);
if (lastPhaseNeeded) {
stichTiles(lastPhaseImage, tile, x * TILE_SIZE, y * TILE_SIZE);
}
}
}
if (lastPhaseNeeded) {
lastPhaseImage = scaleBufferedImage(lastPhaseImage, false);
lastPhaseImage = scaleBufferedImage(lastPhaseImage);
final int lastPhaseZoomLevels = getZoomLevels(lastPhaseImage.getHeight(), lastPhaseImage.getWidth());
writeTiles(zout, lastPhaseImage, 0, 0, lastPhaseZoomLevels, 0, 0, false);
writeTiles(zout, lastPhaseImage, 0, 0, lastPhaseZoomLevels, 0, 0);
}
}

Expand All @@ -137,7 +136,7 @@ private void setZoomLevelPerStep(final short zoomLevel) {
}

private BufferedImage writeTiles(final ZipOutputStream zout, final BufferedImage megaTile, final int x,
final int y, final int imageZoomLevels, final int zoomFactor, final int stopOnZoomLevel, boolean flag)
final int y, final int imageZoomLevels, final int zoomFactor, final int stopOnZoomLevel)
throws IOException {
final int tWidth = megaTile.getWidth();
final int tHeight = megaTile.getHeight();
Expand All @@ -153,8 +152,8 @@ private BufferedImage writeTiles(final ZipOutputStream zout, final BufferedImage
}
}
if (imageZoomLevels > stopOnZoomLevel) {
tile = scaleBufferedImage(megaTile, flag);
return writeTiles(zout, tile, x, y, imageZoomLevels - 1, zoomFactor / 2, stopOnZoomLevel, false);
tile = scaleBufferedImage(megaTile);
return writeTiles(zout, tile, x, y, imageZoomLevels - 1, zoomFactor / 2, stopOnZoomLevel);
}
return tile;
}
Expand Down
Loading

0 comments on commit e710d38

Please sign in to comment.