Solving the quality problem when resizing. It costs a bit in CPU usage, but worth it.
This commit is contained in:
parent
779138efaa
commit
55366a9aa7
3 changed files with 49 additions and 25 deletions
1
photos/geiranger/.cvsignore
Normal file
1
photos/geiranger/.cvsignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
cache.properties
|
||||
|
|
@ -16,6 +16,11 @@ public class Dimension {
|
|||
int w;
|
||||
int h;
|
||||
|
||||
public Dimension(Dimension other) {
|
||||
this.w = other.w;
|
||||
this.h = other.h;
|
||||
}
|
||||
|
||||
public Dimension(int w, int h) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
|
|
@ -28,6 +33,16 @@ public class Dimension {
|
|||
}
|
||||
|
||||
|
||||
public Dimension doubled() {
|
||||
|
||||
return new Dimension(w * 2, h * 2);
|
||||
}
|
||||
|
||||
public Dimension halved() {
|
||||
|
||||
return new Dimension(w / 2, h / 2);
|
||||
}
|
||||
|
||||
public Dimension scaled(int max) {
|
||||
|
||||
return w > h ? scaleWidth(max) : scaleHeight(max);
|
||||
|
|
|
|||
|
|
@ -153,61 +153,69 @@ public class AlbumServlet
|
|||
outd = orig.scaled(worh);
|
||||
}
|
||||
|
||||
/* In order to make the quality as good as possible we follow the advice from
|
||||
* http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
|
||||
* and scale the image by a factor of 2 in intermediate steps, thereby getting a smoother
|
||||
* end result. The first scale will get to a size which is a multiple of the result size.
|
||||
* the first scaling operation will also take care of any rotation that needs to happen.
|
||||
*/
|
||||
Dimension intermediate = new Dimension(outd);
|
||||
int targetWidth = orig.getWidth() / 2;
|
||||
while (intermediate.getWidth() < targetWidth) {
|
||||
intermediate = intermediate.doubled();
|
||||
}
|
||||
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
|
||||
ImageReader reader = readers.next();
|
||||
ImageInputStream iis = ImageIO.createImageInputStream(file);
|
||||
reader.setInput(iis, true);
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
// param.setDestinationType(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
||||
if (false /* subsampling */) {
|
||||
double subSampleScale = (double)outd.getWidth() / orig.getWidth();
|
||||
int subSampling = (int)Math.floor(0.25d/subSampleScale);
|
||||
if (subSampling > 1) {
|
||||
param.setSourceSubsampling(subSampling, subSampling, 0, 0);
|
||||
}
|
||||
}
|
||||
BufferedImage img = reader.read(0, param);
|
||||
|
||||
// Recalculate scale after sub-sampling was applied
|
||||
double scale;
|
||||
AffineTransform xform;
|
||||
if (thumbnail.getOrientation() == 6) {
|
||||
xform = AffineTransform.getTranslateInstance(outd.getWidth() / 2d, outd.getHeight() / 2d);
|
||||
xform = AffineTransform.getTranslateInstance(intermediate.getWidth() / 2d, intermediate.getHeight() / 2d);
|
||||
xform.rotate(Math.PI / 2);
|
||||
scale = (double)outd.getHeight() / img.getWidth();
|
||||
scale = (double)intermediate.getHeight() / img.getWidth();
|
||||
xform.scale(scale, scale);
|
||||
xform.translate(-img.getWidth() / 2d, -img.getHeight() / 2d);
|
||||
|
||||
} else {
|
||||
scale = (double)outd.getWidth() / img.getWidth();
|
||||
scale = (double)intermediate.getWidth() / img.getWidth();
|
||||
xform = AffineTransform.getScaleInstance(scale, scale);
|
||||
}
|
||||
// AffineTransformOp operation = new AffineTransformOp(xform, AffineTransformOp.TYPE_BICUBIC);
|
||||
// BufferedImage buf2 = operation.createCompatibleDestImage(img, img.getColorModel());
|
||||
BufferedImage buf2 = new BufferedImage(outd.getWidth(), outd.getHeight(), img.getType());
|
||||
|
||||
// operation.filter(img, buf2);
|
||||
|
||||
BufferedImage buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), img.getType());
|
||||
Graphics2D g2 = buf2.createGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
|
||||
g2.transform(xform);
|
||||
g2.drawImage(img, 0, 0, null);
|
||||
|
||||
// g2.drawImage(img, operation, 0, 0);
|
||||
while (intermediate.getWidth() > outd.getWidth()) {
|
||||
|
||||
BufferedImage buf3 = buf2;
|
||||
intermediate = intermediate.halved();
|
||||
buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), img.getType());
|
||||
Graphics2D g3 = buf2.createGraphics();
|
||||
g3.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g3.drawImage(buf3, 0, 0, intermediate.getWidth(), intermediate.getHeight(), null);
|
||||
}
|
||||
|
||||
// g2.drawImage(img, operation, 0, 0);
|
||||
|
||||
|
||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
|
||||
ImageWriter writer = writers.next();
|
||||
ImageWriteParam wParam = writer.getDefaultWriteParam();
|
||||
wParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
wParam.setCompressionQuality(1.0f);
|
||||
// ImageWriteParam wParam = writer.getDefaultWriteParam();
|
||||
// wParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
// wParam.setCompressionQuality(1.0f);
|
||||
ImageOutputStream ios = ImageIO.createImageOutputStream(res.getOutputStream());
|
||||
writer.setOutput(ios);
|
||||
writer.write(null, new IIOImage(buf2, null, null), wParam);
|
||||
// writer.write(null, new IIOImage(buf2, null, null), wParam);
|
||||
writer.write(buf2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue