aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eclipse/dictionary.txt1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java326
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java54
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java169
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java191
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java162
7 files changed, 595 insertions, 310 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index 5cd3e2a..fe06849 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -70,6 +70,7 @@ linestyle
linux
locale
logo
+luminance
mac
macs
marquee
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
index 37029a1..337e76e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
@@ -84,7 +84,7 @@ public class ImageOverlay extends Overlay {
mImage = null;
} else {
- mImage = SwtUtils.convertImage(mCanvas.getDisplay(), awtImage, false, -1);
+ mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, false, -1);
}
return mImage;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java
new file mode 100644
index 0000000..21ad07c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+
+import com.android.ide.common.api.Rect;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+
+/**
+ * Utilities related to image processing.
+ */
+public class ImageUtils {
+ /**
+ * Returns true if the given image has no dark pixels
+ *
+ * @param image the image to be checked for dark pixels
+ * @return true if no dark pixels were found
+ */
+ public static boolean containsDarkPixels(BufferedImage image) {
+ for (int y = 0, height = image.getHeight(); y < height; y++) {
+ for (int x = 0, width = image.getWidth(); x < width; x++) {
+ int pixel = image.getRGB(x, y);
+ if ((pixel & 0xFF000000) != 0) {
+ int r = (pixel & 0xFF0000) >> 16;
+ int g = (pixel & 0x00FF00) >> 8;
+ int b = (pixel & 0x0000FF);
+
+ // One perceived luminance formula is (0.299*red + 0.587*green + 0.114*blue)
+ // In order to keep this fast since we don't need a very accurate
+ // measure, I'll just estimate this with integer math:
+ long brightness = (299L*r + 587*g + 114*b) / 1000;
+ if (brightness < 128) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Crops blank pixels from the edges of the image and returns the cropped result. We
+ * crop off pixels that are blank (meaning they have an alpha value = 0). Note that
+ * this is not the same as pixels that aren't opaque (an alpha value other than 255).
+ *
+ * @param image the image to be cropped
+ * @param initialCrop If not null, specifies a rectangle which contains an initial
+ * crop to continue. This can be used to crop an image where you already
+ * know about margins in the image
+ * @return a cropped version of the source image, or null if the whole image was blank
+ * and cropping completely removed everything
+ */
+ public static BufferedImage cropBlank(BufferedImage image, Rect initialCrop) {
+ CropFilter filter = new CropFilter() {
+ public boolean crop(BufferedImage bufferedImage, int x, int y) {
+ int rgb = bufferedImage.getRGB(x, y);
+ return (rgb & 0xFF000000) == 0x00000000;
+ // TODO: Do a threshold of 80 instead of just 0? Might give better
+ // visual results -- e.g. check <= 0x80000000
+ }
+ };
+ return crop(image, filter, initialCrop);
+ }
+
+ /**
+ * Crops pixels of a given color from the edges of the image and returns the cropped
+ * result.
+ *
+ * @param image the image to be cropped
+ * @param blankArgb the color considered to be blank, as a 32 pixel integer with 8
+ * bits of alpha, red, green and blue
+ * @param initialCrop If not null, specifies a rectangle which contains an initial
+ * crop to continue. This can be used to crop an image where you already
+ * know about margins in the image
+ * @return a cropped version of the source image, or null if the whole image was blank
+ * and cropping completely removed everything
+ */
+ public static BufferedImage cropColor(BufferedImage image,
+ final int blankArgb, Rect initialCrop) {
+ CropFilter filter = new CropFilter() {
+ public boolean crop(BufferedImage bufferedImage, int x, int y) {
+ return blankArgb == bufferedImage.getRGB(x, y);
+ }
+ };
+ return crop(image, filter, initialCrop);
+ }
+
+ /**
+ * Interface implemented by cropping functions that determine whether
+ * a pixel should be cropped or not.
+ */
+ private static interface CropFilter {
+ /**
+ * Returns true if the pixel is should be cropped.
+ *
+ * @param image the image containing the pixel in question
+ * @param x the x position of the pixel
+ * @param y the y position of the pixel
+ * @return true if the pixel should be cropped (for example, is blank)
+ */
+ boolean crop(BufferedImage image, int x, int y);
+ }
+
+ private static BufferedImage crop(BufferedImage image, CropFilter filter, Rect initialCrop) {
+ if (image == null) {
+ return null;
+ }
+
+ // First, determine the dimensions of the real image within the image
+ int x1, y1, x2, y2;
+ if (initialCrop != null) {
+ x1 = initialCrop.x;
+ y1 = initialCrop.y;
+ x2 = initialCrop.x + initialCrop.w;
+ y2 = initialCrop.y + initialCrop.h;
+ } else {
+ x1 = 0;
+ y1 = 0;
+ x2 = image.getWidth();
+ y2 = image.getHeight();
+ }
+
+ // Nothing left to crop
+ if (x1 == x2 || y1 == y2) {
+ return null;
+ }
+
+ // This algorithm is a bit dumb -- it just scans along the edges looking for
+ // a pixel that shouldn't be cropped. I could maybe try to make it smarter by
+ // for example doing a binary search to quickly eliminate large empty areas to
+ // the right and bottom -- but this is slightly tricky with components like the
+ // AnalogClock where I could accidentally end up finding a blank horizontal or
+ // vertical line somewhere in the middle of the rendering of the clock, so for now
+ // we do the dumb thing -- not a big deal since we tend to crop reasonably
+ // small images.
+
+ // First determine top edge
+ topEdge: for (; y1 < y2; y1++) {
+ for (int x = x1; x < x2; x++) {
+ if (!filter.crop(image, x, y1)) {
+ break topEdge;
+ }
+ }
+ }
+
+ if (y1 == image.getHeight()) {
+ // The image is blank
+ return null;
+ }
+
+ // Next determine left edge
+ leftEdge: for (; x1 < x2; x1++) {
+ for (int y = y1; y < y2; y++) {
+ if (!filter.crop(image, x1, y)) {
+ break leftEdge;
+ }
+ }
+ }
+
+ // Next determine right edge
+ rightEdge: for (; x2 > x1; x2--) {
+ for (int y = y1; y < y2; y++) {
+ if (!filter.crop(image, x2 - 1, y)) {
+ break rightEdge;
+ }
+ }
+ }
+
+ // Finally determine bottom edge
+ bottomEdge: for (; y2 > y1; y2--) {
+ for (int x = x1; x < x2; x++) {
+ if (!filter.crop(image, x, y2 - 1)) {
+ break bottomEdge;
+ }
+ }
+ }
+
+ // No need to crop?
+ if (x1 == 0 && y1 == 0 && x2 == image.getWidth() && y2 == image.getHeight()) {
+ return image;
+ }
+
+ if (x1 == x2 || y1 == y2) {
+ // Nothing left after crop -- blank image
+ return null;
+ }
+
+ int width = x2 - x1;
+ int height = y2 - y1;
+
+ // Now extract the sub-image
+ BufferedImage cropped = new BufferedImage(width, height, image.getType());
+ Graphics g = cropped.getGraphics();
+ g.drawImage(image, 0, 0, width, height, x1, y1, x2, y2, null);
+
+ g.dispose();
+
+ return cropped;
+ }
+
+ /**
+ * Creates a drop shadow of a given image and returns a new image which shows the
+ * input image on top of its drop shadow.
+ *
+ * @param source the source image to be shadowed
+ * @param shadowSize the size of the shadow in pixels
+ * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque
+ * @param shadowRgb the RGB int to use for the shadow color
+ * @return a new image with the source image on top of its shadow
+ */
+ public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
+ float shadowOpacity, int shadowRgb) {
+
+ // This code is based on
+ // http://www.jroller.com/gfx/entry/non_rectangular_shadow
+
+ BufferedImage image = new BufferedImage(source.getWidth() + shadowSize * 2,
+ source.getHeight() + shadowSize * 2,
+ BufferedImage.TYPE_INT_ARGB);
+
+ Graphics2D g2 = image.createGraphics();
+ g2.drawImage(source, null, shadowSize, shadowSize);
+
+ 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;
+
+ shadowRgb = shadowRgb & 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;
+
+ // subtract the oldest pixel from the sum
+ aSum -= aHistory[historyIdx];
+
+ // get the latest 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;
+
+ // subtract the oldest pixel from the sum
+ aSum -= aHistory[historyIdx];
+
+ // get the latest pixel
+ a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24;
+ aHistory[historyIdx] = a;
+ aSum += a;
+
+ if (++historyIdx >= shadowSize) {
+ historyIdx -= shadowSize;
+ }
+ }
+ }
+
+ g2.drawImage(source, null, 0, 0);
+ g2.dispose();
+
+ return image;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java
index 32bf15b..6cfaff6 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteComposite.java
@@ -555,7 +555,7 @@ public class PaletteComposite extends Composite {
private static final int RENDER_WIDTH = 500;
/** Amount of alpha to multiply into the image (divided by 256) */
- private static final int IMG_ALPHA = 192;
+ private static final int IMG_ALPHA = 216;
/** The item this preview is rendering a preview for */
private final Item mItem;
@@ -590,14 +590,22 @@ public class PaletteComposite extends Composite {
final Image image = new Image(mItem.getDisplay(), size.x, size.y);
gc.copyArea(image, 0, 0);
gc.dispose();
- ImageData data = image.getImageData();
- data.alpha = IMG_ALPHA;
+ Display display = mItem.getDisplay();
+ BufferedImage awtImage = SwtUtils.convertToAwt(image);
+ if (awtImage != null) {
+ awtImage = ImageUtils.createDropShadow(awtImage, 3 /* shadowSize */,
+ 0.7f /* shadowAlpha */, 0x000000 /* shadowRgb */);
+ mImage = SwtUtils.convertToSwt(display, awtImage, true, IMG_ALPHA);
+ } else {
+ ImageData data = image.getImageData();
+ data.alpha = IMG_ALPHA;
- // Changing the ImageData -after- constructing an image on it
- // has no effect, so we have to construct a new image. Luckily these
- // are tiny images.
- mImage = new Image(mItem.getDisplay(), data);
+ // Changing the ImageData -after- constructing an image on it
+ // has no effect, so we have to construct a new image. Luckily these
+ // are tiny images.
+ mImage = new Image(display, data);
+ }
image.dispose();
}
@@ -707,15 +715,39 @@ public class PaletteComposite extends Composite {
}
if (hasTransparency) {
- cropped = SwtUtils.cropBlank(image, initialCrop);
+ cropped = ImageUtils.cropBlank(image, initialCrop);
} else {
- int edgeColor = image.getRGB(image.getWidth() - 1, image.getHeight() - 1);
- cropped = SwtUtils.cropColor(image, edgeColor, initialCrop);
+ // Find out what the "background" color is such that we can properly
+ // crop it out of the image. To do this we pick out a pixel in the
+ // bottom right unpainted area. Rather than pick the one in the far
+ // bottom corner, we pick one as close to the bounds of the view as
+ // possible (but still outside of the bounds), such that we can
+ // deal with themes like the dialog theme.
+ int edgeX = image.getWidth() -1;
+ int edgeY = image.getHeight() -1;
+ if (viewInfo != null) {
+ if (viewInfo.getRight() < image.getWidth()-1) {
+ edgeX = viewInfo.getRight()+1;
+ }
+ if (viewInfo.getBottom() < image.getHeight()-1) {
+ edgeY = viewInfo.getBottom()+1;
+ }
+ }
+ int edgeColor = image.getRGB(edgeX, edgeY);
+ cropped = ImageUtils.cropColor(image, edgeColor, initialCrop);
}
if (cropped != null) {
+ boolean needsContrast = hasTransparency
+ && !ImageUtils.containsDarkPixels(cropped);
+ cropped = ImageUtils.createDropShadow(cropped,
+ hasTransparency ? 3 : 5 /* shadowSize */,
+ !hasTransparency ? 0.6f : needsContrast ? 0.8f : 0.7f /* alpha */,
+ 0x000000 /* shadowRgb */);
+
Display display = getControl().getDisplay();
- Image swtImage = SwtUtils.convertImage(display, cropped, true, IMG_ALPHA);
+ int alpha = (!hasTransparency || !needsContrast) ? IMG_ALPHA : -1;
+ Image swtImage = SwtUtils.convertToSwt(display, cropped, true, alpha);
return swtImage;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
index 3080716..6c55dd3 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
@@ -15,20 +15,17 @@
*/
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
-import com.android.ide.common.api.Rect;
-
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.widgets.Display;
-import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
/**
- * Various generic SWT utilities such as image conversion and cropping.
+ * Various generic SWT utilities such as image conversion.
*/
public class SwtUtils {
private SwtUtils() {
@@ -47,7 +44,7 @@ public class SwtUtils {
* @return A new SWT {@link Image} with the same contents as the source
* {@link BufferedImage}
*/
- public static Image convertImage(Display display, BufferedImage awtImage,
+ public static Image convertToSwt(Display display, BufferedImage awtImage,
boolean transferAlpha, int globalAlpha) {
int width = awtImage.getWidth();
int height = awtImage.getHeight();
@@ -88,158 +85,28 @@ public class SwtUtils {
}
/**
- * Crops blank pixels from the edges of the image and returns the cropped result. We
- * crop off pixels that are blank (meaning they have an alpha value = 0). Note that
- * this is not the same as pixels that aren't opaque (an alpha value other than 255).
- *
- * @param image the image to be cropped
- * @param initialCrop If not null, specifies a rectangle which contains an initial
- * crop to continue. This can be used to crop an image where you already
- * know about margins in the image
- * @return a cropped version of the source image, or null if the whole image was blank
- * and cropping completely removed everything
- */
- public static BufferedImage cropBlank(BufferedImage image, Rect initialCrop) {
- CropFilter filter = new CropFilter() {
- public boolean crop(BufferedImage bufferedImage, int x, int y) {
- int rgb = bufferedImage.getRGB(x, y);
- return (rgb & 0xFF000000) == 0x00000000;
- // TODO: Do a threshold of 80 instead of just 0? Might give better
- // visual results -- e.g. check <= 0x80000000
- }
- };
- return crop(image, filter, initialCrop);
- }
-
- /**
- * Crops pixels of a given color from the edges of the image and returns the cropped
- * result.
+ * Converts a direct-color model SWT image to an equivalent AWT image. If the image
+ * does not have a supported color model, returns null. This method does <b>NOT</b>
+ * preserve alpha in the source image.
*
- * @param image the image to be cropped
- * @param blankRgba the color considered to be blank, as a 32 pixel integer with 8
- * bits of alpha, red, green and blue
- * @param initialCrop If not null, specifies a rectangle which contains an initial
- * crop to continue. This can be used to crop an image where you already
- * know about margins in the image
- * @return a cropped version of the source image, or null if the whole image was blank
- * and cropping completely removed everything
- */
- public static BufferedImage cropColor(BufferedImage image,
- final int blankRgba, Rect initialCrop) {
- CropFilter filter = new CropFilter() {
- public boolean crop(BufferedImage bufferedImage, int x, int y) {
- return blankRgba == bufferedImage.getRGB(x, y);
- }
- };
- return crop(image, filter, initialCrop);
- }
-
- /**
- * Interface implemented by cropping functions that determine whether
- * a pixel should be cropped or not.
+ * @param swtImage the SWT image to be converted to AWT
+ * @return an AWT image representing the source SWT image
*/
- private static interface CropFilter {
- /**
- * Returns true if the pixel is should be cropped.
- *
- * @param image the image containing the pixel in question
- * @param x the x position of the pixel
- * @param y the y position of the pixel
- * @return true if the pixel should be cropped (for example, is blank)
- */
- boolean crop(BufferedImage image, int x, int y);
- }
-
- private static BufferedImage crop(BufferedImage image, CropFilter filter, Rect initialCrop) {
- if (image == null) {
- return null;
- }
-
- // First, determine the dimensions of the real image within the image
- int x1, y1, x2, y2;
- if (initialCrop != null) {
- x1 = initialCrop.x;
- y1 = initialCrop.y;
- x2 = initialCrop.x + initialCrop.w;
- y2 = initialCrop.y + initialCrop.h;
- } else {
- x1 = 0;
- y1 = 0;
- x2 = image.getWidth();
- y2 = image.getHeight();
- }
-
- // Nothing left to crop
- if (x1 == x2 || y1 == y2) {
- return null;
- }
-
- // This algorithm is a bit dumb -- it just scans along the edges looking for
- // a pixel that shouldn't be cropped. I could maybe try to make it smarter by
- // for example doing a binary search to quickly eliminate large empty areas to
- // the right and bottom -- but this is slightly tricky with components like the
- // AnalogClock where I could accidentally end up finding a blank horizontal or
- // vertical line somewhere in the middle of the rendering of the clock, so for now
- // we do the dumb thing -- not a big deal since we tend to crop reasonably
- // small images.
-
- // First determine top edge
- topEdge: for (; y1 < y2; y1++) {
- for (int x = x1; x < x2; x++) {
- if (!filter.crop(image, x, y1)) {
- break topEdge;
- }
- }
- }
-
- if (y1 == image.getHeight()) {
- // The image is blank
- return null;
- }
-
- // Next determine left edge
- leftEdge: for (; x1 < x2; x1++) {
- for (int y = y1; y < y2; y++) {
- if (!filter.crop(image, x1, y)) {
- break leftEdge;
- }
- }
- }
-
- // Next determine right edge
- rightEdge: for (; x2 > x1; x2--) {
- for (int y = y1; y < y2; y++) {
- if (!filter.crop(image, x2 - 1, y)) {
- break rightEdge;
- }
- }
- }
-
- // Finally determine bottom edge
- bottomEdge: for (; y2 > y1; y2--) {
- for (int x = x1; x < x2; x++) {
- if (!filter.crop(image, x, y2 - 1)) {
- break bottomEdge;
+ public static BufferedImage convertToAwt(Image swtImage) {
+ ImageData data = swtImage.getImageData();
+ BufferedImage awtImage = new BufferedImage(data.width, data.height, BufferedImage.TYPE_INT_ARGB);
+ PaletteData palette = data.palette;
+ if (palette.isDirect) {
+ for (int y = 0; y < data.height; y++) {
+ for (int x = 0; x < data.width; x++) {
+ int pixel = data.getPixel(x, y);
+ awtImage.setRGB(x, y, 0xFF000000 | pixel);
}
}
- }
-
- // No need to crop?
- if (x1 == 0 && y1 == 0 && x2 == image.getWidth() && y2 == image.getHeight()) {
- return image;
- }
-
- if (x1 == x2 || y1 == y2) {
- // Nothing left after crop -- blank image
+ } else {
return null;
}
- // Now extract the sub-image
- BufferedImage cropped = new BufferedImage(x2 - x1, y2 - y1, image.getType());
- Graphics g = cropped.getGraphics();
- g.drawImage(image, 0, 0, x2 - x1, y2 - y1, x1, y1, x2, y2, null);
- g.dispose();
-
- return cropped;
+ return awtImage;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
new file mode 100644
index 0000000..e4ddde3
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+
+import com.android.ide.common.api.Rect;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import junit.framework.TestCase;
+
+public class ImageUtilsTest extends TestCase {
+ public void testCropBlank() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNull(crop);
+ }
+
+ public void testCropBlankPre() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(5, 5, 80, 80));
+ assertNull(crop);
+ }
+
+ public void testCropNonblank() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, false));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNotNull(crop);
+ assertEquals(image.getWidth(), crop.getWidth());
+ assertEquals(image.getHeight(), crop.getHeight());
+ }
+
+ public void testCropSomething() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropSomethingPre() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(0, 0, 100, 100));
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropSomethingPre2() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(5, 5, 80, 80));
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropColor() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFF00FF00, null);
+ assertNull(crop);
+ }
+
+ public void testCropNonColor() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFFFF0000, null);
+ assertNotNull(crop);
+ assertEquals(image.getWidth(), crop.getWidth());
+ assertEquals(image.getHeight(), crop.getHeight());
+ }
+
+ public void testCropColorSomething() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFFFF0000, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFF00FF00, null);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFFFF0000, crop.getRGB(0, 0));
+ assertEquals(0xFFFF0000, crop.getRGB(49, 49));
+ }
+
+ public void testNullOk() throws Exception {
+ ImageUtils.cropBlank(null, null);
+ ImageUtils.cropColor(null, 0, null);
+ }
+
+
+ public void testNothingTodo() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFFFF0000, new Rect(40, 40, 0, 0));
+ assertNull(crop);
+ }
+
+ public void testContainsDarkPixels() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ assertFalse(ImageUtils.containsDarkPixels(image));
+
+ image.setRGB(50, 50, 0xFFFFFFFF);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFFAAAAAA);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFF00FF00);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFFFF8800);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFF333333);
+ assertTrue(ImageUtils.containsDarkPixels(image));
+
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java
index 30bb82e..e383796 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java
@@ -16,8 +16,6 @@
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
-import com.android.ide.common.api.Rect;
-
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.widgets.Display;
@@ -30,136 +28,6 @@ import java.awt.image.BufferedImage;
import junit.framework.TestCase;
public class SwtUtilsTest extends TestCase {
- public void testCropBlank() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, null);
- assertNull(crop);
- }
-
- public void testCropBlankPre() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, new Rect(5, 5, 80, 80));
- assertNull(crop);
- }
-
- public void testCropNonblank() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, false));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, null);
- assertNotNull(crop);
- assertEquals(image.getWidth(), crop.getWidth());
- assertEquals(image.getHeight(), crop.getHeight());
- }
-
- public void testCropSomething() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(25, 25, 50, 50);
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, null);
- assertNotNull(crop);
- assertEquals(50, crop.getWidth());
- assertEquals(50, crop.getHeight());
- assertEquals(0xFF00FF00, crop.getRGB(0, 0));
- assertEquals(0xFF00FF00, crop.getRGB(49, 49));
- }
-
- public void testCropSomethingPre() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(25, 25, 50, 50);
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, new Rect(0, 0, 100, 100));
- assertNotNull(crop);
- assertEquals(50, crop.getWidth());
- assertEquals(50, crop.getHeight());
- assertEquals(0xFF00FF00, crop.getRGB(0, 0));
- assertEquals(0xFF00FF00, crop.getRGB(49, 49));
- }
-
- public void testCropSomethingPre2() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(25, 25, 50, 50);
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropBlank(image, new Rect(5, 5, 80, 80));
- assertNotNull(crop);
- assertEquals(50, crop.getWidth());
- assertEquals(50, crop.getHeight());
- assertEquals(0xFF00FF00, crop.getRGB(0, 0));
- assertEquals(0xFF00FF00, crop.getRGB(49, 49));
- }
-
- public void testCropColor() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropColor(image, 0xFF00FF00, null);
- assertNull(crop);
- }
-
- public void testCropNonColor() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropColor(image, 0xFFFF0000, null);
- assertNotNull(crop);
- assertEquals(image.getWidth(), crop.getWidth());
- assertEquals(image.getHeight(), crop.getHeight());
- }
-
- public void testCropColorSomething() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.setColor(new Color(0xFFFF0000, true));
- g.fillRect(25, 25, 50, 50);
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropColor(image, 0xFF00FF00, null);
- assertEquals(50, crop.getWidth());
- assertEquals(50, crop.getHeight());
- assertEquals(0xFFFF0000, crop.getRGB(0, 0));
- assertEquals(0xFFFF0000, crop.getRGB(49, 49));
- }
-
- public void testNullOk() throws Exception {
- SwtUtils.cropBlank(null, null);
- SwtUtils.cropColor(null, 0, null);
- }
public void testImageConvertNoAlpha() throws Exception {
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
@@ -170,7 +38,7 @@ public class SwtUtilsTest extends TestCase {
Shell shell = new Shell();
Display display = shell.getDisplay();
- Image swtImage = SwtUtils.convertImage(display, image, false, -1);
+ Image swtImage = SwtUtils.convertToSwt(display, image, false, -1);
assertNotNull(swtImage);
ImageData data = swtImage.getImageData();
assertEquals(image.getWidth(), data.width);
@@ -181,6 +49,17 @@ public class SwtUtilsTest extends TestCase {
assertEquals(image.getRGB(x, y) & 0xFFFFFF, data.getPixel(x, y));
}
}
+
+ // Convert back to AWT and compare with original AWT image
+ BufferedImage awtImage = SwtUtils.convertToAwt(swtImage);
+ assertNotNull(awtImage);
+ for (int y = 0; y < data.height; y++) {
+ for (int x = 0; x < data.width; x++) {
+ assertEquals(image.getRGB(x, y), awtImage.getRGB(x, y));
+ }
+ }
+
+
}
public void testImageConvertGlobalAlpha() throws Exception {
@@ -192,7 +71,7 @@ public class SwtUtilsTest extends TestCase {
Shell shell = new Shell();
Display display = shell.getDisplay();
- Image swtImage = SwtUtils.convertImage(display, image, false, 128);
+ Image swtImage = SwtUtils.convertToSwt(display, image, false, 128);
assertNotNull(swtImage);
ImageData data = swtImage.getImageData();
assertEquals(image.getWidth(), data.width);
@@ -215,7 +94,7 @@ public class SwtUtilsTest extends TestCase {
Shell shell = new Shell();
Display display = shell.getDisplay();
- Image swtImage = SwtUtils.convertImage(display, image, true, -1);
+ Image swtImage = SwtUtils.convertToSwt(display, image, true, -1);
assertNotNull(swtImage);
ImageData data = swtImage.getImageData();
assertEquals(image.getWidth(), data.width);
@@ -239,7 +118,7 @@ public class SwtUtilsTest extends TestCase {
Shell shell = new Shell();
Display display = shell.getDisplay();
- Image swtImage = SwtUtils.convertImage(display, image, true, 32);
+ Image swtImage = SwtUtils.convertToSwt(display, image, true, 32);
assertNotNull(swtImage);
ImageData data = swtImage.getImageData();
assertEquals(image.getWidth(), data.width);
@@ -255,15 +134,4 @@ public class SwtUtilsTest extends TestCase {
}
}
- public void testNothingTodo() throws Exception {
- BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
- Graphics g = image.getGraphics();
- g.setColor(new Color(0xFF00FF00, true));
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.dispose();
-
- BufferedImage crop = SwtUtils.cropColor(image, 0xFFFF0000, new Rect(40, 40, 0, 0));
- assertNull(crop);
- }
-
}