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

Fix SVG files not having a thumbnail #706

Merged
merged 5 commits into from
Aug 17, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static Type fromString( String string ) {
/**
* image/svg+xml
*/
public static final MediaType SVG_UTF_8 = imageUtf8( "svg+xml" );
public static final MediaType SVG_UTF_8 = imageUtf8( "svg+xml; charset=utf-8" );

/**
* text/plain
Expand Down
2 changes: 2 additions & 0 deletions jgiven-html5-report/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ plugins {
dependencies {
implementation project(':jgiven-core')
implementation project(':jgiven-html-app')
implementation 'org.apache.xmlgraphics:batik-transcoder:1.14'
implementation 'org.apache.xmlgraphics:batik-codec:1.14'
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.tngtech.jgiven.report.html5;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.util.List;
import java.util.Set;

import javax.imageio.ImageIO;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -145,7 +147,11 @@ private File writeFile( AttachmentModel attachment, MediaType mediaType ) {
}
Files.write( BaseEncoding.base64().decode( attachment.getValue() ), targetFile );
} else {
Files.write( attachment.getValue(), targetFile, Charsets.UTF_8 );
Files.write(attachment.getValue().getBytes(Charsets.UTF_8), targetFile);
if (attachment.getMediaType().equals(com.tngtech.jgiven.attachment.MediaType.SVG_UTF_8.toString())) {
andru47 marked this conversation as resolved.
Show resolved Hide resolved
File thumbFile = getThumbnailFileFor(targetFile);
writeThumbnailForSVG(targetFile, thumbFile);
}
}
} catch( IOException e ) {
log.error( "Error while trying to write attachment to file " + targetFile, e );
Expand Down Expand Up @@ -195,4 +201,78 @@ private byte[] bufferedImageToBase64( BufferedImage bi, String extension ) {
}
return imageArray;
}

private void writeThumbnailForSVG(File initialSVG, File thumbnailSVG) {
String base64PNGImage = getPNGFromSVG(initialSVG);
byte[] scaledDownInBytes = compressToThumbnail(base64PNGImage, "png");
Dimension imageDimension = getImageDimension(scaledDownInBytes);
String base64ScaledDownContent = BaseEncoding.base64().encode(scaledDownInBytes);
createSVGThumbFile(thumbnailSVG, base64ScaledDownContent, imageDimension);
}

Dimension getImageDimension(byte[] givenImage) {
ByteArrayInputStream bais = new ByteArrayInputStream(givenImage);
Dimension dimension = new Dimension();
try {
BufferedImage image = ImageIO.read(bais);
dimension.height = image.getHeight();
dimension.width = image.getWidth();
} catch (IOException e) {
log.error("The converted png image cannot be read.");
}

return dimension;
}

void createSVGThumbFile(File targetFile, String base64Image, Dimension dimension) {
String xmlFormat = getXMLFormat(base64Image, dimension);
try {
FileWriter fileWriter = new FileWriter(targetFile);
fileWriter.write(xmlFormat);
fileWriter.close();
andru47 marked this conversation as resolved.
Show resolved Hide resolved
} catch (IOException e) {
log.error("Error writing the thumbnail svg to " + targetFile);
}
}

private String getXMLFormat(String base64Image, Dimension dimension) {
return "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
"height=\"" + dimension.getHeight() + "px\" width=\"" + dimension.getWidth() + "px\">"+
"<image height=\"100%\" width=\"100%\" xlink:href=\"data:image/png;base64, " + base64Image + "\"/>" +
"</svg>";
}

String getPNGFromSVG(File givenSVG) {
PNGTranscoder transcoder = new PNGTranscoder();
TranscoderInput transcoderInput = new TranscoderInput();
TranscoderOutput transcoderOutput = new TranscoderOutput();

FileInputStream fis = null;
try {
fis = new FileInputStream(givenSVG);
} catch (FileNotFoundException e) {
log.error("Error while reading the initial svg file.");
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();

transcoderInput.setInputStream(fis);
transcoderOutput.setOutputStream(baos);

try {
transcoder.transcode(transcoderInput, transcoderOutput);
} catch (TranscoderException e) {
e.printStackTrace();
log.error("Error while transcoding the svg file to png. Is the svg formatted correctly?");
andru47 marked this conversation as resolved.
Show resolved Hide resolved
return null;
}

try {
fis.close();
andru47 marked this conversation as resolved.
Show resolved Hide resolved
} catch (IOException e) {
log.error("Error closing the {} file", givenSVG);
}

return BaseEncoding.base64().encode(baos.toByteArray());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import static com.tngtech.jgiven.report.html5.Html5AttachmentGenerator.scaleDown;
import static org.assertj.core.api.Assertions.assertThat;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.imageio.ImageIO;

Expand Down Expand Up @@ -87,6 +87,42 @@ public void testFindingAndGeneratingAttachmentsInAllSteps() throws IOException {

}

@Test
public void testGetImageDimensions() {
Html5AttachmentGenerator generator = new Html5AttachmentGenerator(temporaryFolderRule.getRoot());
assertThat(generator.getImageDimension(BINARY_SAMPLE)).isEqualTo(new Dimension(22, 22));
}

@Test
public void testPNGConvertor() {
Html5AttachmentGenerator generator = new Html5AttachmentGenerator(temporaryFolderRule.getRoot());
andru47 marked this conversation as resolved.
Show resolved Hide resolved
File sampleSVG = new File("src/test/resources/SampleSVG.svg");
String pngContent = generator.getPNGFromSVG(sampleSVG);

assertThat(generator.getImageDimension(BaseEncoding.base64().decode(pngContent)))
.isEqualTo(new Dimension(25, 25));
}

@Test
public void testSVGFilesHaveAGeneratedThumbnail() throws IOException {
Html5AttachmentGenerator generator = new Html5AttachmentGenerator(temporaryFolderRule.getRoot());
File sampleSVG = new File("src/test/resources/SampleSVG.svg");
Attachment sampleSVGAttachment= Attachment.fromTextFile(sampleSVG, MediaType.SVG_UTF_8)
.withFileName("SampleSVG");
StepModel stepModel = new StepModel("svgTest", Lists.newArrayList());
stepModel.addAttachment(sampleSVGAttachment);

generator.visit(stepModel);

File svgThumbnail = new File( temporaryFolderRule.getRoot().getPath() +
"/SampleSVG-thumb.svg" );

String pngContent = generator.getPNGFromSVG(svgThumbnail);

assertThat(generator.getImageDimension(BaseEncoding.base64().decode(pngContent)))
.isEqualTo(new Dimension(MINIMAL_THUMBNAIL_SIZE, MINIMAL_THUMBNAIL_SIZE));
}

private ReportModel generateReportModelWithAttachments() {
Attachment nestedAttachment = Attachment.fromBinaryBytes( BINARY_SAMPLE, MediaType.GIF ).withFileName( "nestedAttachment" );
Attachment parentAttachment = Attachment.fromBinaryBytes( BINARY_SAMPLE, MediaType.GIF ).withFileName( "parentAttachment" );
Expand Down
3 changes: 3 additions & 0 deletions jgiven-html5-report/src/test/resources/SampleSVG.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.