From 7218f83513cf8337a3cca24b4cf99864232a7b23 Mon Sep 17 00:00:00 2001
From: Jan Sladek <Jan.Sladek@mni.thm.de>
Date: Tue, 10 Mar 2015 16:24:00 +0100
Subject: [PATCH] Worked on #15324. Added rescale capabilities and thumbnail
 field in DB

---
 src/main/java/de/thm/arsnova/ImageUtils.java  | 75 +++++++++++++++++++
 .../java/de/thm/arsnova/dao/CouchDBDao.java   |  3 +
 .../java/de/thm/arsnova/entities/Answer.java  |  9 +++
 3 files changed, 87 insertions(+)

diff --git a/src/main/java/de/thm/arsnova/ImageUtils.java b/src/main/java/de/thm/arsnova/ImageUtils.java
index f291f8234..3c8cf374f 100644
--- a/src/main/java/de/thm/arsnova/ImageUtils.java
+++ b/src/main/java/de/thm/arsnova/ImageUtils.java
@@ -17,12 +17,16 @@
  */
 package de.thm.arsnova;
 
+import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.imageio.ImageIO;
 
@@ -40,6 +44,9 @@ public class ImageUtils {
 
 	// Or whatever size you want to read in at a time.
 	private static final int CHUNK_SIZE = 4096;
+	
+	public static final Pattern BASE64_IMAGE_PREFIX_PATTERN = Pattern.compile("data:image/(.*);base64,(.*)");
+	
 
 	private ImageUtils() {
 	}
@@ -72,6 +79,74 @@ public class ImageUtils {
 
 		return null;
 	}
+	
+	/**
+	 * Checks if a String starts with the base 64 prefix.
+	 * 
+	 * @param maybeImage The Image as a base64 encoded {@link String} 
+	 * @return true if the string is a potentially a base 64 encoded image.
+	 */
+	public static boolean isBase64EncodedImage(String maybeImage) {
+		if (maybeImage == null) {
+			return false;
+		}
+		else if (maybeImage.isEmpty()) {
+			return false;
+		}
+		else
+			return BASE64_IMAGE_PREFIX_PATTERN.matcher(maybeImage).matches();
+	}
+	
+	public static String rescaleImage(String originalImageString, final int width, final int height) {
+		if (!isBase64EncodedImage(originalImageString)) return null;
+		else {
+			Matcher imageMatcher = BASE64_IMAGE_PREFIX_PATTERN.matcher(originalImageString);
+			if (!imageMatcher.find()) {
+				// shouldn't ever happen, because the regex is already checked.
+				return null;
+			}
+			String extension = imageMatcher.group(1);
+			String base64String = imageMatcher.group(2);
+			
+			byte[] imageData = Base64.decodeBase64(base64String);
+			try {
+				BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
+				BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+				Graphics2D g = newImage.createGraphics();
+				
+				final double ratio = ((double) originalImage.getWidth()) / ((double) originalImage.getHeight());
+				
+				int x = 0, y = 0, w = width, h = height;
+				if (originalImage.getWidth() > originalImage.getHeight()) {
+					final int newWidth = (int) Math.round((float) height * ratio);
+					x = -(newWidth - width) >> 1;
+					w = newWidth;
+				} else if (originalImage.getWidth() < originalImage.getHeight()) {
+					final int newHeight = (int) Math.round((float) width / ratio);
+					y = -(newHeight - height) >> 1;
+					h = newHeight;
+				}
+				g.drawImage(originalImage, x, y, w, h, null);
+				g.dispose();
+				
+				StringBuilder result = new StringBuilder();
+				result.append("data:image/");
+				result.append(extension);
+				result.append(";base64,");
+				
+				ByteArrayOutputStream output = new ByteArrayOutputStream();
+				ImageIO.write(newImage, extension, output);
+				
+				output.flush();
+				output.close();
+				
+				return Base64.encodeBase64String(output.toByteArray());
+			} catch (IOException e) {
+				LOGGER.error(e.getLocalizedMessage());
+				return null;
+			}
+		}
+	}
 
 	/**
 	 * Gets the bytestream of an image url.
diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java
index 13ad2949e..1e2b29a3a 100644
--- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java
+++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java
@@ -1257,6 +1257,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware
 		a.put("piRound", answer.getPiRound());
 		a.put("abstention", answer.isAbstention());
 		a.put("answerImage", answer.getAnswerImage());
+		a.put("answerThumbnailImage", answer.getAnswerThumbnailImage());
 		AnswerQueueElement answerQueueElement = new AnswerQueueElement(session, question, answer, user);
 		this.answerQueue.offer(new AbstractMap.SimpleEntry<Document, AnswerQueueElement>(a, answerQueueElement));
 		return answer;
@@ -1306,6 +1307,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware
 			a.put("abstention", answer.isAbstention());
 			a.put("questionValue", answer.getQuestionValue());
 			a.put("answerImage", answer.getAnswerImage());
+			
+			a.put("answerThumbnailImage", answer.getAnswerThumbnailImage());
 			database.saveDocument(a);
 			answer.set_rev(a.getRev());
 			return answer;
diff --git a/src/main/java/de/thm/arsnova/entities/Answer.java b/src/main/java/de/thm/arsnova/entities/Answer.java
index 33d5b349a..5d7023eea 100644
--- a/src/main/java/de/thm/arsnova/entities/Answer.java
+++ b/src/main/java/de/thm/arsnova/entities/Answer.java
@@ -37,6 +37,7 @@ public class Answer {
 	private boolean abstention;
 	private int abstentionCount;
 	private String answerImage;
+	private String answerThumbnailImage;
 
 	public Answer() {
 		this.type = "skill_question_answer";
@@ -121,6 +122,14 @@ public class Answer {
 	public void setAnswerImage(String answerImage) {
 		this.answerImage = answerImage;
 	}
+	
+	public String getAnswerThumbnailImage() {
+		return answerThumbnailImage;
+	}
+	
+	public void setAnswerThumbnailImage(String answerThumbnailImage) {
+		this.answerThumbnailImage = answerThumbnailImage;
+	}
 
 	public final void setUser(final String user) {
 		this.user = user;
-- 
GitLab