Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/97 add svg support using salamander #895

Merged
merged 2 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ dependencies {
compile "com.openhtmltopdf:openhtmltopdf-core:1.0.2"
compile "com.openhtmltopdf:openhtmltopdf-pdfbox:1.0.2"
compile "ch.digitalfondue.jfiveparse:jfiveparse:0.7.1"
compile "guru.nidi.com.kitfox:svgSalamander:1.1.3"
/**/
compile "com.google.zxing:core:3.4.0"
compile "com.google.zxing:javase:3.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,36 @@
import alfio.manager.FileUploadManager;
import alfio.model.modification.UploadBase64FileModification;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;

import org.imgscalr.Scalr;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;

import com.kitfox.svg.SVGUniverse;
import com.kitfox.svg.app.beans.SVGIcon;

import javax.imageio.ImageIO;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;

@RestController
@RequestMapping("/admin/api")
@Log4j2
public class FileUploadApiController {

private static final MimeType MIME_TYPE_IMAGE_SVG = MimeTypeUtils.parseMimeType("image/svg+xml");

private static final int IMAGE_THUMB_MAX_WIDTH_PX = 500;
private static final int IMAGE_THUMB_MAX_HEIGHT_PX = 500;

private final FileUploadManager fileUploadManager;

@Autowired
Expand All @@ -45,30 +59,69 @@ public FileUploadApiController(FileUploadManager fileUploadManager) {
@PostMapping("/file/upload")
public ResponseEntity<String> uploadFile(@RequestParam(required = false, value = "resizeImage", defaultValue = "false") Boolean resizeImage,
@RequestBody UploadBase64FileModification upload) {
try {

if (Boolean.TRUE.equals(resizeImage)) {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(upload.getFile()));
//resize only if the image is bigger than 500px on one of the side
if(image.getWidth() > 500 || image.getHeight() > 500) {
UploadBase64FileModification resized = new UploadBase64FileModification();
BufferedImage thumbImg = Scalr.resize(image, Scalr.Method.QUALITY, Scalr.Mode.AUTOMATIC, 500, 500, Scalr.OP_ANTIALIAS);
ByteArrayOutputStream baos = new ByteArrayOutputStream();

ImageIO.write(thumbImg, StringUtils.substringAfter(upload.getType(), "/"), baos);

resized.setFile(baos.toByteArray());
resized.setAttributes(upload.getAttributes());
resized.setName(upload.getName());
resized.setType(upload.getType());
upload = resized;
}
try {
final var mimeType = MimeTypeUtils.parseMimeType(upload.getType());
if (MIME_TYPE_IMAGE_SVG.equalsTypeAndSubtype(mimeType)) {
upload = rasterizeSVG(upload, resizeImage);
} else if (Boolean.TRUE.equals(resizeImage)) {
upload = resize(upload, mimeType);
}

return ResponseEntity.ok(fileUploadManager.insertFile(upload));
} catch (Exception e) {
log.error("error while uploading image", e);
return ResponseEntity.badRequest().build();
}
}

private UploadBase64FileModification resize(UploadBase64FileModification upload, MimeType mimeType) throws IOException {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(upload.getFile()));
//resize only if the image is bigger than 500px on one of the side
if(image.getWidth() > IMAGE_THUMB_MAX_WIDTH_PX || image.getHeight() > IMAGE_THUMB_MAX_HEIGHT_PX) {
UploadBase64FileModification resized = new UploadBase64FileModification();
BufferedImage thumbImg = Scalr.resize(image, Scalr.Method.QUALITY, Scalr.Mode.AUTOMATIC, IMAGE_THUMB_MAX_WIDTH_PX, IMAGE_THUMB_MAX_HEIGHT_PX, Scalr.OP_ANTIALIAS);
try (final var baos = new ByteArrayOutputStream()) {
ImageIO.write(thumbImg, mimeType.getSubtype(), baos);
resized.setFile(baos.toByteArray());
}
resized.setAttributes(upload.getAttributes());
resized.setName(upload.getName());
resized.setType(upload.getType());
return resized;
}
return upload;
}

private UploadBase64FileModification rasterizeSVG(UploadBase64FileModification upload, Boolean resizeImage) throws IOException {

final SVGUniverse uni = new SVGUniverse();
final URI uri = uni.loadSVG(upload.getInputStream(), "_");
// use apply 10% margin to prevent final image size to exceed max allowed size
final int maxWidthWithMargin = (int) (IMAGE_THUMB_MAX_WIDTH_PX * 0.9);
final int maxHeightWithMargin = (int) (IMAGE_THUMB_MAX_HEIGHT_PX * 0.9);

final SVGIcon icon = new SVGIcon();
icon.setSvgUniverse(uni);
icon.setSvgURI(uri);
icon.setAntiAlias(true);
if(icon.getIconWidth() > maxHeightWithMargin || icon.getIconHeight() > maxHeightWithMargin) {
emassip marked this conversation as resolved.
Show resolved Hide resolved
icon.setAutosize(SVGIcon.AUTOSIZE_STRETCH);
icon.setPreferredSize(new Dimension(Math.min(maxWidthWithMargin, icon.getIconWidth()), Math.min(maxHeightWithMargin, icon.getIconHeight())));
}
final BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
icon.paintIcon(null, bi.createGraphics(), 0, 0);

final UploadBase64FileModification rasterized = new UploadBase64FileModification();
try (final var baos = new ByteArrayOutputStream()) {
ImageIO.write(bi, "PNG", baos);
rasterized.setFile(baos.toByteArray());
}
rasterized.setAttributes(upload.getAttributes());
rasterized.setName(upload.getName() + ".png");
rasterized.setType(MimeTypeUtils.IMAGE_PNG_VALUE);

uni.removeDocument(uri);

return rasterized;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ <h3>URLs Configuration</h3>
</div>
<div class="page-header">
<h3>Logo</h3>
<small class="text-muted">Upload the event logo in PNG or JPG format.</small>
<small class="text-muted">Upload the event logo in PNG, JPG or SVG format.</small>
</div>
<div class="row">
<div class="col-xs-6">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,8 @@
};
if (files.length <= 0) {
alert('Your image not uploaded correctly.Please upload the image again');
} else if (!((files[0].type === 'image/png') || (files[0].type === 'image/jpeg'))) {
alert('only png or jpeg files are accepted');
} else if (!((files[0].type === 'image/png') || (files[0].type === 'image/jpeg') || (files[0].type === 'image/svg+xml'))) {
alert('Only PNG, JPG or SVG image files are accepted');
} else if (files[0].size > (1024 * 200)) {
alert('Image size exceeds the allowable limit 200KB');
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Alf.io currently supports the following formats:

- PNG
- JPG

- SVG

## Seats and payment info

Expand Down