/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed 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 org.jkiss.dbeaver.ui;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
/**
* Image-related utils
*
* <p/>
* Web image transformation originally get from org.eclipse.gmf.runtime.diagram.ui.render.util.CopyToImageUtil
*
* Web image transformation by Anthony Hunter, cmahoney
*/
public class ImageUtils {
private static Image imageCheckboxEnabledOn, imageCheckboxEnabledOff, imageCheckboxDisabledOn, imageCheckboxDisabledOff;
public static Image getImageCheckboxEnabledOn()
{
if (imageCheckboxEnabledOn == null) {
initImages();
}
return imageCheckboxEnabledOn;
}
public static Image getImageCheckboxEnabledOff()
{
if (imageCheckboxEnabledOff == null) {
initImages();
}
return imageCheckboxEnabledOff;
}
public static Image getImageCheckboxDisabledOn()
{
if (imageCheckboxDisabledOn == null) {
initImages();
}
return imageCheckboxDisabledOn;
}
public static Image getImageCheckboxDisabledOff()
{
if (imageCheckboxDisabledOff == null) {
initImages();
}
return imageCheckboxDisabledOff;
}
private static synchronized void initImages()
{
// Capture checkbox image - only for windows
// There could be hard-to-understand problems in Linux
if (!DBeaverCore.getInstance().getLocalSystem().isWindows()) {
imageCheckboxEnabledOff = DBeaverIcons.getImage(UIIcon.CHECK_OFF);
imageCheckboxEnabledOn = DBeaverIcons.getImage(UIIcon.CHECK_ON);
imageCheckboxDisabledOn = DBeaverIcons.getImage(UIIcon.CHECK_ON);
imageCheckboxDisabledOff = DBeaverIcons.getImage(UIIcon.CHECK_OFF);
return;
}
final Shell shell = DBeaverUI.getActiveWorkbenchShell();
Button checkBox = new Button(shell, SWT.CHECK);
checkBox.setVisible(true);
final Color borderColor = shell.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
checkBox.setBackground(borderColor);
Point checkboxSize = checkBox.computeSize(SWT.DEFAULT, SWT.DEFAULT);
checkBox.setBounds(0, 0, checkboxSize.x, checkboxSize.y);
try {
checkBox.setSelection(false);
imageCheckboxEnabledOff = captureWidget(checkBox, borderColor, DBeaverIcons.getImage(UIIcon.CHECK_OFF));
checkBox.setSelection(true);
imageCheckboxEnabledOn = captureWidget(checkBox, borderColor, DBeaverIcons.getImage(UIIcon.CHECK_ON));
checkBox.setEnabled(false);
imageCheckboxDisabledOn = captureWidget(checkBox, borderColor, DBeaverIcons.getImage(UIIcon.CHECK_ON));
checkBox.setSelection(false);
imageCheckboxDisabledOff = captureWidget(checkBox, borderColor, DBeaverIcons.getImage(UIIcon.CHECK_OFF));
} finally {
UIUtils.dispose(checkBox);
}
}
public static Image captureWidget(Control widget, Color borderColor, Image defaultImage)
{
Point size = widget.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Image image = new Image(widget.getDisplay(), size.x, size.y);
//image.
GC gc = new GC(image);
try {
//gc.copyArea(image, 0, 0);
widget.print(gc);
} finally {
UIUtils.dispose(gc);
}
Image result = removeImageBorder(image, borderColor);
if (result == null) {
return defaultImage;
} else {
return result;
}
/*
final ImageData imageData = image.getImageData();
imageData.transparentPixel = imageData.getPixel(0, 0);
Image fixedImage = new Image(widget.getDisplay(), imageData);
image.dispose();
return fixedImage;
*/
}
public static Image removeImageBorder(Image srcImage, Color borderColor)
{
final ImageData imageData = srcImage.getImageData();
if (imageData.height == 0 || imageData.width == 0) {
return srcImage;
}
int borderPixel = imageData.getPixel(0, 0);
if (!imageData.palette.getRGB(borderPixel).equals(borderColor.getRGB())) {
// First pixel isn't a border
return srcImage;
}
int emptyTopRows = 0, emptyBottomRows = 0, emptyLeftColumns = 0, emptyRightColumns = 0;
// Check top rows
int row;
for (row = 0; row < imageData.height; row++) {
boolean emptyRow = true;
for (int col = 0; col < imageData.width; col++) {
if (borderPixel != imageData.getPixel(col, row)) {
emptyRow = false;
break;
}
}
if (!emptyRow) {
emptyTopRows = row;
break;
}
}
if (row == imageData.height) {
// All rows are empty
return null;
}
// Check bottom rows
for (row = imageData.height - 1; row >= 0; row--) {
boolean emptyRow = true;
for (int col = 0; col < imageData.width; col++) {
if (borderPixel != imageData.getPixel(col, row)) {
emptyRow = false;
break;
}
}
if (!emptyRow) {
emptyBottomRows = imageData.height - row - 1;
break;
}
}
if (emptyTopRows > 0 || emptyBottomRows > 0 || emptyLeftColumns > 0 || emptyRightColumns > 0) {
return cropImage(
srcImage,
emptyLeftColumns,
emptyTopRows,
imageData.width - emptyLeftColumns - emptyRightColumns,
imageData.height - emptyTopRows - emptyBottomRows);
}
return srcImage;
}
public static Image cropImage(Image srcImage, int x, int y, int w, int h)
{
Image cropImage = new Image(srcImage.getDevice(), w, h);
// Redefine w and h to void them to be too big
if (x+w > srcImage.getBounds().width) {
w = srcImage.getBounds().width - x;
}
if (y+h > srcImage.getBounds().height) {
h = srcImage.getBounds().height - y;
}
GC cropGC = new GC(cropImage);
cropGC.drawImage(srcImage,
x, y,
w, h,
0, 0,
w, h);
UIUtils.dispose(cropGC);
UIUtils.dispose(srcImage);
return cropImage;
}
/**
* Retrieve the image data for the image, using a palette of at most 256
* colours.
*
* @param image the SWT image.
* @return new image data.
*/
public static ImageData makeWebImageData(Image image)
{
ImageData imageData = image.getImageData();
/**
* If the image depth is 8 bits or less, then we can use the existing
* image data.
*/
if (imageData.depth <= 8) {
return imageData;
}
/**
* get an 8 bit imageData for the image
*/
ImageData newImageData = get8BitPaletteImageData(imageData);
/**
* if newImageData is null, it has more than 256 colours. Use the web
* safe palette to get an 8 bit image data for the image.
*/
if (newImageData == null) {
newImageData = getWebSafePaletteImageData(imageData);
}
return newImageData;
}
/**
* Retrieve an image data with an 8 bit palette for an image. We assume that
* the image has less than 256 colours.
*
* @param imageData the imageData for the image.
* @return the new 8 bit imageData or null if the image has more than 256
* colours.
*/
private static ImageData get8BitPaletteImageData(ImageData imageData)
{
PaletteData palette = imageData.palette;
RGB colours[] = new RGB[256];
PaletteData newPaletteData = new PaletteData(colours);
ImageData newImageData = new ImageData(imageData.width, imageData.height, 8, newPaletteData);
int lastPixel = -1;
int newPixel = -1;
for (int i = 0; i < imageData.width; ++i) {
for (int j = 0; j < imageData.height; ++j) {
int pixel = imageData.getPixel(i, j);
if (pixel != lastPixel) {
lastPixel = pixel;
RGB colour = palette.getRGB(pixel);
for (newPixel = 0; newPixel < 256; ++newPixel) {
if (colours[newPixel] == null) {
colours[newPixel] = colour;
break;
}
if (colours[newPixel].equals(colour)) {
break;
}
}
if (newPixel >= 256) {
/**
* Diagram has more than 256 colors, return null
*/
return null;
}
}
newImageData.setPixel(i, j, newPixel);
}
}
RGB colour = new RGB(0, 0, 0);
for (int k = 0; k < 256; ++k) {
if (colours[k] == null) {
colours[k] = colour;
}
}
return newImageData;
}
/**
* If the image has less than 256 colours, simply create a new 8 bit palette
* and map the colours to the new palette.
*/
private static ImageData getWebSafePaletteImageData(ImageData imageData)
{
PaletteData palette = imageData.palette;
RGB[] webSafePalette = getWebSafePalette();
PaletteData newPaletteData = new PaletteData(webSafePalette);
ImageData newImageData = new ImageData(imageData.width,
imageData.height, 8, newPaletteData);
int lastPixel = -1;
int newPixel = -1;
for (int i = 0; i < imageData.width; ++i) {
for (int j = 0; j < imageData.height; ++j) {
int pixel = imageData.getPixel(i, j);
if (pixel != lastPixel) {
lastPixel = pixel;
RGB colour = palette.getRGB(pixel);
RGB webSafeColour = getWebSafeColour(colour);
for (newPixel = 0; newPixel < 256; ++newPixel) {
if (webSafePalette[newPixel].equals(webSafeColour)) {
break;
}
}
Assert.isTrue(newPixel < 216);
}
newImageData.setPixel(i, j, newPixel);
}
}
return newImageData;
}
/**
* Retrieves a web safe colour that closely matches the provided colour.
*
* @param colour a colour.
* @return the web safe colour.
*/
private static RGB getWebSafeColour(RGB colour)
{
int red = Math.round((colour.red + 25) / 51) * 51;
int green = Math.round((colour.green + 25) / 51) * 51;
int blue = Math.round((colour.blue + 25) / 51) * 51;
return new RGB(red, green, blue);
}
/**
* Retrieves a web safe palette. Our palette will be 216 web safe colours
* and the remaining filled with white.
*
* @return array of 256 colours.
*/
private static RGB[] getWebSafePalette()
{
RGB[] colours = new RGB[256];
int i = 0;
for (int red = 0; red <= 255; red = red + 51) {
for (int green = 0; green <= 255; green = green + 51) {
for (int blue = 0; blue <= 255; blue = blue + 51) {
RGB colour = new RGB(red, green, blue);
colours[i++] = colour;
}
}
}
RGB colour = new RGB(0, 0, 0);
for (int k = 0; k < 256; ++k) {
if (colours[k] == null) {
colours[k] = colour;
}
}
return colours;
}
}