Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java')
-rw-r--r--org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java298
1 files changed, 298 insertions, 0 deletions
diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java
new file mode 100644
index 000000000..18a12e791
--- /dev/null
+++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java
@@ -0,0 +1,298 @@
+/****************************************************************************
+ * Copyright (c) 2017, 2018 Remain Software
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation
+ *****************************************************************************/
+package org.eclipse.tips.core;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Base64;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tips.core.internal.ImageUtil;
+
+/**
+ * Provides more information about the image to be used in the tip. The image
+ * aspect ratio must be around 3:2 to be comfortably displayed in the Tip UI.
+ *
+ */
+public class TipImage {
+
+ private static final double THREE_TO_TWO = 1.5;
+
+ /**
+ * Value to indicate that the height or width are to be determined by the Tip
+ * framework.
+ */
+ public static final int UNDEFINED = -1;
+
+ private String fExtension = null;
+ private int fMaxWidth = UNDEFINED;
+ private int fMaxHeight = UNDEFINED;
+ final private URL fURL;
+ private double fAspectRatio = THREE_TO_TWO;
+
+ final private String fBase64Image;
+
+ private static final int _4KB = 4096;
+
+ /**
+ * Creates a new TipImage with the specified URL which gets read into a base 64
+ * string.
+ *
+ * @param url
+ * the image URL which may not be null
+ * @throws IOException
+ * in case the stream of the passed URL could not be opened or read.
+ *
+ */
+ public TipImage(URL url) throws IOException {
+ Assert.isNotNull(url);
+ fURL = url;
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] chunk = new byte[_4KB];
+ int bytesRead;
+ InputStream stream = url.openStream();
+ while ((bytesRead = stream.read(chunk)) > 0) {
+ outputStream.write(chunk, 0, bytesRead);
+ }
+ fBase64Image = "data:image/" //
+ + getExtension() //
+ + ";base64," //
+ + Base64.getEncoder().encodeToString(outputStream.toByteArray());
+ }
+
+ /**
+ * @return true if the URL constructor was used and not the base64 constructor.
+ */
+ public boolean isURLSet() {
+ return fURL != null;
+ }
+
+ /**
+ * Creates a new {@link TipImage} with the specified base64 string which must be
+ * a valid RFC-2397 string thats begins with
+ * <code>"data:image/&lt;subtype&gt;;base64"</code> where <code>subtype</code>
+ * must be a valid image type (pmg, bmp, gif, etc..).
+ *
+ * @param base64Image
+ * the non-null base64 encoded image according to RFC-2397.
+ *
+ * @throws RuntimeException
+ * if the string is not valid
+ * @see TipImage
+ * @see <a href="https://tools.ietf.org/search/rfc2397">RFC-2397
+ * (https://tools.ietf.org/search/rfc2397)</a>
+ *
+ */
+ public TipImage(String base64Image) {
+ Assert.isNotNull(base64Image);
+ fURL = null;
+ if (base64Image.matches("^data:image\\/.*?;base64,.*$")) {
+ fBase64Image = base64Image;
+ int from = base64Image.indexOf("/") + 1;
+ int to = base64Image.indexOf(";");
+ setExtension(base64Image.substring(from, to).trim());
+ setExtension(base64Image.substring(from, to).trim());
+ } else {
+ int length = base64Image.length();
+ throw new RuntimeException("Wrong base64 data " + base64Image.substring(0, length < 50 ? length : 50));
+ }
+ }
+
+ /**
+ * Sets the maximum height that this image can display. For example, if you have
+ * a 32x32 image the framework will blow it up to a larger size which will not
+ * work for the image and you might want to pass 64 to indicate that the image
+ * cannot be resized passed 64 pixels. If the height is not set or set to
+ * {@link #UNDEFINED}, then it is automatically resized based on aspect ratio
+ * and maximum width.
+ *
+ * @param maxHeight
+ * the maximum height for this image or {@link #UNDEFINED}
+ * @return this
+ * @see #setAspectRatio(double)
+ * @see #setAspectRatio(int, int, boolean)
+ * @see #setMaxWidth(int)
+ */
+ public TipImage setMaxHeight(int maxHeight) {
+ fMaxHeight = maxHeight;
+ return this;
+ }
+
+ /**
+ * Sets the maximum width that this image can display. For example, if you have
+ * a 32x32 image the framework will blow it up to a larger size which will not
+ * work for the image and you might want to pass 64 to indicate that the image
+ * cannot be resized passed 64 pixels. If the width is not set or set to
+ * {@link #UNDEFINED}, it is automatically resized based on aspect ratio and
+ * maximum height.
+ *
+ * @param maxWidth
+ * the maximum width for this image or {@link #UNDEFINED}
+ * @return this
+ * @see #setAspectRatio(double)
+ * @see #setAspectRatio(int, int, boolean)
+ * @see #setMaxHeight(int)
+ */
+ public TipImage setMaxWidth(int maxWidth) {
+ fMaxWidth = maxWidth;
+ return this;
+ }
+
+ /**
+ * Sets the aspect ratio of this image. If the image is 300 wide and 600 high
+ * then the aspect ratio is 300/600 = 0,5 (1:2). If your image is 1200 wide and
+ * 250 high then the aspect ratio (1200/250) = 4,8. With the supplied values the
+ * best dimensions for the image can be calculated give the available space in
+ * the UI.
+ * <p>
+ * In case you pass true for <code>pSetAsMax</code> then the image can not be
+ * up-scaled beyond the specified size. So if your image is 200x200 and you want
+ * a maximum up-scale of 2 then pass 400x400 to this method to maintain the
+ * aspect ratio but allow the image to be resized to maximum it's double size.
+ * <p>
+ * The recommended aspect ratio is around 3:2 (1.5) to be comfortably displayed
+ * in the Tip UI.
+ *
+ * @param width
+ * the width of the image, must be greater than 0
+ * @param height
+ * the height of the image, must be greater than 0
+ * @param setAsMax
+ * true to set the passed width and height as the maximum width and
+ * height for the image
+ * @return this
+ * @see #setAspectRatio(double)
+ * @see #getIMGAttributes(int, int)
+ * @see #setMaxHeight(int)
+ * @see #setMaxWidth(int)
+ */
+ public TipImage setAspectRatio(int width, int height, boolean setAsMax) {
+ Assert.isTrue(width > 0);
+ Assert.isTrue(height > 0);
+ fAspectRatio = (double) width / (double) height;
+ if (setAsMax) {
+ setMaxHeight(height);
+ setMaxWidth(width);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the aspect ratio of your image which is defined by width divided by
+ * height.
+ * <p>
+ * The recommended aspect ratio is around 3:2 (1.5) to be comfortably displayed
+ * in the Tip UI.
+ *
+ *
+ * @param aspectRatio
+ * the aspect ration
+ * @return this
+ * @see #setAspectRatio(int, int, boolean)
+ * @see #getIMGAttributes(int, int)
+ */
+ public TipImage setAspectRatio(double aspectRatio) {
+ fAspectRatio = aspectRatio;
+ return this;
+ }
+
+ /**
+ * Changes the default value "null" to the passed value which commonly is "png",
+ * "gif" and such.
+ *
+ * @param extension
+ * the extension of this file
+ * @return this
+ * @see #getExtension()
+ */
+ public TipImage setExtension(String extension) {
+ fExtension = extension;
+ return this;
+ }
+
+ /**
+ * Returns the base64 encoded image string according to RFC-2397 or null. The
+ * recommended aspect ratio is around 3:2.
+ *
+ * @return the base64 encoded image string according to RFC-2397 or null
+ */
+ public String getBase64Image() {
+ return fBase64Image;
+ }
+
+ /**
+ * Returns the width and height attributes of the HTML IMG tag.
+ *
+ * <pre>
+ * &lt;img src="smiley.gif" height="42" width="42"&gt;
+ * </pre>
+ *
+ * The available space in the UI is passed and with it the best size of the
+ * image will be calculated based on the aspect ratio of this image.
+ *
+ * Clients may override if they can provide better information.
+ *
+ * @param widthHint
+ * the available width which must be greater than 0
+ * @param heightHint
+ * the available height which must be greater than 0
+ * @return the attributes in the HTML img tag
+ * @see TipImage#setAspectRatio(double)
+ * @see TipImage#setAspectRatio(int, int, boolean)
+ * @see TipImage#setMaxHeight(int)
+ * @see TipImage#setMaxWidth(int)
+ */
+ public String getIMGAttributes(int widthHint, int heightHint) {
+
+ int myWidthHint = (fMaxWidth == UNDEFINED) ? widthHint : Math.min(widthHint, fMaxWidth);
+ int myHeightHint = (fMaxHeight == UNDEFINED) ? heightHint : Math.min(heightHint, fMaxHeight);
+
+ int width = ImageUtil.getWidth(fAspectRatio, myWidthHint, myHeightHint);
+ int height = ImageUtil.getHeight(fAspectRatio, myWidthHint, myHeightHint);
+
+ String result = "";
+ if (fMaxWidth == UNDEFINED) {
+ result += " width=\"" + width + "\"";
+ } else {
+ result += " width=\"" + Math.min(fMaxWidth, width) + "\"";
+ }
+
+ if (fMaxHeight == UNDEFINED) {
+ result += " height=\"" + height + "\"";
+ } else {
+ result += " height=\"" + Math.min(fMaxHeight, height) + "\"";
+ }
+ return result;
+ }
+
+ /**
+ * Returns the image extension for use in the IMG tag for the data attribute
+ * (<code>data:image/???</code>). If the extension is not set in this object,
+ * then the URL is examined to find the extension. If that can not be determined
+ * then "png" is returned.
+ *
+ * @return the extension
+ */
+ private String getExtension() {
+ if (fExtension != null) {
+ return fExtension;
+ }
+ String[] split = fURL.getPath().split("\\.");
+ if (split.length > 1) {
+ fExtension = split[split.length - 1];
+ } else {
+ fExtension = "png";
+ }
+ return fExtension;
+ }
+} \ No newline at end of file

Back to the top