Commit 82e8b490 authored by Matija Obreza's avatar Matija Obreza

Merge branch 'server-446-better-thumbnail-quality' into 'master'

Thumbnails as JPEGs

See merge request !32
parents 7adf7dd7 71ae1fae
Pipeline #10121 passed with stage
in 1 minute and 25 seconds
/* /*
* Copyright 2018 Global Crop Diversity Trust * Copyright 2019 Global Crop Diversity Trust
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -24,7 +24,6 @@ import org.genesys.filerepository.model.RepositoryFolder; ...@@ -24,7 +24,6 @@ import org.genesys.filerepository.model.RepositoryFolder;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
// TODO: Auto-generated Javadoc
/** /**
* The ImageGalleryService. * The ImageGalleryService.
*/ */
...@@ -34,7 +33,10 @@ public interface ImageGalleryService { ...@@ -34,7 +33,10 @@ public interface ImageGalleryService {
public static final String THUMB_PATH = "/_thumbs"; public static final String THUMB_PATH = "/_thumbs";
/** The Constant THUMB_EXT. */ /** The Constant THUMB_EXT. */
public static final String THUMB_EXT = ".png"; public static final String THUMB_EXT = ".jpg";
/** The Constant THUMB_CONTENT_TYPE. */
public static final String THUMB_CONTENT_TYPE = "image/jpeg";
/** /**
* Loads gallery with the specified path. * Loads gallery with the specified path.
......
...@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
...@@ -77,6 +78,9 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { ...@@ -77,6 +78,9 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/** Thumbnail generator. */ /** Thumbnail generator. */
@Autowired @Autowired
private ThumbnailGenerator thumbnailGenerator; private ThumbnailGenerator thumbnailGenerator;
@Autowired(required = false)
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
/** The jpa query factory. */ /** The jpa query factory. */
@Autowired @Autowired
...@@ -251,27 +255,40 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { ...@@ -251,27 +255,40 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
return; return;
} }
imageGallery2.getImages().forEach(repositoryImage -> { imageGallery2.getImages().forEach(repositoryImage -> makeThumbnails(repositoryImage));
try { }
final byte[][] cache = new byte[1][];
/**
for (int i = thumbnailSizes.length - 1; i >= 0; i--) { * Use {@link #threadPoolTaskExecutor} if available.
cache[0] = ensureThumbnail(thumbnailSizes[i], thumbnailSizes[i], repositoryImage, () -> { */
if (cache[0] != null) { private void makeThumbnails(RepositoryImage repositoryImage) {
LOG.debug("Using cached image bytes for {}", repositoryImage.getStoragePath()); if (threadPoolTaskExecutor != null) {
return cache[0]; threadPoolTaskExecutor.submit(() -> generateThumbnails(repositoryImage));
} else { } else {
LOG.info("Must load image bytes for {}", repositoryImage.getStoragePath()); generateThumbnails(repositoryImage);
return cache[0] = bytesStorageService.get(repositoryImage.storagePath()); }
} }
});
} private void generateThumbnails(final RepositoryImage repositoryImage) {
} catch (final NullPointerException e) { try {
LOG.error("Error generating thumbnail for image={} message={}", repositoryImage, e.getMessage(), e); final byte[][] cache = new byte[1][];
} catch (final Exception e) {
LOG.error("Error generating thumbnail for " + repositoryImage, e); for (int i = thumbnailSizes.length - 1; i >= 0; i--) {
cache[0] = ensureThumbnail(thumbnailSizes[i], thumbnailSizes[i], repositoryImage, () -> {
if (cache[0] != null) {
LOG.debug("Using cached image bytes for {}", repositoryImage.getStoragePath());
return cache[0];
} else {
LOG.info("Must load image bytes for {}", repositoryImage.getStoragePath());
return cache[0] = bytesStorageService.get(repositoryImage.storagePath());
}
});
} }
}); } catch (final NullPointerException e) {
LOG.error("Error generating thumbnail for image={} message={}", repositoryImage, e.getMessage(), e);
} catch (final Exception e) {
LOG.error("Error generating thumbnail for " + repositoryImage, e);
}
} }
/** /**
...@@ -327,12 +344,12 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { ...@@ -327,12 +344,12 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
LOG.debug("Generating new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid()); LOG.debug("Generating new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid());
try { try {
final byte[] bytesPng = thumbnailGenerator.createThumbnail(width, height, loader.getImageBytes()); final byte[] thumbnailBytes = thumbnailGenerator.createThumbnail(width, height, loader.getImageBytes());
LOG.debug("Persisting new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid()); LOG.debug("Persisting new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid());
bytesStorageService.upsert(getFullThumbnailsPath(repositoryImage).resolve(filename), bytesPng); bytesStorageService.upsert(getFullThumbnailsPath(repositoryImage).resolve(filename), thumbnailBytes);
return bytesPng; return thumbnailBytes;
} catch (NullPointerException e) { } catch (NullPointerException e) {
LOG.warn("Error generating thumbnail: {}", e.getMessage()); LOG.warn("Error generating thumbnail: {}", e.getMessage());
} }
...@@ -358,7 +375,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { ...@@ -358,7 +375,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
if (height != null) { if (height != null) {
sb.append(height); sb.append(height);
} }
sb.append(".png"); sb.append(ImageGalleryService.THUMB_EXT);
return sb.toString(); return sb.toString();
} }
......
...@@ -56,13 +56,13 @@ public class ThumbnailGenerator1 implements ThumbnailGenerator { ...@@ -56,13 +56,13 @@ public class ThumbnailGenerator1 implements ThumbnailGenerator {
final InputStream inputStream = new ByteArrayInputStream(imageBytes); final InputStream inputStream = new ByteArrayInputStream(imageBytes);
final Builder<? extends InputStream> th = Thumbnails.of(inputStream); final Builder<? extends InputStream> th = Thumbnails.of(inputStream);
th.outputFormat("png"); th.outputFormat("jpg");
th.antialiasing(Antialiasing.ON); th.antialiasing(Antialiasing.ON);
th.alphaInterpolation(AlphaInterpolation.QUALITY); th.alphaInterpolation(AlphaInterpolation.QUALITY);
// th.dithering(Dithering.DISABLE); // th.dithering(Dithering.DISABLE);
th.outputQuality(0.9f); th.outputQuality(0.9f);
th.rendering(Rendering.QUALITY); th.rendering(Rendering.QUALITY);
th.scalingMode(ScalingMode.BICUBIC); th.scalingMode(ScalingMode.PROGRESSIVE_BILINEAR);
th.crop(Positions.CENTER); th.crop(Positions.CENTER);
if ((width != null) && (height != null)) { if ((width != null) && (height != null)) {
......
...@@ -121,7 +121,7 @@ public class ImageGalleryThumbnailsTest extends RepositoryServiceTest { ...@@ -121,7 +121,7 @@ public class ImageGalleryThumbnailsTest extends RepositoryServiceTest {
final TestImage image1 = new TestImage("maize.jpg", "image/jpg"); final TestImage image1 = new TestImage("maize.jpg", "image/jpg");
final RepositoryImage repoImage1 = fileRepoService.addImage(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null); final RepositoryImage repoImage1 = fileRepoService.addImage(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null);
final byte[] thumbBytes1 = bytesStorageService.get(Paths.get(ImageGalleryService.THUMB_PATH, repoImage1.getThumbnailPath(), "200x200" + ".png")); final byte[] thumbBytes1 = bytesStorageService.get(Paths.get(ImageGalleryService.THUMB_PATH, repoImage1.getThumbnailPath(), "200x200" + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail must not be null", thumbBytes1, notNullValue()); assertThat("Thumbnail must not be null", thumbBytes1, notNullValue());
try (InputStream is = new ByteArrayInputStream(thumbBytes1)) { try (InputStream is = new ByteArrayInputStream(thumbBytes1)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment