From 2e6993df433ee36e946a3ddf1983d4a2affcf8fa Mon Sep 17 00:00:00 2001 From: Vipin Date: Mon, 20 Mar 2017 22:22:09 +0530 Subject: [PATCH] Fix for improvement: SPARK-1872. Added new image cropping library. Implemented resizing of large images. --- core/pom.xml | 5 ++ .../sparkimpl/profile/AvatarPanel.java | 73 ++++++++++++++----- .../sparkimpl/profile/VCardEditor.java | 13 +--- 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index ddc8426a8..042403d14 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -217,6 +217,11 @@ 4.8.2 test + + net.coobird + thumbnailator + 0.4.8 + diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/profile/AvatarPanel.java b/core/src/main/java/org/jivesoftware/sparkimpl/profile/AvatarPanel.java index 928bcc609..de83e1761 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/profile/AvatarPanel.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/profile/AvatarPanel.java @@ -16,12 +16,17 @@ package org.jivesoftware.sparkimpl.profile; import org.jivesoftware.resource.Res; +import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.util.GraphicUtils; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.URLFileSystem; import org.jivesoftware.spark.util.log.Log; +import net.coobird.thumbnailator.Thumbnails; +import net.coobird.thumbnailator.geometry.Positions; + +import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.ImageIcon; @@ -42,6 +47,8 @@ import java.awt.Image; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; @@ -172,7 +179,7 @@ public class AvatarPanel extends JPanel implements ActionListener { changeAvatar(file, this); } else { - UIManager.put("OptionPane.okButtonText", Res.getString("ok")); + UIManager.put("OptionPane.okButtonText", Res.getString("ok")); JOptionPane.showMessageDialog(this, "Please choose a valid image file.", Res.getString("title.error"), JOptionPane.ERROR_MESSAGE); } @@ -182,24 +189,12 @@ public class AvatarPanel extends JPanel implements ActionListener { private void changeAvatar(final File selectedFile, final Component parent) { SwingWorker worker = new SwingWorker() { - public Object construct() { - try { - ImageIcon imageOnDisk = new ImageIcon(selectedFile.getCanonicalPath()); - Image avatarImage = imageOnDisk.getImage(); - if (avatarImage.getHeight(null) > 128 || avatarImage.getWidth(null) > 128) { - avatarImage = avatarImage.getScaledInstance(-1, 128, Image.SCALE_SMOOTH); - } - return avatarImage; - } - catch (IOException ex) { - Log.error(ex); - } - return null; + public Object construct() { + return cropImageFile(selectedFile); } public void finished() { - Image avatarImage = (Image)get(); - + BufferedImage avatarImage = (BufferedImage)get(); /* // Check size. long length = GraphicUtils.getBytesFromImage(avatarImage).length * 8; @@ -214,8 +209,14 @@ public class AvatarPanel extends JPanel implements ActionListener { return; } */ - setAvatar(new ImageIcon(avatarImage)); - avatarFile = selectedFile; + //convert BufferedImage to bytes + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ImageIO.write(avatarImage, "png", baos); + setAvatar(new ImageIcon(avatarImage)); + setAvatarBytes(baos.toByteArray()); + } catch (IOException ex) { + Log.error(ex); + } } }; @@ -291,7 +292,43 @@ public class AvatarPanel extends JPanel implements ActionListener { this.dlg = dialog; } + /* + * Crop the given image file to the target dimensions + * without changing aspect ratio. + * Returns modified image as BufferedImage. + */ + private BufferedImage cropImageFile(File selectedFile) { + int targetImageWidth = 64; + int targetImageHeight = 64; + + BufferedImage croppedImage = null; + try { + BufferedImage avatarImageBuffered = ImageIO.read(selectedFile); + int currentImageWidth = avatarImageBuffered.getWidth(null); + int currentImageHeight = avatarImageBuffered.getHeight(null); + + if (currentImageHeight == targetImageHeight && currentImageWidth == targetImageHeight) { + //no need to crop + croppedImage = avatarImageBuffered; + } else { + double targetImageRatio = (double)targetImageWidth / (double)targetImageHeight; + + if (currentImageWidth < targetImageRatio * currentImageHeight) { + currentImageHeight = new Double((double)currentImageWidth / (double)targetImageRatio).intValue(); + } else { + currentImageWidth = new Double(((double)currentImageHeight * targetImageRatio)).intValue(); + } + //crop image in the center + croppedImage = Thumbnails.of(avatarImageBuffered).sourceRegion(Positions.CENTER, currentImageWidth, currentImageHeight). + size(targetImageWidth, targetImageHeight).asBufferedImage(); + } + + } catch (IOException ex) { + Log.error(ex); + } + return croppedImage; + } } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/profile/VCardEditor.java b/core/src/main/java/org/jivesoftware/sparkimpl/profile/VCardEditor.java index 00be38912..e10e99bc4 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/profile/VCardEditor.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/profile/VCardEditor.java @@ -442,19 +442,8 @@ public class VCardEditor { vcard.setPhoneHome("CELL", homePanel.getMobile()); // Save Avatar - final File avatarFile = avatarPanel.getAvatarFile(); byte[] avatarBytes = avatarPanel.getAvatarBytes(); - if (avatarFile != null) { - avatarBytes = GraphicUtils.getBytesFromImage(avatarFile); - ImageIcon icon = new ImageIcon(avatarBytes); - Image image = icon.getImage(); - if (icon.getIconHeight() > 128 || icon.getIconWidth() > 128) { - image = image.getScaledInstance(-1, 128, Image.SCALE_SMOOTH); - } - - } - // If avatar bytes, persist as vcard. if (avatarBytes != null) { vcard.setAvatar(avatarBytes); @@ -467,7 +456,7 @@ public class VCardEditor { vcard.save(SparkManager.getConnection()); // Notify users. - if (avatarFile != null || avatarBytes != null) { + if (avatarBytes != null) { Presence presence = SparkManager.getWorkspace().getStatusBar() .getPresence(); Presence newPresence = new Presence(presence.getType(),