aboutsummaryrefslogtreecommitdiffstats
path: root/assetstudio/src
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-07-15 21:16:56 -0700
committerTor Norbye <tnorbye@google.com>2011-07-27 16:46:57 -0700
commit7208e72d510e1bf5d3860f4a15d135e42d64eaa0 (patch)
treeb190a7e85efd913d5aaff25f0ccaa37ffb28312e /assetstudio/src
parentc766a5e884fbb9a3a4f02809961942173c7cce8b (diff)
downloadsdk-7208e72d510e1bf5d3860f4a15d135e42d64eaa0.zip
sdk-7208e72d510e1bf5d3860f4a15d135e42d64eaa0.tar.gz
sdk-7208e72d510e1bf5d3860f4a15d135e42d64eaa0.tar.bz2
Asset Studio wizard
This is an initial integration of the Android Asset Studio into Eclipse, as a New Asset wizard. It uses the Java port of the Android Asset Studio to generate the assets: https://code.google.com/a/google.com/p/android-asset-studio-java/ It only supports launcher icons, and some of the configurable parameters (file, shape, crop). To run it, put the AssetStudioLib.jar file into the the adt libs directory. There's a new "Asset Set" wizard in the New wizard, which will open up a two page wizard; the first page lets you select the project (which it attempts to pick up from context), as well as the type of asset to create, and the asset output name. In the second page there are the various widgets to tweak the code generator, and a preview area on the right which updates as you tweak the various controls. The main remaining work is to support additional asset types as they are added to the assetstudio generator library. Change-Id: I2e556337f8e5c3bc09e84b35a342ba05110abebc
Diffstat (limited to 'assetstudio/src')
-rw-r--r--assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java52
-rw-r--r--assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java33
-rw-r--r--assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java108
-rw-r--r--assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java92
-rw-r--r--assetstudio/src/com/android/assetstudiolib/Util.java440
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/back.pngbin0 -> 1885 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.pngbin0 -> 666 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.pngbin0 -> 2922 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.pngbin0 -> 4690 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/mask.pngbin0 -> 992 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/ldpi/back.pngbin0 -> 745 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.pngbin0 -> 376 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.pngbin0 -> 1370 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.pngbin0 -> 2432 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/ldpi/mask.pngbin0 -> 435 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/back.pngbin0 -> 1162 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.pngbin0 -> 457 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.pngbin0 -> 1720 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.pngbin0 -> 2926 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/mask.pngbin0 -> 610 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/back.pngbin0 -> 29806 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/fore1.pngbin0 -> 30292 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/fore2.pngbin0 -> 59463 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/fore3.pngbin0 -> 61713 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/mask.pngbin0 -> 8447 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/back.pngbin0 -> 3451 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.pngbin0 -> 1746 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.pngbin0 -> 5054 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.pngbin0 -> 6239 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.pngbin0 -> 2142 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/back.pngbin0 -> 713 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/fore1.pngbin0 -> 331 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/fore2.pngbin0 -> 1477 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/fore3.pngbin0 -> 3592 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/mask.pngbin0 -> 370 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/ldpi/back.pngbin0 -> 295 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/ldpi/fore1.pngbin0 -> 212 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/ldpi/fore2.pngbin0 -> 693 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/ldpi/fore3.pngbin0 -> 2061 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/ldpi/mask.pngbin0 -> 205 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/back.pngbin0 -> 455 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/fore1.pngbin0 -> 239 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/fore2.pngbin0 -> 1010 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/fore3.pngbin0 -> 2510 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/mask.pngbin0 -> 250 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/back.pngbin0 -> 10984 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/fore1.pngbin0 -> 8562 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/fore2.pngbin0 -> 26230 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/fore3.pngbin0 -> 42175 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/mask.pngbin0 -> 3786 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/back.pngbin0 -> 1956 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.pngbin0 -> 1289 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.pngbin0 -> 2932 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.pngbin0 -> 4649 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/mask.pngbin0 -> 1396 bytes
55 files changed, 725 insertions, 0 deletions
diff --git a/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java b/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java
new file mode 100644
index 0000000..e53f0ab
--- /dev/null
+++ b/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.assetstudiolib;
+
+import com.android.resources.Density;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+
+/**
+ * The base Generator class.
+ */
+public class GraphicGenerator {
+ /**
+ * Options used for all generators.
+ */
+ public static class Options {
+ }
+
+ public static float getScaleFactor(Density density) {
+ return density.getDpiValue() / (float) Density.DEFAULT_DENSITY;
+ }
+
+ /**
+ * Returns one of the built in stencil images, or null
+ *
+ * @param relativePath stencil path such as "launcher-stencil/square/web/back.png"
+ * @return the image, or null
+ * @throws IOException if an unexpected I/O error occurs
+ */
+ public static BufferedImage getStencilImage(String relativePath) throws IOException {
+ InputStream is = GraphicGenerator.class.getResourceAsStream(relativePath);
+ return ImageIO.read(is);
+ }
+}
diff --git a/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java b/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java
new file mode 100644
index 0000000..e0b00a6
--- /dev/null
+++ b/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.assetstudiolib;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * The context used during graphic generation.
+ */
+public interface GraphicGeneratorContext {
+ /**
+ * Loads the given image resource, as requested by the graphic generator.
+ *
+ * @param path The path to the resource, relative to the general "resources" path, as defined by
+ * the context implementor.
+ * @return The loaded image resource, or null if there was an error.
+ */
+ public BufferedImage loadImageResource(String path);
+}
diff --git a/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java
new file mode 100644
index 0000000..b6715a4
--- /dev/null
+++ b/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.assetstudiolib;
+
+import com.android.resources.Density;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * A {@link GraphicGenerator} that generates Android "launcher" icons.
+ */
+public class LauncherIconGenerator extends GraphicGenerator {
+ private static final Rectangle BASE_IMAGE_RECT = new Rectangle(0, 0, 48, 48);
+ private static final Rectangle BASE_TARGET_RECT = new Rectangle(4, 4, 40, 40);
+
+ private Options mOptions;
+ private BufferedImage mBackImage;
+ private BufferedImage mMaskImage;
+ private BufferedImage mForeImage;
+
+ public LauncherIconGenerator(GraphicGeneratorContext context, Options options) {
+ mOptions = options;
+ mBackImage = context.loadImageResource("/images/launcher_stencil/"
+ + options.shape.id + "/" + options.density.getResourceValue() + "/back.png");
+ mForeImage = context.loadImageResource("/images/launcher_stencil/"
+ + options.shape.id + "/" + options.density.getResourceValue() + "/"
+ + options.style.id + ".png");
+ mMaskImage = context.loadImageResource("/images/launcher_stencil/"
+ + options.shape.id + "/" + options.density.getResourceValue() + "/mask.png");
+ }
+
+ public BufferedImage generate() {
+ final float scaleFactor = GraphicGenerator.getScaleFactor(mOptions.density);
+ Rectangle imageRect = Util.scaleRectangle(BASE_IMAGE_RECT, scaleFactor);
+ Rectangle targetRect = Util.scaleRectangle(BASE_TARGET_RECT, scaleFactor);
+
+ BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
+ Graphics2D g = (Graphics2D) outImage.getGraphics();
+ g.drawImage(mBackImage, 0, 0, null);
+
+ {
+ BufferedImage tempImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
+ Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
+ g2.drawImage(mMaskImage, 0, 0, null);
+ g2.setComposite(AlphaComposite.SrcAtop);
+ g2.setPaint(new Color(mOptions.backgroundColor));
+ g2.fillRect(0, 0, imageRect.width, imageRect.height);
+
+ if (mOptions.crop) {
+ Util.drawCenterCrop(g2, mOptions.sourceImage, targetRect);
+ } else {
+ Util.drawCenterInside(g2, mOptions.sourceImage, targetRect);
+ }
+
+ g.drawImage(tempImage, 0, 0, null);
+ }
+
+ g.drawImage(mForeImage, 0, 0, null);
+ return outImage;
+ }
+
+ public static class Options {
+ public BufferedImage sourceImage;
+ public int backgroundColor = 0;
+ public boolean crop = true;
+ public Shape shape = Shape.SQUARE;
+ public Style style = Style.SIMPLE;
+ public Density density = Density.XHIGH;
+
+ public static enum Shape {
+ CIRCLE("circle"), SQUARE("square");
+
+ public String id;
+
+ Shape(String id) {
+ this.id = id;
+ }
+ }
+
+ public static enum Style {
+ SIMPLE("fore1"), FANCY("fore2"), GLOSSY("fore3");
+
+ public String id;
+
+ Style(String id) {
+ this.id = id;
+ }
+ }
+ }
+}
diff --git a/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java
new file mode 100644
index 0000000..07b7a6b
--- /dev/null
+++ b/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.assetstudiolib;
+
+import com.android.resources.Density;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * A {@link GraphicGenerator} that generates Android "menu" icons.
+ */
+public class MenuIconGenerator extends GraphicGenerator {
+ private static final Rectangle BASE_IMAGE_RECT = new Rectangle(0, 0, 48, 48);
+ private static final Rectangle BASE_TARGET_RECT = new Rectangle(8, 8, 32, 32);
+
+ private Options mOptions;
+
+ public MenuIconGenerator(GraphicGeneratorContext context, Options options) {
+ mOptions = options;
+ }
+
+ public BufferedImage generate() {
+ final float scaleFactor = GraphicGenerator.getScaleFactor(mOptions.density);
+ Rectangle imageRect = Util.scaleRectangle(BASE_IMAGE_RECT, scaleFactor);
+ Rectangle targetRect = Util.scaleRectangle(BASE_TARGET_RECT, scaleFactor);
+
+ BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
+ Graphics2D g = (Graphics2D) outImage.getGraphics();
+
+ {
+ BufferedImage tempImage = Util.newArgbBufferedImage(
+ imageRect.width, imageRect.height);
+ Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
+ Util.drawCenterInside(g2, mOptions.sourceImage, targetRect);
+
+ Util.drawEffects(g, tempImage, 0, 0, new Util.Effect[]{
+ new Util.FillEffect(
+ new GradientPaint(
+ 0, 0,
+ new Color(0xa3a3a3),
+ 0, imageRect.height,
+ new Color(0x787878))),
+ new Util.ShadowEffect(
+ 0,
+ 3 * scaleFactor,
+ 3 * scaleFactor,
+ Color.black,
+ 0.2,
+ true),
+ new Util.ShadowEffect(
+ 0,
+ 1,
+ 0,
+ Color.black,
+ 0.35,
+ true),
+ new Util.ShadowEffect(
+ 0,
+ -1,
+ 0,
+ Color.white,
+ 0.35,
+ true),
+ });
+ }
+
+ return outImage;
+ }
+
+ public static class Options {
+ public BufferedImage sourceImage;
+ public Density density = Density.XHIGH;
+ }
+}
diff --git a/assetstudio/src/com/android/assetstudiolib/Util.java b/assetstudio/src/com/android/assetstudiolib/Util.java
new file mode 100644
index 0000000..82299a4
--- /dev/null
+++ b/assetstudio/src/com/android/assetstudiolib/Util.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.assetstudiolib;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.awt.image.Raster;
+import java.awt.image.RescaleOp;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A set of utility classes for manipulating {@link BufferedImage} objects and drawing them to
+ * {@link Graphics2D} canvases.
+ */
+public class Util {
+ /**
+ * Scales the given rectangle by the given scale factor.
+ *
+ * @param rect The rectangle to scale.
+ * @param scaleFactor The factor to scale by.
+ * @return The scaled rectangle.
+ */
+ public static Rectangle scaleRectangle(Rectangle rect, float scaleFactor) {
+ return new Rectangle(
+ (int) (rect.x * scaleFactor),
+ (int) (rect.y * scaleFactor),
+ (int) (rect.width * scaleFactor),
+ (int) (rect.height * scaleFactor));
+ }
+
+ /**
+ * Creates a new ARGB {@link BufferedImage} of the given width and height.
+ *
+ * @param width The width of the new image.
+ * @param height The height of the new image.
+ * @return The newly created image.
+ */
+ public static BufferedImage newArgbBufferedImage(int width, int height) {
+ return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /**
+ * Smoothly scales the given {@link BufferedImage} to the given width and height using the
+ * {@link Image#SCALE_SMOOTH} algorithm (generally bicubic resampling or bilinear filtering).
+ *
+ * @param source The source image.
+ * @param width The destination width to scale to.
+ * @param height The destination height to scale to.
+ * @return A new, scaled image.
+ */
+ public static BufferedImage scaledImage(BufferedImage source, int width, int height) {
+ Image scaledImage = source.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+ BufferedImage scaledBufImage = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics g = scaledBufImage.createGraphics();
+ g.drawImage(scaledImage, 0, 0, null);
+ g.dispose();
+ return scaledBufImage;
+ }
+
+ /**
+ * Applies a gaussion blur of the given radius to the given {@link BufferedImage} using a kernel
+ * convolution.
+ *
+ * @param source The source image.
+ * @param radius The blur radius, in pixels.
+ * @return A new, blurred image, or the source image if no blur is performed.
+ */
+ public static BufferedImage blurredImage(BufferedImage source, double radius) {
+ if (radius == 0) {
+ return source;
+ }
+
+ final int r = (int) Math.ceil(radius);
+ final int rows = r * 2 + 1;
+ final float[] kernelData = new float[rows * rows];
+
+ final double sigma = radius / 3;
+ final double sigma22 = 2 * sigma * sigma;
+ final double sqrtPiSigma22 = Math.sqrt(Math.PI * sigma22);
+ final double radius2 = radius * radius;
+
+ double total = 0;
+ int index = 0;
+ double distance2;
+
+ int x, y;
+ for (y = -r; y <= r; y++) {
+ for (x = -r; x <= r; x++) {
+ distance2 = 1.0 * x * x + 1.0 * y * y;
+ if (distance2 > radius2) {
+ kernelData[index] = 0;
+ } else {
+ kernelData[index] = (float) (Math.exp(-distance2 / sigma22) / sqrtPiSigma22);
+ }
+ total += kernelData[index];
+ ++index;
+ }
+ }
+
+ for (index = 0; index < kernelData.length; index++) {
+ kernelData[index] /= total;
+ }
+
+ // We first pad the image so the kernel can operate at the edges.
+ BufferedImage paddedSource = paddedImage(source, r);
+ BufferedImage blurredPaddedImage = operatedImage(paddedSource, new ConvolveOp(
+ new Kernel(rows, rows, kernelData), ConvolveOp.EDGE_ZERO_FILL, null));
+ return blurredPaddedImage.getSubimage(r, r, source.getWidth(), source.getHeight());
+ }
+
+ /**
+ * Inverts the alpha channel of the given {@link BufferedImage}. RGB data for the inverted area
+ * are undefined, so it's generally best to fill the resulting image with a color.
+ *
+ * @param source The source image.
+ * @return A new image with an alpha channel inverted from the original.
+ */
+ public static BufferedImage invertedAlphaImage(BufferedImage source) {
+ final float[] scaleFactors = new float[]{1, 1, 1, -1};
+ final float[] offsets = new float[]{0, 0, 0, 255};
+
+ return operatedImage(source, new RescaleOp(scaleFactors, offsets, null));
+ }
+
+ /**
+ * Applies a {@link BufferedImageOp} on the given {@link BufferedImage}.
+ *
+ * @param source The source image.
+ * @param op The operation to perform.
+ * @return A new image with the operation performed.
+ */
+ public static BufferedImage operatedImage(BufferedImage source, BufferedImageOp op) {
+ BufferedImage newImage = newArgbBufferedImage(source.getWidth(), source.getHeight());
+ Graphics2D g = (Graphics2D) newImage.getGraphics();
+ g.drawImage(source, op, 0, 0);
+ return newImage;
+ }
+
+ /**
+ * Fills the given {@link BufferedImage} with a {@link Paint}, preserving its alpha channel.
+ *
+ * @param source The source image.
+ * @param paint The paint to fill with.
+ * @return A new, painted/filled image.
+ */
+ public static BufferedImage filledImage(BufferedImage source, Paint paint) {
+ BufferedImage newImage = newArgbBufferedImage(source.getWidth(), source.getHeight());
+ Graphics2D g = (Graphics2D) newImage.getGraphics();
+ g.drawImage(source, 0, 0, null);
+ g.setComposite(AlphaComposite.SrcAtop);
+ g.setPaint(paint);
+ g.fillRect(0, 0, source.getWidth(), source.getHeight());
+ return newImage;
+ }
+
+ /**
+ * Pads the given {@link BufferedImage} on all sides by the given padding amount.
+ *
+ * @param source The source image.
+ * @param padding The amount to pad on all sides, in pixels.
+ * @return A new, padded image, or the source image if no padding is performed.
+ */
+ public static BufferedImage paddedImage(BufferedImage source, int padding) {
+ if (padding == 0) {
+ return source;
+ }
+
+ BufferedImage newImage = newArgbBufferedImage(
+ source.getWidth() + padding * 2, source.getHeight() + padding * 2);
+ Graphics2D g = (Graphics2D) newImage.getGraphics();
+ g.drawImage(source, padding, padding, null);
+ return newImage;
+ }
+
+ /**
+ * Trims the transparent pixels from the given {@link BufferedImage} (returns a sub-image).
+ *
+ * @param source The source image.
+ * @return A new, trimmed image, or the source image if no trim is performed.
+ */
+ public static BufferedImage trimmedImage(BufferedImage source) {
+ final int minAlpha = 1;
+ final int srcWidth = source.getWidth();
+ final int srcHeight = source.getHeight();
+ Raster raster = source.getRaster();
+ int l = srcWidth, t = srcHeight, r = 0, b = 0;
+
+ int alpha, x, y;
+ int[] pixel = new int[4];
+ for (y = 0; y < srcHeight; y++) {
+ for (x = 0; x < srcWidth; x++) {
+ raster.getPixel(x, y, pixel);
+ alpha = pixel[3];
+ if (alpha >= minAlpha) {
+ l = Math.min(x, l);
+ t = Math.min(y, t);
+ r = Math.max(x, r);
+ b = Math.max(y, b);
+ }
+ }
+ }
+
+ if (l > r || t > b) {
+ // No pixels, couldn't trim
+ return source;
+ }
+
+ return source.getSubimage(l, t, r - l + 1, b - t + 1);
+ }
+
+ /**
+ * Draws the given {@link BufferedImage} to the canvas, at the given coordinates, with the given
+ * {@link Effect}s applied. Note that drawn effects may be outside the bounds of the source
+ * image.
+ *
+ * @param g The destination canvas.
+ * @param source The source image.
+ * @param x The x offset at which to draw the image.
+ * @param y The y offset at which to draw the image.
+ * @param effects The list of effects to apply.
+ */
+ public static void drawEffects(Graphics2D g, BufferedImage source, int x, int y,
+ Effect[] effects) {
+ List<ShadowEffect> shadowEffects = new ArrayList<ShadowEffect>();
+ List<FillEffect> fillEffects = new ArrayList<FillEffect>();
+
+ for (Effect effect : effects) {
+ if (effect instanceof ShadowEffect) {
+ shadowEffects.add((ShadowEffect) effect);
+ } else if (effect instanceof FillEffect) {
+ fillEffects.add((FillEffect) effect);
+ }
+ }
+
+ Composite oldComposite = g.getComposite();
+ for (ShadowEffect effect : shadowEffects) {
+ if (effect.inner) {
+ continue;
+ }
+
+ // Outer shadow
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC_OVER, (float) effect.opacity));
+ g.drawImage(
+ filledImage(
+ blurredImage(source, effect.radius),
+ effect.color),
+ (int) effect.xOffset, (int) effect.yOffset, null);
+ }
+ g.setComposite(oldComposite);
+
+ // Inner shadow & fill effects.
+ final Rectangle imageRect = new Rectangle(0, 0, source.getWidth(), source.getHeight());
+ BufferedImage out = newArgbBufferedImage(imageRect.width, imageRect.height);
+ Graphics2D g2 = (Graphics2D) out.getGraphics();
+
+ g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+ g2.drawImage(source, 0, 0, null);
+ g2.setComposite(AlphaComposite.SrcAtop);
+
+ // Gradient fill
+ for (FillEffect effect : fillEffects) {
+ g2.setPaint(effect.paint);
+ g2.fillRect(0, 0, imageRect.width, imageRect.height);
+ }
+
+ // Inner shadows
+ for (ShadowEffect effect : shadowEffects) {
+ if (!effect.inner) {
+ continue;
+ }
+
+ BufferedImage innerShadowImage = newArgbBufferedImage(
+ imageRect.width, imageRect.height);
+ Graphics2D g3 = (Graphics2D) innerShadowImage.getGraphics();
+ g3.drawImage(source, (int) effect.xOffset, (int) effect.yOffset, null);
+ g2.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC_ATOP, (float) effect.opacity));
+ g2.drawImage(
+ filledImage(
+ blurredImage(invertedAlphaImage(innerShadowImage), effect.radius),
+ effect.color),
+ 0, 0, null);
+ }
+
+ g.drawImage(out, x, y, null);
+ }
+
+ /**
+ * Draws the given {@link BufferedImage} to the canvas, centered, wholly contained within the
+ * bounds defined by the destination rectangle, and with preserved aspect ratio.
+ *
+ * @param g The destination canvas.
+ * @param source The source image.
+ * @param dstRect The destination rectangle in the destination canvas into which to draw the
+ * image.
+ */
+ public static void drawCenterInside(Graphics2D g, BufferedImage source, Rectangle dstRect) {
+ final int srcWidth = source.getWidth();
+ final int srcHeight = source.getHeight();
+ if (srcWidth * 1.0 / srcHeight > dstRect.width * 1.0 / dstRect.height) {
+ final int scaledWidth = dstRect.width;
+ final int scaledHeight = dstRect.width * srcHeight / srcWidth;
+ Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
+ g.drawImage(scaledImage,
+ dstRect.x,
+ dstRect.y + (dstRect.height - scaledHeight) / 2,
+ dstRect.x + dstRect.width,
+ dstRect.y + (dstRect.height - scaledHeight) / 2 + scaledHeight,
+ 0,
+ 0,
+ 0 + scaledWidth,
+ 0 + scaledHeight,
+ null);
+ } else {
+ final int scaledWidth = dstRect.height * srcWidth / srcHeight;
+ final int scaledHeight = dstRect.height;
+ Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
+ g.drawImage(scaledImage,
+ dstRect.x + (dstRect.width - scaledWidth) / 2,
+ dstRect.y,
+ dstRect.x + (dstRect.width - scaledWidth) / 2 + scaledWidth,
+ dstRect.y + dstRect.height,
+ 0,
+ 0,
+ 0 + scaledWidth,
+ 0 + scaledHeight,
+ null);
+ }
+ }
+
+ /**
+ * Draws the given {@link BufferedImage} to the canvas, centered and cropped to fill the
+ * bounds defined by the destination rectangle, and with preserved aspect ratio.
+ *
+ * @param g The destination canvas.
+ * @param source The source image.
+ * @param dstRect The destination rectangle in the destination canvas into which to draw the
+ * image.
+ */
+ public static void drawCenterCrop(Graphics2D g, BufferedImage source, Rectangle dstRect) {
+ final int srcWidth = source.getWidth();
+ final int srcHeight = source.getHeight();
+ if (srcWidth * 1.0 / srcHeight > dstRect.width * 1.0 / dstRect.height) {
+ final int scaledWidth = dstRect.height * srcWidth / srcHeight;
+ final int scaledHeight = dstRect.height;
+ Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
+ g.drawImage(scaledImage,
+ dstRect.x,
+ dstRect.y,
+ dstRect.x + dstRect.width,
+ dstRect.y + dstRect.height,
+ 0 + (scaledWidth - dstRect.width) / 2,
+ 0,
+ 0 + (scaledWidth - dstRect.width) / 2 + dstRect.width,
+ 0 + dstRect.height,
+ null);
+ } else {
+ final int scaledWidth = dstRect.width;
+ final int scaledHeight = dstRect.width * srcHeight / srcWidth;
+ Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
+ g.drawImage(scaledImage,
+ dstRect.x,
+ dstRect.y,
+ dstRect.x + dstRect.width,
+ dstRect.y + dstRect.height,
+ 0,
+ 0 + (scaledHeight - dstRect.height) / 2,
+ 0 + dstRect.width,
+ 0 + (scaledHeight - dstRect.height) / 2 + dstRect.height,
+ null);
+ }
+ }
+
+ /**
+ * An effect to apply in
+ * {@link Util#drawEffects(java.awt.Graphics2D, java.awt.image.BufferedImage, int, int, Util.Effect[])}
+ */
+ public static abstract class Effect {
+ }
+
+ /**
+ * An inner or outer shadow.
+ */
+ public static class ShadowEffect extends Effect {
+ public double xOffset;
+ public double yOffset;
+ public double radius;
+ public Color color;
+ public double opacity;
+ public boolean inner;
+
+ public ShadowEffect(double xOffset, double yOffset, double radius, Color color,
+ double opacity, boolean inner) {
+ this.xOffset = xOffset;
+ this.yOffset = yOffset;
+ this.radius = radius;
+ this.color = color;
+ this.opacity = opacity;
+ this.inner = inner;
+ }
+ }
+
+ /**
+ * A fill, defined by a paint.
+ */
+ public static class FillEffect extends Effect {
+ public Paint paint;
+
+ public FillEffect(Paint paint) {
+ this.paint = paint;
+ }
+ }
+}
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png
new file mode 100644
index 0000000..8e3dbc1
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png
new file mode 100644
index 0000000..79d75c0
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.png
new file mode 100644
index 0000000..594257a
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.png
new file mode 100644
index 0000000..65fb48b
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png
new file mode 100644
index 0000000..99e787a
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/ldpi/back.png b/assetstudio/src/images/launcher_stencil/circle/ldpi/back.png
new file mode 100644
index 0000000..d9a9fcc
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/ldpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.png
new file mode 100644
index 0000000..ecc3bc5
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.png b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.png
new file mode 100644
index 0000000..c86b59c
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.png b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.png
new file mode 100644
index 0000000..1ae4d31
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/ldpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/ldpi/mask.png
new file mode 100644
index 0000000..e537ad0
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/ldpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png
new file mode 100644
index 0000000..e165038
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png
new file mode 100644
index 0000000..c42af13
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.png
new file mode 100644
index 0000000..0c06821
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.png
new file mode 100644
index 0000000..01fe418
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png
new file mode 100644
index 0000000..19f18bf
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/back.png b/assetstudio/src/images/launcher_stencil/circle/web/back.png
new file mode 100644
index 0000000..191c677
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/web/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/fore1.png b/assetstudio/src/images/launcher_stencil/circle/web/fore1.png
new file mode 100644
index 0000000..7ea8096
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/web/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/fore2.png b/assetstudio/src/images/launcher_stencil/circle/web/fore2.png
new file mode 100644
index 0000000..5a76240
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/web/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/fore3.png b/assetstudio/src/images/launcher_stencil/circle/web/fore3.png
new file mode 100644
index 0000000..1794bff
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/web/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/mask.png b/assetstudio/src/images/launcher_stencil/circle/web/mask.png
new file mode 100644
index 0000000..8316d80
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/web/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png
new file mode 100644
index 0000000..e655af6
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png
new file mode 100644
index 0000000..639ccba
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.png
new file mode 100644
index 0000000..b922452
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.png
new file mode 100644
index 0000000..5f1c15e
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png
new file mode 100644
index 0000000..6dc3bc7
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/back.png b/assetstudio/src/images/launcher_stencil/square/hdpi/back.png
new file mode 100644
index 0000000..3e58211
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/hdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png
new file mode 100644
index 0000000..e76d493
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/fore2.png b/assetstudio/src/images/launcher_stencil/square/hdpi/fore2.png
new file mode 100644
index 0000000..ab28d8d
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/hdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/fore3.png b/assetstudio/src/images/launcher_stencil/square/hdpi/fore3.png
new file mode 100644
index 0000000..59f5e8f
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/hdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png
new file mode 100644
index 0000000..9c56fe6
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/ldpi/back.png b/assetstudio/src/images/launcher_stencil/square/ldpi/back.png
new file mode 100644
index 0000000..1a68be3
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/ldpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/ldpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/ldpi/fore1.png
new file mode 100644
index 0000000..c46e1c2
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/ldpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/ldpi/fore2.png b/assetstudio/src/images/launcher_stencil/square/ldpi/fore2.png
new file mode 100644
index 0000000..3bc8315
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/ldpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/ldpi/fore3.png b/assetstudio/src/images/launcher_stencil/square/ldpi/fore3.png
new file mode 100644
index 0000000..0bfa4f7
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/ldpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/ldpi/mask.png b/assetstudio/src/images/launcher_stencil/square/ldpi/mask.png
new file mode 100644
index 0000000..04d6d1a
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/ldpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/back.png b/assetstudio/src/images/launcher_stencil/square/mdpi/back.png
new file mode 100644
index 0000000..f49e513
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/mdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png
new file mode 100644
index 0000000..2837d41
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/fore2.png b/assetstudio/src/images/launcher_stencil/square/mdpi/fore2.png
new file mode 100644
index 0000000..566941f
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/mdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/fore3.png b/assetstudio/src/images/launcher_stencil/square/mdpi/fore3.png
new file mode 100644
index 0000000..9bcfc5e
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/mdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png
new file mode 100644
index 0000000..90e5cd0
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/back.png b/assetstudio/src/images/launcher_stencil/square/web/back.png
new file mode 100644
index 0000000..2f008b7
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/web/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/fore1.png b/assetstudio/src/images/launcher_stencil/square/web/fore1.png
new file mode 100644
index 0000000..527ac47
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/web/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/fore2.png b/assetstudio/src/images/launcher_stencil/square/web/fore2.png
new file mode 100644
index 0000000..5e557f8
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/web/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/fore3.png b/assetstudio/src/images/launcher_stencil/square/web/fore3.png
new file mode 100644
index 0000000..58d85af
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/web/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/mask.png b/assetstudio/src/images/launcher_stencil/square/web/mask.png
new file mode 100644
index 0000000..2c80196
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/web/mask.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png
new file mode 100644
index 0000000..84caac0
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png
new file mode 100644
index 0000000..2d237e1
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.png
new file mode 100644
index 0000000..cce5e0e
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.png
new file mode 100644
index 0000000..3b91aa4
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.png
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png
new file mode 100644
index 0000000..9e0bbdc
--- /dev/null
+++ b/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png
Binary files differ