Commit 0efa2385 authored by Martin Lowe's avatar Martin Lowe 🇨🇦
Browse files

#445 - Fix EPS compression, save source of compressed images

parent 95e8c912
......@@ -13,7 +13,7 @@ public interface ImageStoreFormat {
String getName();
public enum ImageStoreFormats implements ImageStoreFormat {
SMALL, LARGE, PRINT, WEB;
SMALL, LARGE, PRINT, WEB, WEB_SRC;
@Override
public String getName() {
......
......@@ -49,7 +49,8 @@ public interface ImageStoreService {
* @param format the name of the format to write the image for
* @return absolute path to access the live image
*/
String writeImage(Supplier<byte[]> imageBytes, String organization, String mimeType, Optional<ImageStoreFormat> format);
String writeImage(Supplier<byte[]> imageBytes, String organization, String mimeType,
Optional<ImageStoreFormat> format);
/**
* Remove images associated with the given organization. This should clear all images that exist for the
......@@ -73,17 +74,33 @@ public interface ImageStoreService {
String webRoot();
@WithDefault("1000000")
long maxSizeInBytes();
@WithDefault("")
String defaultImageUrl();
MaxSizeInBytes maxSizeInBytes();
Compression compression();
@WithDefault("false")
boolean persistToDb();
/**
* Contains the properties regarding max size of saved assets
*
* @author Martin Lowe
*
*/
interface MaxSizeInBytes {
@WithDefault("1000000")
long web();
@WithDefault("64000")
long webPostCompression();
@WithDefault("10000000")
long print();
}
/**
* Represents compression configuration settings.
*
......@@ -93,10 +110,10 @@ public interface ImageStoreService {
interface Compression {
@WithDefault("true")
boolean enabled();
@WithDefault("200")
int maxDimension();
@WithDefault("0.80f")
@Max(1)
float factor();
......
......@@ -51,6 +51,7 @@ import org.eclipsefoundation.persistence.model.RDBMSQuery;
import org.eclipsefoundation.persistence.service.FilterService;
import org.eclipsefoundation.react.helper.ImageFileHelper;
import org.eclipsefoundation.react.namespace.ImageStoreFormat;
import org.eclipsefoundation.react.namespace.ImageStoreFormat.ImageStoreFormats;
import org.eclipsefoundation.react.service.ImageStoreService;
import org.imgscalr.Scalr;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
......@@ -153,20 +154,39 @@ public class DefaultImageStoreService implements ImageStoreService {
// cannot provide image, return null
return null;
}
// compress image and then compare max size
byte[] compressedImage = compress(bytes, mimeType);
if (compressedImage.length > config.maxSizeInBytes() && (!Files.exists(p)
|| !approximatelyMatch((long) compressedImage.length, attrView.readAttributes().size(), 1000))) {
throw new BadRequestException(
"Passed image is larger than allowed size of '" + config.maxSizeInBytes() + "' bytes");
}
// if enabled, update the EclipseDB on logo update when image name is numeric
// max size check is related to max blob size of 64kb
// TODO remove once the Drupal API references this API as this will no longer be needed then
handleDBPersist(fileName, compressedImage, mimeType, format);
if (format.isPresent() && format.get().equals(ImageStoreFormats.PRINT)) {
if (bytes.length > config.maxSizeInBytes().print()) {
throw new BadRequestException("Passed image is larger than allowed size of '"
+ config.maxSizeInBytes().print() + "' bytes");
}
// Any print files should not attempt compression (as they are meant to be big)
return getWebUrl(Files.write(p, bytes));
} else {
if (bytes.length > config.maxSizeInBytes().web()) {
throw new BadRequestException("Passed image is larger than allowed size of '"
+ config.maxSizeInBytes().web() + "' bytes");
}
// compress image and then compare max size
byte[] compressedImage = compress(bytes, mimeType);
if (compressedImage.length > config.maxSizeInBytes().webPostCompression()
&& (!Files.exists(p) || !approximatelyMatch((long) compressedImage.length,
attrView.readAttributes().size(), 1000))) {
throw new BadRequestException("Passed image is larger than allowed size of '"
+ config.maxSizeInBytes().webPostCompression() + "' bytes");
}
// if enabled, update the EclipseDB on logo update when image name is numeric
// max size check is related to max blob size of 64kb
// TODO remove once the Drupal API references this API as this will no longer be needed then
handleDBPersist(fileName, compressedImage, mimeType, format);
// write will create and overwrite file by default if it exists
return getWebUrl(Files.write(p, compress(bytes, mimeType)));
// write the orginal bytes to preserve source file in case of emergency
Files.write(imageStoreRoot.resolve(ImageFileHelper.getFileNameWithExtension(fileName,
Optional.of(ImageStoreFormats.WEB_SRC), mimeType)), bytes);
// write will create and overwrite file by default if it exists
return getWebUrl(Files.write(p, compressedImage));
}
} catch (IOException e) {
throw new ServerErrorException("Could not write image for organization " + fileName,
Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
......@@ -229,8 +249,8 @@ public class DefaultImageStoreService implements ImageStoreService {
// get a ref to the given organization information object
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(DefaultUrlParameterNames.ID.getName(), fileName);
List<OrganizationInformation> infoRefs = dao
.get(new RDBMSQuery<>(new RequestWrapper(), filters.get(OrganizationInformation.class), params));
List<OrganizationInformation> infoRefs = dao.get(
new RDBMSQuery<>(new RequestWrapper(), filters.get(OrganizationInformation.class), params));
// if ref doesn't exist, create one
OrganizationInformation oi;
if (infoRefs.isEmpty()) {
......@@ -247,7 +267,7 @@ public class DefaultImageStoreService implements ImageStoreService {
oi.setSmallMime(mimeType);
dao.add(new RDBMSQuery<>(new RequestWrapper(), filters.get(OrganizationInformation.class)),
Arrays.asList(oi));
}
}
}
......
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