/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ro.nextreports.designer.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.awt.image.ColorModel;
import java.awt.image.DataBufferInt;
import java.util.Properties;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
/**
* @author Decebal Suiu
*/
public class ImageUtil {
private static final Log LOG = LogFactory.getLog(ImageUtil.class);
private static Properties imageNames;
public static final ImageIcon TABLE_IMAGE_ICON;
public static final ImageIcon VIEW_IMAGE_ICON;
public static final ImageIcon COLUMN_IMAGE_ICON;
public static final ImageIcon PROCEDURE_IMAGE_ICON;
public static final ImageIcon PROCEDURE_VALID_IMAGE_ICON;
public static final ImageIcon QUERY_ICON;
public static final ImageIcon QUERY_ERROR_ICON;
public static final ImageIcon REPORT_ICON;
public static final ImageIcon REPORT_ERROR_ICON;
public static final ImageIcon CHART_ICON;
public static final ImageIcon CHART_ERROR_ICON;
public static final String LEFT_ICON_NAME = "left";
public static final String RIGHT_ICON_NAME = "right";
public static final String UP_ICON_NAME = "up";
public static final String DOWN_ICON_NAME = "down";
private static int shadowSize = 5;
private static float shadowOpacity = 0.5f;
private static Color shadowColor = new Color(0x000000);
static {
loadImagesNames();
TABLE_IMAGE_ICON = getImageIcon("table");
VIEW_IMAGE_ICON = getImageIcon("view");
COLUMN_IMAGE_ICON = getImageIcon("column");
PROCEDURE_IMAGE_ICON = getImageIcon("procedure");
PROCEDURE_VALID_IMAGE_ICON = getImageIcon("procedure_valid");
QUERY_ICON = getImageIcon("query");
QUERY_ERROR_ICON = getImageIcon("query_error");
REPORT_ICON = getImageIcon("report");
REPORT_ERROR_ICON = getImageIcon("report_error");
CHART_ICON = getImageIcon("chart");
CHART_ERROR_ICON = getImageIcon("chart_error");
}
public static ImageIcon getImageIcon(String image) {
return getImageIcon(image, true);
}
public static ImageIcon getImageIcon(String image, boolean logError) {
URL url = getImageURL(image, logError);
if (url == null) {
if (logError) {
LOG.error("Cannot load image " + image);
}
return null;
}
return new ImageIcon(url);
}
public static URL getImageURL(String image) {
return getImageURL(image, true);
}
public static URL getImageURL(String image, boolean logError) {
if (!imageNames.containsKey(image)) {
if (logError) {
LOG.error("Cannot find a image file for image '" + image + "'");
}
return null;
}
return ImageUtil.class.getResource("/images/" + getImageName(image));
}
public static BufferedImage getImage(String image) {
URL url = getImageURL(image);
if (url == null) {
LOG.error("Cannot load image " + image);
}
try {
return ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent Pixels
boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
if (hasAlpha) {
transparency = Transparency.BITMASK;
}
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(
image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
// This method returns true if the specified image has transparent pixels
private static boolean hasAlpha(Image image) {
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Get the image's color model
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
private static void applyShadow(BufferedImage image) {
int dstWidth = image.getWidth();
int dstHeight = image.getHeight();
int left = (shadowSize - 1) >> 1;
int right = shadowSize - left;
int xStart = left;
int xStop = dstWidth - right;
int yStart = left;
int yStop = dstHeight - right;
int shadowRgb = shadowColor.getRGB() & 0x00FFFFFF;
int[] aHistory = new int[shadowSize];
int historyIdx = 0;
int aSum;
int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
int lastPixelOffset = right * dstWidth;
float sumDivider = shadowOpacity / shadowSize;
// horizontal pass
for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) {
aSum = 0;
historyIdx = 0;
for (int x = 0; x < shadowSize; x++, bufferOffset++) {
int a = dataBuffer[bufferOffset] >>> 24;
aHistory[x] = a;
aSum += a;
}
bufferOffset -= right;
for (int x = xStart; x < xStop; x++, bufferOffset++) {
int a = (int) (aSum * sumDivider);
dataBuffer[bufferOffset] = a << 24 | shadowRgb;
// substract the oldest pixel from the sum
aSum -= aHistory[historyIdx];
// get the lastest pixel
a = dataBuffer[bufferOffset + right] >>> 24;
aHistory[historyIdx] = a;
aSum += a;
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
}
// vertical pass
for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
aSum = 0;
historyIdx = 0;
for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) {
int a = dataBuffer[bufferOffset] >>> 24;
aHistory[y] = a;
aSum += a;
}
bufferOffset -= lastPixelOffset;
for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) {
int a = (int) (aSum * sumDivider);
dataBuffer[bufferOffset] = a << 24 | shadowRgb;
// substract the oldest pixel from the sum
aSum -= aHistory[historyIdx];
// get the lastest pixel
a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24;
aHistory[historyIdx] = a;
aSum += a;
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
}
}
private static BufferedImage prepareImage(BufferedImage image) {
BufferedImage subject = new BufferedImage(image.getWidth() + shadowSize * 2,
image.getHeight() + shadowSize * 2,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = subject.createGraphics();
g2.drawImage(image, null, shadowSize, shadowSize);
g2.dispose();
return subject;
}
private static BufferedImage createDropShadow(BufferedImage image) {
BufferedImage subject = prepareImage(image);
applyShadow(subject);
return subject;
}
private static Dimension computeShadowPosition(double angle, int distance) {
double angleRadians = Math.toRadians(angle);
int distance_x = (int) (Math.cos(angleRadians) * distance);
int distance_y = (int) (Math.sin(angleRadians) * distance);
return new Dimension(distance_x, distance_y);
}
public static void drawImage(String imageName, boolean withShadow, Graphics2D g2, int x, int y) {
BufferedImage img = toBufferedImage(getImage(imageName));
g2.drawImage(img, null, x, y);
if (withShadow) {
BufferedImage shadow = createDropShadow(img);
if (shadow != null) {
Dimension d = ImageUtil.computeShadowPosition(30, 5);
g2.drawImage(shadow, x + (int) d.getWidth(), y + (int) d.getHeight(), null);
}
}
}
private static void loadImagesNames() {
if (imageNames == null) {
imageNames = new Properties();
try {
imageNames.load(ImageUtil.class.getResourceAsStream("/images.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getImageName(String imageKey) {
return imageNames.getProperty(imageKey);
}
}