From 7208e72d510e1bf5d3860f4a15d135e42d64eaa0 Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Fri, 15 Jul 2011 21:16:56 -0700 Subject: 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 --- assetstudio/.classpath | 7 + assetstudio/.gitignore | 2 + assetstudio/.project | 17 + assetstudio/.settings/org.eclipse.jdt.core.prefs | 71 ++ assetstudio/Android.mk | 30 + .../android/assetstudiolib/GraphicGenerator.java | 46 -- .../assetstudiolib/GraphicGeneratorContext.java | 33 - .../assetstudiolib/LauncherIconGenerator.java | 105 --- .../android/assetstudiolib/MenuIconGenerator.java | 90 --- .../src/com/android/assetstudiolib/Util.java | 440 ------------ .../res/launcher-stencil/circle/hdpi/back.png | Bin 1885 -> 0 bytes .../res/launcher-stencil/circle/hdpi/fore1.png | Bin 666 -> 0 bytes .../res/launcher-stencil/circle/hdpi/fore2.png | Bin 2922 -> 0 bytes .../res/launcher-stencil/circle/hdpi/fore3.png | Bin 4690 -> 0 bytes .../res/launcher-stencil/circle/hdpi/mask.png | Bin 992 -> 0 bytes .../res/launcher-stencil/circle/ldpi/back.png | Bin 745 -> 0 bytes .../res/launcher-stencil/circle/ldpi/fore1.png | Bin 376 -> 0 bytes .../res/launcher-stencil/circle/ldpi/fore2.png | Bin 1370 -> 0 bytes .../res/launcher-stencil/circle/ldpi/fore3.png | Bin 2432 -> 0 bytes .../res/launcher-stencil/circle/ldpi/mask.png | Bin 435 -> 0 bytes .../res/launcher-stencil/circle/mdpi/back.png | Bin 1162 -> 0 bytes .../res/launcher-stencil/circle/mdpi/fore1.png | Bin 457 -> 0 bytes .../res/launcher-stencil/circle/mdpi/fore2.png | Bin 1720 -> 0 bytes .../res/launcher-stencil/circle/mdpi/fore3.png | Bin 2926 -> 0 bytes .../res/launcher-stencil/circle/mdpi/mask.png | Bin 610 -> 0 bytes .../res/launcher-stencil/circle/web/back.png | Bin 29806 -> 0 bytes .../res/launcher-stencil/circle/web/fore1.png | Bin 30292 -> 0 bytes .../res/launcher-stencil/circle/web/fore2.png | Bin 59463 -> 0 bytes .../res/launcher-stencil/circle/web/fore3.png | Bin 61713 -> 0 bytes .../res/launcher-stencil/circle/web/mask.png | Bin 8447 -> 0 bytes .../res/launcher-stencil/circle/xhdpi/back.png | Bin 3451 -> 0 bytes .../res/launcher-stencil/circle/xhdpi/fore1.png | Bin 1746 -> 0 bytes .../res/launcher-stencil/circle/xhdpi/fore2.png | Bin 5054 -> 0 bytes .../res/launcher-stencil/circle/xhdpi/fore3.png | Bin 6239 -> 0 bytes .../res/launcher-stencil/circle/xhdpi/mask.png | Bin 2142 -> 0 bytes .../res/launcher-stencil/square/hdpi/back.png | Bin 713 -> 0 bytes .../res/launcher-stencil/square/hdpi/fore1.png | Bin 331 -> 0 bytes .../res/launcher-stencil/square/hdpi/fore2.png | Bin 1477 -> 0 bytes .../res/launcher-stencil/square/hdpi/fore3.png | Bin 3592 -> 0 bytes .../res/launcher-stencil/square/hdpi/mask.png | Bin 370 -> 0 bytes .../res/launcher-stencil/square/ldpi/back.png | Bin 295 -> 0 bytes .../res/launcher-stencil/square/ldpi/fore1.png | Bin 212 -> 0 bytes .../res/launcher-stencil/square/ldpi/fore2.png | Bin 693 -> 0 bytes .../res/launcher-stencil/square/ldpi/fore3.png | Bin 2061 -> 0 bytes .../res/launcher-stencil/square/ldpi/mask.png | Bin 205 -> 0 bytes .../res/launcher-stencil/square/mdpi/back.png | Bin 455 -> 0 bytes .../res/launcher-stencil/square/mdpi/fore1.png | Bin 239 -> 0 bytes .../res/launcher-stencil/square/mdpi/fore2.png | Bin 1010 -> 0 bytes .../res/launcher-stencil/square/mdpi/fore3.png | Bin 2510 -> 0 bytes .../res/launcher-stencil/square/mdpi/mask.png | Bin 250 -> 0 bytes .../res/launcher-stencil/square/web/back.png | Bin 10984 -> 0 bytes .../res/launcher-stencil/square/web/fore1.png | Bin 8562 -> 0 bytes .../res/launcher-stencil/square/web/fore2.png | Bin 26230 -> 0 bytes .../res/launcher-stencil/square/web/fore3.png | Bin 42175 -> 0 bytes .../res/launcher-stencil/square/web/mask.png | Bin 3786 -> 0 bytes .../res/launcher-stencil/square/xhdpi/back.png | Bin 1956 -> 0 bytes .../res/launcher-stencil/square/xhdpi/fore1.png | Bin 1289 -> 0 bytes .../res/launcher-stencil/square/xhdpi/fore2.png | Bin 2932 -> 0 bytes .../res/launcher-stencil/square/xhdpi/fore3.png | Bin 4649 -> 0 bytes .../res/launcher-stencil/square/xhdpi/mask.png | Bin 1396 -> 0 bytes .../android/assetstudiolib/GraphicGenerator.java | 52 ++ .../assetstudiolib/GraphicGeneratorContext.java | 33 + .../assetstudiolib/LauncherIconGenerator.java | 108 +++ .../android/assetstudiolib/MenuIconGenerator.java | 92 +++ .../src/com/android/assetstudiolib/Util.java | 440 ++++++++++++ .../images/launcher_stencil/circle/hdpi/back.png | Bin 0 -> 1885 bytes .../images/launcher_stencil/circle/hdpi/fore1.png | Bin 0 -> 666 bytes .../images/launcher_stencil/circle/hdpi/fore2.png | Bin 0 -> 2922 bytes .../images/launcher_stencil/circle/hdpi/fore3.png | Bin 0 -> 4690 bytes .../images/launcher_stencil/circle/hdpi/mask.png | Bin 0 -> 992 bytes .../images/launcher_stencil/circle/ldpi/back.png | Bin 0 -> 745 bytes .../images/launcher_stencil/circle/ldpi/fore1.png | Bin 0 -> 376 bytes .../images/launcher_stencil/circle/ldpi/fore2.png | Bin 0 -> 1370 bytes .../images/launcher_stencil/circle/ldpi/fore3.png | Bin 0 -> 2432 bytes .../images/launcher_stencil/circle/ldpi/mask.png | Bin 0 -> 435 bytes .../images/launcher_stencil/circle/mdpi/back.png | Bin 0 -> 1162 bytes .../images/launcher_stencil/circle/mdpi/fore1.png | Bin 0 -> 457 bytes .../images/launcher_stencil/circle/mdpi/fore2.png | Bin 0 -> 1720 bytes .../images/launcher_stencil/circle/mdpi/fore3.png | Bin 0 -> 2926 bytes .../images/launcher_stencil/circle/mdpi/mask.png | Bin 0 -> 610 bytes .../images/launcher_stencil/circle/web/back.png | Bin 0 -> 29806 bytes .../images/launcher_stencil/circle/web/fore1.png | Bin 0 -> 30292 bytes .../images/launcher_stencil/circle/web/fore2.png | Bin 0 -> 59463 bytes .../images/launcher_stencil/circle/web/fore3.png | Bin 0 -> 61713 bytes .../images/launcher_stencil/circle/web/mask.png | Bin 0 -> 8447 bytes .../images/launcher_stencil/circle/xhdpi/back.png | Bin 0 -> 3451 bytes .../images/launcher_stencil/circle/xhdpi/fore1.png | Bin 0 -> 1746 bytes .../images/launcher_stencil/circle/xhdpi/fore2.png | Bin 0 -> 5054 bytes .../images/launcher_stencil/circle/xhdpi/fore3.png | Bin 0 -> 6239 bytes .../images/launcher_stencil/circle/xhdpi/mask.png | Bin 0 -> 2142 bytes .../images/launcher_stencil/square/hdpi/back.png | Bin 0 -> 713 bytes .../images/launcher_stencil/square/hdpi/fore1.png | Bin 0 -> 331 bytes .../images/launcher_stencil/square/hdpi/fore2.png | Bin 0 -> 1477 bytes .../images/launcher_stencil/square/hdpi/fore3.png | Bin 0 -> 3592 bytes .../images/launcher_stencil/square/hdpi/mask.png | Bin 0 -> 370 bytes .../images/launcher_stencil/square/ldpi/back.png | Bin 0 -> 295 bytes .../images/launcher_stencil/square/ldpi/fore1.png | Bin 0 -> 212 bytes .../images/launcher_stencil/square/ldpi/fore2.png | Bin 0 -> 693 bytes .../images/launcher_stencil/square/ldpi/fore3.png | Bin 0 -> 2061 bytes .../images/launcher_stencil/square/ldpi/mask.png | Bin 0 -> 205 bytes .../images/launcher_stencil/square/mdpi/back.png | Bin 0 -> 455 bytes .../images/launcher_stencil/square/mdpi/fore1.png | Bin 0 -> 239 bytes .../images/launcher_stencil/square/mdpi/fore2.png | Bin 0 -> 1010 bytes .../images/launcher_stencil/square/mdpi/fore3.png | Bin 0 -> 2510 bytes .../images/launcher_stencil/square/mdpi/mask.png | Bin 0 -> 250 bytes .../images/launcher_stencil/square/web/back.png | Bin 0 -> 10984 bytes .../images/launcher_stencil/square/web/fore1.png | Bin 0 -> 8562 bytes .../images/launcher_stencil/square/web/fore2.png | Bin 0 -> 26230 bytes .../images/launcher_stencil/square/web/fore3.png | Bin 0 -> 42175 bytes .../images/launcher_stencil/square/web/mask.png | Bin 0 -> 3786 bytes .../images/launcher_stencil/square/xhdpi/back.png | Bin 0 -> 1956 bytes .../images/launcher_stencil/square/xhdpi/fore1.png | Bin 0 -> 1289 bytes .../images/launcher_stencil/square/xhdpi/fore2.png | Bin 0 -> 2932 bytes .../images/launcher_stencil/square/xhdpi/fore3.png | Bin 0 -> 4649 bytes .../images/launcher_stencil/square/xhdpi/mask.png | Bin 0 -> 1396 bytes .../plugins/com.android.ide.eclipse.adt/.classpath | 1 + .../META-INF/MANIFEST.MF | 3 +- .../icons/new_asset_set.png | Bin 0 -> 907 bytes .../plugins/com.android.ide.eclipse.adt/plugin.xml | 11 + .../com/android/ide/eclipse/adt/AdtConstants.java | 2 + .../internal/assetstudio/ChooseAssetTypePage.java | 217 ++++++ .../assetstudio/ConfigureAssetSetPage.java | 782 +++++++++++++++++++++ .../assetstudio/ConfigureLauncherAssetsPanel.java | 37 + .../internal/assetstudio/CreateAssetSetWizard.java | 249 +++++++ .../internal/resources/ResourceNameValidator.java | 32 +- .../wizards/newxmlfile/NewXmlFileWizard.java | 2 +- eclipse/scripts/create_adt_symlinks.sh | 2 +- 127 files changed, 2180 insertions(+), 724 deletions(-) create mode 100644 assetstudio/.classpath create mode 100644 assetstudio/.gitignore create mode 100644 assetstudio/.project create mode 100644 assetstudio/.settings/org.eclipse.jdt.core.prefs create mode 100644 assetstudio/Android.mk delete mode 100644 assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGenerator.java delete mode 100644 assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGeneratorContext.java delete mode 100644 assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/LauncherIconGenerator.java delete mode 100644 assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/MenuIconGenerator.java delete mode 100644 assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/Util.java delete mode 100644 assetstudio/res/launcher-stencil/circle/hdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/circle/hdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/circle/hdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/circle/hdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/circle/hdpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/circle/ldpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/circle/ldpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/circle/ldpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/circle/ldpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/circle/ldpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/circle/mdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/circle/mdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/circle/mdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/circle/mdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/circle/mdpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/circle/web/back.png delete mode 100644 assetstudio/res/launcher-stencil/circle/web/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/circle/web/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/circle/web/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/circle/web/mask.png delete mode 100644 assetstudio/res/launcher-stencil/circle/xhdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/circle/xhdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/circle/xhdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/circle/xhdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/circle/xhdpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/square/hdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/square/hdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/square/hdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/square/hdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/square/hdpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/square/ldpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/square/ldpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/square/ldpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/square/ldpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/square/ldpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/square/mdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/square/mdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/square/mdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/square/mdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/square/mdpi/mask.png delete mode 100644 assetstudio/res/launcher-stencil/square/web/back.png delete mode 100644 assetstudio/res/launcher-stencil/square/web/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/square/web/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/square/web/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/square/web/mask.png delete mode 100644 assetstudio/res/launcher-stencil/square/xhdpi/back.png delete mode 100644 assetstudio/res/launcher-stencil/square/xhdpi/fore1.png delete mode 100644 assetstudio/res/launcher-stencil/square/xhdpi/fore2.png delete mode 100644 assetstudio/res/launcher-stencil/square/xhdpi/fore3.png delete mode 100644 assetstudio/res/launcher-stencil/square/xhdpi/mask.png create mode 100644 assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java create mode 100644 assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java create mode 100644 assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java create mode 100644 assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java create mode 100644 assetstudio/src/com/android/assetstudiolib/Util.java create mode 100644 assetstudio/src/images/launcher_stencil/circle/hdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/ldpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/ldpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/mdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/web/back.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/web/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/web/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/web/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/web/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/square/hdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/square/hdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/square/hdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/square/hdpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/square/ldpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/square/ldpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/square/ldpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/square/ldpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/square/ldpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/square/mdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/square/mdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/square/mdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/square/mdpi/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/square/web/back.png create mode 100644 assetstudio/src/images/launcher_stencil/square/web/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/square/web/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/square/web/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/square/web/mask.png create mode 100644 assetstudio/src/images/launcher_stencil/square/xhdpi/back.png create mode 100644 assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png create mode 100644 assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.png create mode 100644 assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.png create mode 100644 assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/icons/new_asset_set.png create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ChooseAssetTypePage.java create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureLauncherAssetsPanel.java create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizard.java diff --git a/assetstudio/.classpath b/assetstudio/.classpath new file mode 100644 index 0000000..ee79d96 --- /dev/null +++ b/assetstudio/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assetstudio/.gitignore b/assetstudio/.gitignore new file mode 100644 index 0000000..fe99505 --- /dev/null +++ b/assetstudio/.gitignore @@ -0,0 +1,2 @@ +bin + diff --git a/assetstudio/.project b/assetstudio/.project new file mode 100644 index 0000000..f9aa2ce --- /dev/null +++ b/assetstudio/.project @@ -0,0 +1,17 @@ + + + assetstudio + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/assetstudio/.settings/org.eclipse.jdt.core.prefs b/assetstudio/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..e755df2 --- /dev/null +++ b/assetstudio/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,71 @@ +#Thu Jun 09 12:26:44 PDT 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning diff --git a/assetstudio/Android.mk b/assetstudio/Android.mk new file mode 100644 index 0000000..a48c3a0 --- /dev/null +++ b/assetstudio/Android.mk @@ -0,0 +1,30 @@ +# +# 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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_JAVA_RESOURCE_DIRS := src + +# TODO: Replace common with the batik stuff +LOCAL_JAVA_LIBRARIES := \ + common + +LOCAL_MODULE := assetstudio + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGenerator.java b/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGenerator.java deleted file mode 100644 index 25f7039..0000000 --- a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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; - -/** - * The base Generator class. - */ -public class GraphicGenerator { - /** - * Options used for all generators. - */ - public static class Options { - /** - * The screen density of the icon. - */ - public static enum Density { - LDPI("ldpi", 120), MDPI("mdpi", 160), HDPI("hdpi", 240), XHDPI("xhdpi", 320); - - public String id; - public int dpi; - - Density(String id, int dpi) { - this.id = id; - this.dpi = dpi; - } - - public float scaleFactor() { - return (float) this.dpi / 160; - } - } - } -} diff --git a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGeneratorContext.java b/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGeneratorContext.java deleted file mode 100644 index e0b00a6..0000000 --- a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/GraphicGeneratorContext.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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/libs/assetstudiolib/src/com/android/assetstudiolib/LauncherIconGenerator.java b/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/LauncherIconGenerator.java deleted file mode 100644 index e9cc65b..0000000 --- a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/LauncherIconGenerator.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.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("launcher-stencil/" - + options.shape.id + "/" + options.density.id + "/back.png"); - mForeImage = context.loadImageResource("launcher-stencil/" - + options.shape.id + "/" + options.density.id + "/" + options.style.id + ".png"); - mMaskImage = context.loadImageResource("launcher-stencil/" - + options.shape.id + "/" + options.density.id + "/mask.png"); - } - - public BufferedImage generate() { - final float scaleFactor = mOptions.density.scaleFactor(); - 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 GraphicGenerator.Options.Density density = GraphicGenerator.Options.Density.XHDPI; - - 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/libs/assetstudiolib/src/com/android/assetstudiolib/MenuIconGenerator.java b/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/MenuIconGenerator.java deleted file mode 100644 index bff6e42..0000000 --- a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/MenuIconGenerator.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.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 = mOptions.density.scaleFactor(); - 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 GraphicGenerator.Options.Density density = GraphicGenerator.Options.Density.XHDPI; - } -} diff --git a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/Util.java b/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/Util.java deleted file mode 100644 index 82299a4..0000000 --- a/assetstudio/libs/assetstudiolib/src/com/android/assetstudiolib/Util.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * 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 shadowEffects = new ArrayList(); - List fillEffects = new ArrayList(); - - 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/res/launcher-stencil/circle/hdpi/back.png b/assetstudio/res/launcher-stencil/circle/hdpi/back.png deleted file mode 100644 index 8e3dbc1..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/hdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/hdpi/fore1.png b/assetstudio/res/launcher-stencil/circle/hdpi/fore1.png deleted file mode 100644 index 79d75c0..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/hdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/hdpi/fore2.png b/assetstudio/res/launcher-stencil/circle/hdpi/fore2.png deleted file mode 100644 index 594257a..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/hdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/hdpi/fore3.png b/assetstudio/res/launcher-stencil/circle/hdpi/fore3.png deleted file mode 100644 index 65fb48b..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/hdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/hdpi/mask.png b/assetstudio/res/launcher-stencil/circle/hdpi/mask.png deleted file mode 100644 index 99e787a..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/hdpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/ldpi/back.png b/assetstudio/res/launcher-stencil/circle/ldpi/back.png deleted file mode 100644 index d9a9fcc..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/ldpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/ldpi/fore1.png b/assetstudio/res/launcher-stencil/circle/ldpi/fore1.png deleted file mode 100644 index ecc3bc5..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/ldpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/ldpi/fore2.png b/assetstudio/res/launcher-stencil/circle/ldpi/fore2.png deleted file mode 100644 index c86b59c..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/ldpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/ldpi/fore3.png b/assetstudio/res/launcher-stencil/circle/ldpi/fore3.png deleted file mode 100644 index 1ae4d31..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/ldpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/ldpi/mask.png b/assetstudio/res/launcher-stencil/circle/ldpi/mask.png deleted file mode 100644 index e537ad0..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/ldpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/mdpi/back.png b/assetstudio/res/launcher-stencil/circle/mdpi/back.png deleted file mode 100644 index e165038..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/mdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/mdpi/fore1.png b/assetstudio/res/launcher-stencil/circle/mdpi/fore1.png deleted file mode 100644 index c42af13..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/mdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/mdpi/fore2.png b/assetstudio/res/launcher-stencil/circle/mdpi/fore2.png deleted file mode 100644 index 0c06821..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/mdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/mdpi/fore3.png b/assetstudio/res/launcher-stencil/circle/mdpi/fore3.png deleted file mode 100644 index 01fe418..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/mdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/mdpi/mask.png b/assetstudio/res/launcher-stencil/circle/mdpi/mask.png deleted file mode 100644 index 19f18bf..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/mdpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/web/back.png b/assetstudio/res/launcher-stencil/circle/web/back.png deleted file mode 100644 index 191c677..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/web/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/web/fore1.png b/assetstudio/res/launcher-stencil/circle/web/fore1.png deleted file mode 100644 index 7ea8096..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/web/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/web/fore2.png b/assetstudio/res/launcher-stencil/circle/web/fore2.png deleted file mode 100644 index 5a76240..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/web/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/web/fore3.png b/assetstudio/res/launcher-stencil/circle/web/fore3.png deleted file mode 100644 index 1794bff..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/web/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/web/mask.png b/assetstudio/res/launcher-stencil/circle/web/mask.png deleted file mode 100644 index 8316d80..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/web/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/xhdpi/back.png b/assetstudio/res/launcher-stencil/circle/xhdpi/back.png deleted file mode 100644 index e655af6..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/xhdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/xhdpi/fore1.png b/assetstudio/res/launcher-stencil/circle/xhdpi/fore1.png deleted file mode 100644 index 639ccba..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/xhdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/xhdpi/fore2.png b/assetstudio/res/launcher-stencil/circle/xhdpi/fore2.png deleted file mode 100644 index b922452..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/xhdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/xhdpi/fore3.png b/assetstudio/res/launcher-stencil/circle/xhdpi/fore3.png deleted file mode 100644 index 5f1c15e..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/xhdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/circle/xhdpi/mask.png b/assetstudio/res/launcher-stencil/circle/xhdpi/mask.png deleted file mode 100644 index 6dc3bc7..0000000 Binary files a/assetstudio/res/launcher-stencil/circle/xhdpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/hdpi/back.png b/assetstudio/res/launcher-stencil/square/hdpi/back.png deleted file mode 100644 index 3e58211..0000000 Binary files a/assetstudio/res/launcher-stencil/square/hdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/hdpi/fore1.png b/assetstudio/res/launcher-stencil/square/hdpi/fore1.png deleted file mode 100644 index e76d493..0000000 Binary files a/assetstudio/res/launcher-stencil/square/hdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/hdpi/fore2.png b/assetstudio/res/launcher-stencil/square/hdpi/fore2.png deleted file mode 100644 index ab28d8d..0000000 Binary files a/assetstudio/res/launcher-stencil/square/hdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/hdpi/fore3.png b/assetstudio/res/launcher-stencil/square/hdpi/fore3.png deleted file mode 100644 index 59f5e8f..0000000 Binary files a/assetstudio/res/launcher-stencil/square/hdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/hdpi/mask.png b/assetstudio/res/launcher-stencil/square/hdpi/mask.png deleted file mode 100644 index 9c56fe6..0000000 Binary files a/assetstudio/res/launcher-stencil/square/hdpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/ldpi/back.png b/assetstudio/res/launcher-stencil/square/ldpi/back.png deleted file mode 100644 index 1a68be3..0000000 Binary files a/assetstudio/res/launcher-stencil/square/ldpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/ldpi/fore1.png b/assetstudio/res/launcher-stencil/square/ldpi/fore1.png deleted file mode 100644 index c46e1c2..0000000 Binary files a/assetstudio/res/launcher-stencil/square/ldpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/ldpi/fore2.png b/assetstudio/res/launcher-stencil/square/ldpi/fore2.png deleted file mode 100644 index 3bc8315..0000000 Binary files a/assetstudio/res/launcher-stencil/square/ldpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/ldpi/fore3.png b/assetstudio/res/launcher-stencil/square/ldpi/fore3.png deleted file mode 100644 index 0bfa4f7..0000000 Binary files a/assetstudio/res/launcher-stencil/square/ldpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/ldpi/mask.png b/assetstudio/res/launcher-stencil/square/ldpi/mask.png deleted file mode 100644 index 04d6d1a..0000000 Binary files a/assetstudio/res/launcher-stencil/square/ldpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/mdpi/back.png b/assetstudio/res/launcher-stencil/square/mdpi/back.png deleted file mode 100644 index f49e513..0000000 Binary files a/assetstudio/res/launcher-stencil/square/mdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/mdpi/fore1.png b/assetstudio/res/launcher-stencil/square/mdpi/fore1.png deleted file mode 100644 index 2837d41..0000000 Binary files a/assetstudio/res/launcher-stencil/square/mdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/mdpi/fore2.png b/assetstudio/res/launcher-stencil/square/mdpi/fore2.png deleted file mode 100644 index 566941f..0000000 Binary files a/assetstudio/res/launcher-stencil/square/mdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/mdpi/fore3.png b/assetstudio/res/launcher-stencil/square/mdpi/fore3.png deleted file mode 100644 index 9bcfc5e..0000000 Binary files a/assetstudio/res/launcher-stencil/square/mdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/mdpi/mask.png b/assetstudio/res/launcher-stencil/square/mdpi/mask.png deleted file mode 100644 index 90e5cd0..0000000 Binary files a/assetstudio/res/launcher-stencil/square/mdpi/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/web/back.png b/assetstudio/res/launcher-stencil/square/web/back.png deleted file mode 100644 index 2f008b7..0000000 Binary files a/assetstudio/res/launcher-stencil/square/web/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/web/fore1.png b/assetstudio/res/launcher-stencil/square/web/fore1.png deleted file mode 100644 index 527ac47..0000000 Binary files a/assetstudio/res/launcher-stencil/square/web/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/web/fore2.png b/assetstudio/res/launcher-stencil/square/web/fore2.png deleted file mode 100644 index 5e557f8..0000000 Binary files a/assetstudio/res/launcher-stencil/square/web/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/web/fore3.png b/assetstudio/res/launcher-stencil/square/web/fore3.png deleted file mode 100644 index 58d85af..0000000 Binary files a/assetstudio/res/launcher-stencil/square/web/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/web/mask.png b/assetstudio/res/launcher-stencil/square/web/mask.png deleted file mode 100644 index 2c80196..0000000 Binary files a/assetstudio/res/launcher-stencil/square/web/mask.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/xhdpi/back.png b/assetstudio/res/launcher-stencil/square/xhdpi/back.png deleted file mode 100644 index 84caac0..0000000 Binary files a/assetstudio/res/launcher-stencil/square/xhdpi/back.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/xhdpi/fore1.png b/assetstudio/res/launcher-stencil/square/xhdpi/fore1.png deleted file mode 100644 index 2d237e1..0000000 Binary files a/assetstudio/res/launcher-stencil/square/xhdpi/fore1.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/xhdpi/fore2.png b/assetstudio/res/launcher-stencil/square/xhdpi/fore2.png deleted file mode 100644 index cce5e0e..0000000 Binary files a/assetstudio/res/launcher-stencil/square/xhdpi/fore2.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/xhdpi/fore3.png b/assetstudio/res/launcher-stencil/square/xhdpi/fore3.png deleted file mode 100644 index 3b91aa4..0000000 Binary files a/assetstudio/res/launcher-stencil/square/xhdpi/fore3.png and /dev/null differ diff --git a/assetstudio/res/launcher-stencil/square/xhdpi/mask.png b/assetstudio/res/launcher-stencil/square/xhdpi/mask.png deleted file mode 100644 index 9e0bbdc..0000000 Binary files a/assetstudio/res/launcher-stencil/square/xhdpi/mask.png and /dev/null differ 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 shadowEffects = new ArrayList(); + List fillEffects = new ArrayList(); + + 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/ldpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/ldpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/ldpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/web/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/web/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/web/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/web/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/web/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/hdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/hdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/hdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/ldpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/ldpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/ldpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/ldpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/ldpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/mdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/mdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/mdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/web/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/web/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/web/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/web/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/web/mask.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore2.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore3.png 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 Binary files /dev/null and b/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png differ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath index 7a693db..a77b6b6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath +++ b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath @@ -13,6 +13,7 @@ + diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index aa4d55e..9218d6d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Bundle-ClassPath: ., libs/kxml2-2.3.0.jar, libs/layoutlib_api.jar, libs/ide_common.jar, - libs/common.jar + libs/common.jar, + libs/assetstudio.jar Bundle-Activator: com.android.ide.eclipse.adt.AdtPlugin Bundle-Vendor: The Android Open Source Project Require-Bundle: com.android.ide.eclipse.ddms, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_asset_set.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_asset_set.png new file mode 100644 index 0000000..108dcb1 Binary files /dev/null and b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_asset_set.png differ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 9a956d3..32442b6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -140,6 +140,17 @@ preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective" project="false"> + diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index 1eaa4b9..ac2e4dd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -118,6 +118,8 @@ public class AdtConstants { public static final String DOT_JPG = ".jpg"; //$NON-NLS-1$ /** Dot-Extension for BMP files, i.e. ".bmp" */ public static final String DOT_BMP = ".bmp"; //$NON-NLS-1$ + /** Dot-Extension for SVG files, i.e. ".svg" */ + public static final String DOT_SVG = ".svg"; //$NON-NLS-1$ /** Name of the android sources directory */ public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ChooseAssetTypePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ChooseAssetTypePage.java new file mode 100644 index 0000000..a5b0480 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ChooseAssetTypePage.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2011 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.assetstudio; + +import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; +import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; +import com.android.resources.ResourceFolderType; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +public class ChooseAssetTypePage extends WizardPage implements SelectionListener, ModifyListener { + private Text mProjectText; + private Button mBrowseButton; + private ProjectChooserHelper mProjectChooserHelper; + private IProject mProject; + private Text mNameText; + + /** + * Create the wizard. + */ + public ChooseAssetTypePage() { + super("chooseAssetTypePage"); + setTitle("Choose Asset Set Type"); + setDescription("Select the type of asset set to create:"); + } + + /** + * Create contents of the wizard. + * + * @param parent the parent composite + */ + @SuppressWarnings("unused") + public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NULL); + + setControl(container); + container.setLayout(new GridLayout(3, false)); + + Button launcherIcons = new Button(container, SWT.RADIO); + launcherIcons.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + launcherIcons.setSelection(true); + launcherIcons.setText("Launcher Icons"); + + Button menuIcons = new Button(container, SWT.RADIO); + menuIcons.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + menuIcons.setEnabled(false); + menuIcons.setText("Menu Icons"); + + Button actionBarIcons = new Button(container, SWT.RADIO); + actionBarIcons.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + actionBarIcons.setEnabled(false); + actionBarIcons.setText("Action Bar Icons (Android 3.0+)"); + + Button tabIcons = new Button(container, SWT.RADIO); + tabIcons.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + tabIcons.setEnabled(false); + tabIcons.setText("Tab Icons"); + + Button notificationIcons = new Button(container, SWT.RADIO); + notificationIcons.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + notificationIcons.setEnabled(false); + notificationIcons.setText("Notification Icons"); + + mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), null /*filter*/); + + Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gdSeparator = new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1); + gdSeparator.heightHint = 20; + separator.setLayoutData(gdSeparator); + + Label projectLabel = new Label(container, SWT.NONE); + projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + projectLabel.setText("Project:"); + + mProjectText = new Text(container, SWT.BORDER); + mProjectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + if (mProject != null) { + mProjectText.setText(mProject.getName()); + } + mProjectText.addModifyListener(this); + + mBrowseButton = new Button(container, SWT.FLAT); + mBrowseButton.setText("Browse..."); + mBrowseButton.setToolTipText("Allows you to select the Android project to modify."); + + Label assetLabel = new Label(container, SWT.NONE); + assetLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + assetLabel.setText("Asset Name:"); + + mNameText = new Text(container, SWT.BORDER); + mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + mNameText.setText("ic_launcher"); + mNameText.addModifyListener(this); + new Label(container, SWT.NONE); + mBrowseButton.addSelectionListener(this); + + validatePage(); + parent.getDisplay().asyncExec(new Runnable() { + public void run() { + mNameText.setFocus(); + } + }); + } + + void setProject(IProject project) { + mProject = project; + } + + IProject getProject() { + return mProject; + } + + @Override + public boolean canFlipToNextPage() { + return mProject != null; + } + + public void widgetSelected(SelectionEvent e) { + if (e.getSource() == mBrowseButton) { + IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectText.getText(), + "Please select the target project"); + if (p != null) { + changeProject(p.getProject()); + mProjectText.setText(mProject.getName()); + } + + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + + public void modifyText(ModifyEvent e) { + String project = mProjectText.getText(); + + // Is this a valid project? + IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null /*javaModel*/); + IProject found = null; + for (IJavaProject p : projects) { + if (p.getProject().getName().equals(project)) { + found = p.getProject(); + break; + } + } + + if (found != mProject) { + changeProject(found); + } + + validatePage(); + } + + private void changeProject(IProject newProject) { + mProject = newProject; + validatePage(); + } + + String getOutputName() { + return mNameText.getText().trim(); + } + + private void validatePage() { + String error = null; + //String warning = null; + + if (getProject() == null) { + error = "Please select an Android project."; + } + + String outputName = getOutputName(); + if (outputName == null || outputName.length() == 0) { + error = "Please enter a name"; + } else { + ResourceNameValidator validator = + ResourceNameValidator.create(true, ResourceFolderType.DRAWABLE); + error = validator.isValid(outputName); + } + + setPageComplete(error == null); + if (error != null) { + setMessage(error, IMessageProvider.ERROR); + //} else if (warning != null) { + // setMessage(warning, IMessageProvider.WARNING); + } else { + setErrorMessage(null); + setMessage(null); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java new file mode 100644 index 0000000..b871d1e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2011 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.assetstudio; + +import static com.android.assetstudiolib.LauncherIconGenerator.Options.Shape.CIRCLE; +import static com.android.assetstudiolib.LauncherIconGenerator.Options.Shape.SQUARE; + +import com.android.assetstudiolib.GraphicGenerator; +import com.android.assetstudiolib.GraphicGeneratorContext; +import com.android.assetstudiolib.LauncherIconGenerator; +import com.android.assetstudiolib.LauncherIconGenerator.Options.Style; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils; +import com.android.resources.Density; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.FontDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Slider; +import org.eclipse.swt.widgets.Text; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.imageio.ImageIO; + +/** + * This is normally page 2 of a Create New Asset Set wizard, unless we can offer actions + * to create a specific asset type, in which case we skip page 1. On this page the user + * gets to configure the parameters of the asset, and see a preview. + */ +public class ConfigureAssetSetPage extends WizardPage implements SelectionListener, + GraphicGeneratorContext, ModifyListener { + + private Composite configurationArea; + private Button mImageRadio; + private Button mClipartRadio; + private Button mTextRadio; + private Button mPickImageButton; + private Button mTrimCheckBox; + private Slider mPaddingSlider; + private Label mPercentLabel; + private Button mCropRadio; + private Button mCenterRadio; + private Button mSquareRadio; + private Button mCircleButton; + private Button mBgButton; + private Button mFgButton; + private Button mSimpleRadio; + private Button mFancyRadio; + private Button mGlossyRadio; + private Composite mPreviewArea; + private Button mFontButton; + private Composite mForegroundArea; + private Composite mImageForm; + private Composite mClipartForm; + private Composite mTextForm; + private Text mImagePathText; + + private boolean mTimerPending; + private Map mImageCache = new HashMap(); + private RGB mBgColor; + private RGB mFgColor; + private Text mText; + + /** Most recently set image path: preserved across wizard sessions */ + private static String sImagePath; + + /** + * Create the wizard. + * + * @param wizard the surrounding wizard + */ + public ConfigureAssetSetPage() { + super("configureAssetPage"); + setTitle("Configure Asset Set"); + setDescription("Configure the attributes of the asset set"); + } + + /** + * Create contents of the wizard. + * + * @param parent the parent widget + */ + @SuppressWarnings("unused") // Don't warn about unassigned "new Label(.)": has side-effect + public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NULL); + + setControl(container); + GridLayout glContainer = new GridLayout(2, false); + glContainer.marginWidth = 0; + glContainer.horizontalSpacing = 0; + glContainer.marginHeight = 0; + glContainer.verticalSpacing = 0; + container.setLayout(glContainer); + + ScrolledComposite configurationScrollArea = new ScrolledComposite(container, SWT.V_SCROLL); + configurationScrollArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2)); + configurationScrollArea.setExpandHorizontal(true); + configurationScrollArea.setExpandVertical(true); + + configurationArea = new Composite(configurationScrollArea, SWT.NONE); + GridLayout glConfigurationArea = new GridLayout(3, false); + glConfigurationArea.marginRight = 15; + glConfigurationArea.marginWidth = 0; + glConfigurationArea.marginHeight = 0; + configurationArea.setLayout(glConfigurationArea); + + Label foregroundLabel = new Label(configurationArea, SWT.NONE); + foregroundLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + foregroundLabel.setText("Foreground:"); + + Composite foregroundComposite = new Composite(configurationArea, SWT.NONE); + foregroundComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); + GridLayout glForegroundComposite = new GridLayout(5, false); + glForegroundComposite.horizontalSpacing = 0; + foregroundComposite.setLayout(glForegroundComposite); + + mImageRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); + mImageRadio.setSelection(true); + mImageRadio.addSelectionListener(this); + mImageRadio.setText("Image"); + + mClipartRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); + mClipartRadio.setEnabled(false); + mClipartRadio.setText("Clipart"); + mClipartRadio.addSelectionListener(this); + + mTextRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); + mTextRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + mTextRadio.setText("Text"); + mTextRadio.addSelectionListener(this); + new Label(configurationArea, SWT.NONE); + + mForegroundArea = new Composite(configurationArea, SWT.NONE); + mForegroundArea.setLayout(new StackLayout()); + mForegroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); + + mImageForm = new Composite(mForegroundArea, SWT.NONE); + mImageForm.setLayout(new GridLayout(3, false)); + + Label fileLabel = new Label(mImageForm, SWT.NONE); + fileLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + fileLabel.setText("Image File:"); + + mImagePathText = new Text(mImageForm, SWT.BORDER); + GridData pathLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); + pathLayoutData.widthHint = 200; + mImagePathText.setLayoutData(pathLayoutData); + mImagePathText.addSelectionListener(this); + mImagePathText.addModifyListener(this); + + mPickImageButton = new Button(mImageForm, SWT.FLAT); + mPickImageButton.setText("Browse..."); + mPickImageButton.addSelectionListener(this); + + mClipartForm = new Composite(mForegroundArea, SWT.V_SCROLL); + mClipartForm.setLayout(new FillLayout(SWT.HORIZONTAL)); + + mTextForm = new Composite(mForegroundArea, SWT.NONE); + mTextForm.setLayout(new GridLayout(2, false)); + + Label textLabel = new Label(mTextForm, SWT.NONE); + textLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + textLabel.setText("Text:"); + + mText = new Text(mTextForm, SWT.BORDER); + mText.setText("Label"); + mText.setLayoutData(pathLayoutData); + + Label fontLabel = new Label(mTextForm, SWT.NONE); + fontLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + fontLabel.setText("Font:"); + + mFontButton = new Button(mTextForm, SWT.FLAT); + mFontButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); + mFontButton.addSelectionListener(this); + mFontButton.setText("Choose Font..."); + new Label(configurationArea, SWT.NONE); + + mTrimCheckBox = new Button(configurationArea, SWT.CHECK); + mTrimCheckBox.setEnabled(false); + mTrimCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + mTrimCheckBox.setSelection(true); + mTrimCheckBox.setText("Trim Surrounding Blank Space"); + new Label(configurationArea, SWT.NONE); + + Label paddingLabel = new Label(configurationArea, SWT.NONE); + paddingLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + paddingLabel.setText("Additional Padding:"); + new Label(configurationArea, SWT.NONE); + + mPaddingSlider = new Slider(configurationArea, SWT.NONE); + mPaddingSlider.setEnabled(false); + mPaddingSlider.setLayoutData(pathLayoutData); + // This doesn't work right -- not sure why. For now just use a plain slider + // and subtract from it to get the real range. + //mPaddingSlider.setValues(0, -10, 50, 0, 1, 10); + mPaddingSlider.setSelection(10); + mPaddingSlider.addSelectionListener(this); + + mPercentLabel = new Label(configurationArea, SWT.NONE); + mPercentLabel.setText(" 0%"); // Enough available space for -10% + + Label scalingLabel = new Label(configurationArea, SWT.NONE); + scalingLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + scalingLabel.setText("Foreground Scaling:"); + + Composite scalingComposite = new Composite(configurationArea, SWT.NONE); + scalingComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); + GridLayout glScalingComposite = new GridLayout(5, false); + glScalingComposite.horizontalSpacing = 0; + scalingComposite.setLayout(glScalingComposite); + + mCropRadio = new Button(scalingComposite, SWT.FLAT | SWT.TOGGLE); + mCropRadio.setSelection(true); + mCropRadio.setText("Crop"); + mCropRadio.addSelectionListener(this); + + mCenterRadio = new Button(scalingComposite, SWT.FLAT | SWT.TOGGLE); + mCenterRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); + mCenterRadio.setText("Center"); + mCenterRadio.addSelectionListener(this); + + Label shapeLabel = new Label(configurationArea, SWT.NONE); + shapeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + shapeLabel.setText("Shape"); + + Composite shapeComposite = new Composite(configurationArea, SWT.NONE); + shapeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); + GridLayout glShapeComposite = new GridLayout(5, false); + glShapeComposite.horizontalSpacing = 0; + shapeComposite.setLayout(glShapeComposite); + + mSquareRadio = new Button(shapeComposite, SWT.FLAT | SWT.TOGGLE); + mSquareRadio.setSelection(true); + mSquareRadio.setText("Square"); + mSquareRadio.addSelectionListener(this); + + mCircleButton = new Button(shapeComposite, SWT.FLAT | SWT.TOGGLE); + mCircleButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); + mCircleButton.setText("Circle"); + mCircleButton.addSelectionListener(this); + + Label bgColorLabel = new Label(configurationArea, SWT.NONE); + bgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + bgColorLabel.setText("Background Color:"); + + mBgButton = new Button(configurationArea, SWT.FLAT); + mBgButton.addSelectionListener(this); + mBgButton.setAlignment(SWT.CENTER); + new Label(configurationArea, SWT.NONE); + + Label fgColorLabel = new Label(configurationArea, SWT.NONE); + fgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + fgColorLabel.setText("Foreground Color:"); + + mFgButton = new Button(configurationArea, SWT.FLAT); + mFgButton.setAlignment(SWT.CENTER); + mFgButton.addSelectionListener(this); + new Label(configurationArea, SWT.NONE); + + Label effectsLabel = new Label(configurationArea, SWT.NONE); + effectsLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + effectsLabel.setText("Foreground Effects:"); + + Composite effectsComposite = new Composite(configurationArea, SWT.NONE); + effectsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1)); + GridLayout glEffectsComposite = new GridLayout(5, false); + glEffectsComposite.horizontalSpacing = 0; + effectsComposite.setLayout(glEffectsComposite); + + mSimpleRadio = new Button(effectsComposite, SWT.FLAT | SWT.TOGGLE); + mSimpleRadio.setEnabled(false); + mSimpleRadio.setSelection(true); + mSimpleRadio.setText("Simple"); + mSimpleRadio.addSelectionListener(this); + + mFancyRadio = new Button(effectsComposite, SWT.FLAT | SWT.TOGGLE); + mFancyRadio.setEnabled(false); + mFancyRadio.setText("Fancy"); + mFancyRadio.addSelectionListener(this); + + mGlossyRadio = new Button(effectsComposite, SWT.FLAT | SWT.TOGGLE); + mGlossyRadio.setEnabled(false); + mGlossyRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); + mGlossyRadio.setText("Glossy"); + mGlossyRadio.addSelectionListener(this); + + new Label(configurationArea, SWT.NONE); + configurationScrollArea.setContent(configurationArea); + configurationScrollArea.setMinSize(configurationArea.computeSize(SWT.DEFAULT, + SWT.DEFAULT)); + + Label previewLabel = new Label(container, SWT.NONE); + previewLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1)); + previewLabel.setText("Preview:"); + + mPreviewArea = new Composite(container, SWT.BORDER); + + RowLayout rlPreviewAreaPreviewArea = new RowLayout(SWT.VERTICAL); + rlPreviewAreaPreviewArea.wrap = false; + rlPreviewAreaPreviewArea.pack = true; + rlPreviewAreaPreviewArea.center = true; + rlPreviewAreaPreviewArea.spacing = 0; + rlPreviewAreaPreviewArea.marginBottom = 0; + rlPreviewAreaPreviewArea.marginTop = 0; + rlPreviewAreaPreviewArea.marginRight = 0; + rlPreviewAreaPreviewArea.marginLeft = 0; + mPreviewArea.setLayout(rlPreviewAreaPreviewArea); + GridData gdMPreviewArea = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); + gdMPreviewArea.widthHint = 120; + mPreviewArea.setLayoutData(gdMPreviewArea); + + // Initial color + Display display = parent.getDisplay(); + updateColor(display, new RGB(0xa4, 0xc6, 0x39), true /*background*/); + updateColor(display, new RGB(0x00, 0x00, 0x00), false /*background*/); + + // Start out showing the image form + mImageRadio.setSelection(true); + chooseForegroundTab(mImageRadio, mImageForm); + validatePage(); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + + // We update the image selection here rather than in {@link #createControl} because + // that method is called when the wizard is created, and we want to wait until the + // user has chosen a project before attempting to look up the right default image to use + if (visible) { + // Initial image - use the most recently used image, or the default launcher + // icon created in our default projects, if there + if (sImagePath == null) { + IProject project = ((CreateAssetSetWizard) getWizard()).getProject(); + if (project != null) { + IResource icon = project.findMember("res/drawable-hdpi/icon.png"); //$NON-NLS-1$ + if (icon != null) { + IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); + IPath workspacePath = workspace.getLocation(); + sImagePath = workspacePath.append(icon.getFullPath()).toOSString(); + } + } + } + if (sImagePath != null) { + mImagePathText.setText(sImagePath); + } + validatePage(); + } + } + + private boolean validatePage() { + String error = null; + //String warning = null; + + if (mImageRadio.getSelection()) { + String path = mImagePathText.getText().trim(); + if (path.length() == 0) { + error = "Select an image"; + } else if (!(new File(path).exists())) { + error = String.format("%1$s does not exist", path); + } else { + // Preserve across wizard sessions + sImagePath = path; + } + } else { + error = "Clipart and Text not yet implemented"; + } + + setPageComplete(error == null); + if (error != null) { + setMessage(error, IMessageProvider.ERROR); + //} else if (warning != null) { + // setMessage(warning, IMessageProvider.WARNING); + } else { + setErrorMessage(null); + setMessage(null); + } + + return error == null; + } + + // ---- Implements ModifyListener ---- + + public void modifyText(ModifyEvent e) { + if (e.getSource() == mImagePathText) { + requestUpdatePreview(false); + } + + validatePage(); + } + + // ---- Implements SelectionListener ---- + + public void widgetDefaultSelected(SelectionEvent e) { + // Nothing to do + } + + public void widgetSelected(SelectionEvent e) { + Object source = e.getSource(); + boolean updateQuickly = true; + + // Tabs + if (source == mImageRadio) { + chooseForegroundTab((Button) source, mImageForm); + } else if (source == mClipartRadio) { + chooseForegroundTab((Button) source, mClipartForm); + } else if (source == mTextRadio) { + updateFontLabel(mFontButton.getFont()); + chooseForegroundTab((Button) source, mTextForm); + mText.setFocus(); + } + + // Choose image file + if (source == mPickImageButton) { + FileDialog dialog = new FileDialog(mPickImageButton.getShell(), SWT.OPEN); + String file = dialog.open(); + if (file != null) { + mImagePathText.setText(file); + } + } + + // Enforce Radio Groups + if (source == mCropRadio) { + mCenterRadio.setSelection(false); + } else if (source == mCenterRadio) { + mCropRadio.setSelection(false); + } + if (source == mSquareRadio) { + mCircleButton.setSelection(false); + } else if (source == mCircleButton) { + mSquareRadio.setSelection(false); + } + if (source == mSimpleRadio) { + mGlossyRadio.setSelection(false); + mFancyRadio.setSelection(false); + } else if (source == mFancyRadio) { + mSimpleRadio.setSelection(false); + mGlossyRadio.setSelection(false); + } else if (source == mGlossyRadio) { + mSimpleRadio.setSelection(false); + mFancyRadio.setSelection(false); + } + + if (source == mBgButton) { + ColorDialog dlg = new ColorDialog(mBgButton.getShell()); + dlg.setRGB(mBgColor); + dlg.setText("Choose a new Background Color"); + RGB rgb = dlg.open(); + if (rgb != null) { + // Dispose the old color, create the + // new one, and set into the label + updateColor(mBgButton.getDisplay(), rgb, true /*background*/); + } + } else if (source == mFgButton) { + ColorDialog dlg = new ColorDialog(mFgButton.getShell()); + dlg.setRGB(mFgColor); + dlg.setText("Choose a new Foreground Color"); + RGB rgb = dlg.open(); + if (rgb != null) { + // Dispose the old color, create the + // new one, and set into the label + updateColor(mFgButton.getDisplay(), rgb, false /*background*/); + } + } + + if (source == mFontButton) { + FontDialog dialog = new FontDialog(mFontButton.getShell()); + FontData data = dialog.open(); + if (data != null) { + Font font = new Font(mFontButton.getDisplay(), dialog.getFontList()); + mFontButton.setFont(font); + updateFontLabel(font); + mFontButton.getParent().pack(); + } + } + + if (source == mPaddingSlider) { + mPercentLabel.setText(Integer.toString(getPadding()) + '%'); + + // When dragging the slider, only do periodic updates + updateQuickly = false; + } + + requestUpdatePreview(updateQuickly); + } + + private void updateFontLabel(Font f) { + FontData[] fd = f.getFontData(); + FontData primary = fd[0]; + String description = String.format("%1$s %2$s", primary.name, + Integer.toString((int) primary.height)); + mFontButton.setText(description); + } + + private java.awt.Font getSelectedFont() { + Font font = mFontButton.getFont(); + FontData fontData = font.getFontData()[0]; + + int awtStyle = java.awt.Font.PLAIN; + int swtStyle = fontData.getStyle(); + + if ((swtStyle & SWT.ITALIC) != 0) { + awtStyle |= java.awt.Font.ITALIC; + } + if ((swtStyle & SWT.BOLD) != 0) { + awtStyle = java.awt.Font.BOLD; + } + + int dpi = mFontButton.getDisplay().getDPI().y; + int height = (int) Math.round(fontData.getHeight() * dpi / 72.0); + + return new java.awt.Font(fontData.getName(), awtStyle, height); + } + + private int getPadding() { + // Shifted - see comment for mPaddingSlider construction for an explanation + return mPaddingSlider.getSelection() - 10; + } + + public void chooseForegroundTab(Button newButton, Composite newArea) { + if (newButton.getSelection()) { + mImageRadio.setSelection(false); + mClipartRadio.setSelection(false); + mTextRadio.setSelection(false); + newButton.setSelection(true); + StackLayout stackLayout = (StackLayout) mForegroundArea.getLayout(); + stackLayout.topControl = newArea; + mForegroundArea.layout(); + } + } + + /** + * Delay updates of the preview, to ensure that the SWT UI acts immediately (to handle + * radio group selections etc). + * + * @param quickly if true, update the previews soon, otherwise schedule one a bit later + */ + private void requestUpdatePreview(boolean quickly) { + if (mTimerPending) { + return; + } + mTimerPending = true; + + final Runnable timer = new Runnable() { + public void run() { + mTimerPending = false; + updatePreview(); + } + }; + + mPreviewArea.getDisplay().timerExec(quickly ? 10 : 250, timer); + } + + private void updatePreview() { + Display display = mPreviewArea.getDisplay(); + + for (Control c : mPreviewArea.getChildren()) { + c.dispose(); + } + + if (!validatePage()) { + return; + } + + Map map = generatePreviews(); + for (Map.Entry entry : map.entrySet()) { + String id = entry.getKey(); + BufferedImage image = entry.getValue(); + Label nameLabel = new Label(mPreviewArea, SWT.NONE); + nameLabel.setText(id); + + Image swtImage = SwtUtils.convertToSwt(display, image, true, -1); + if (swtImage != null) { + @SuppressWarnings("unused") // Has side effect + ImageControl imageControl = new ImageControl(mPreviewArea, SWT.NONE, swtImage); + } + } + + mPreviewArea.layout(true); + } + + Map generatePreviews() { + // Map of ids to images: Preserve insertion order (the densities) + Map imageMap = new LinkedHashMap(); + + // Load the image + // TODO: Only do this when the source image type is image + String path = mImagePathText.getText().trim(); + if (path.length() == 0) { + setErrorMessage("Enter a filename"); + return Collections.emptyMap(); + } + File file = new File(path); + if (!file.exists()) { + setErrorMessage(String.format("%1$s does not exist", file.getPath())); + return Collections.emptyMap(); + } + + setErrorMessage(null); + BufferedImage sourceImage = getImage(path, false); + + LauncherIconGenerator.Options options = new LauncherIconGenerator.Options(); + options.shape = mCircleButton.getSelection() ? CIRCLE : SQUARE; + options.crop = mCropRadio.getSelection(); + + int color = (mBgColor.red << 16) | (mBgColor.green << 8) | mBgColor.blue; + options.backgroundColor = color; + options.sourceImage = sourceImage; + + Density[] densityValues = Density.values(); + // Sort density values into ascending order + Arrays.sort(densityValues, new Comparator() { + public int compare(Density d1, Density d2) { + return d1.getDpiValue() - d2.getDpiValue(); + } + + }); + Style[] styleValues = LauncherIconGenerator.Options.Style.values(); + + for (Density density : densityValues) { + if (!density.isValidValueForDevice()) { + continue; + } + if (density == Density.TV) { + // Not yet supported -- missing stencil image + continue; + } + options.density = density; + for (LauncherIconGenerator.Options.Style style : styleValues) { + options.style = style; + LauncherIconGenerator generator = new LauncherIconGenerator(this, options); + BufferedImage image = generator.generate(); + if (image != null) { + imageMap.put(density.getResourceValue(), image); + } + } + } + + return imageMap; + } + + private void updateColor(Display display, RGB color, boolean isBackground) { + // Button.setBackgroundColor does not work (at least not on OSX) so + // we instead have to use Button.setImage with an image of the given + // color + BufferedImage coloredImage = ImageUtils.createColoredImage(60, 20, color); + Image image = SwtUtils.convertToSwt(display, coloredImage, false, -1); + + if (isBackground) { + mBgColor = color; + mBgButton.setImage(image); + } else { + mFgColor = color; + mFgButton.setImage(image); + } + } + + public BufferedImage loadImageResource(String relativeName) { + return getImage(relativeName, true); + } + + private BufferedImage getImage(String path, boolean isPluginRelative) { + BufferedImage image = mImageCache.get(path); + if (image == null) { + try { + if (isPluginRelative) { + image = GraphicGenerator.getStencilImage(path); + } else { + File file = new File(path); + + // Requires Batik + //if (file.getName().endsWith(DOT_SVG)) { + // image = loadSvgImage(file); + //} + + if (image == null) { + image = ImageIO.read(file); + } + } + } catch (IOException e) { + setErrorMessage(e.getLocalizedMessage()); + } + + if (image == null) { + image = new BufferedImage(1,1, BufferedImage.TYPE_INT_ARGB); + } + + mImageCache.put(path, image); + } + + return image; + } + + // This requires Batik for SVG rendering + // + //public static BufferedImage loadSvgImage(File file) { + // BufferedImageTranscoder transcoder = new BufferedImageTranscoder(); + // + // String svgURI = file.toURI().toString(); + // TranscoderInput input = new TranscoderInput(svgURI); + // + // try { + // transcoder.transcode(input, null); + // } catch (TranscoderException e) { + // e.printStackTrace(); + // return null; + // } + // + // return transcoder.decodedImage; + //} + // + ///** + // * A dummy implementation of an {@link ImageTranscoder} that simply stores the {@link + // * BufferedImage} generated by the SVG library. + // */ + //private static class BufferedImageTranscoder extends ImageTranscoder { + // public BufferedImage decodedImage; + // + // @Override + // public BufferedImage createImage(int w, int h) { + // return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + // } + // + // @Override + // public void writeImage(BufferedImage image, TranscoderOutput output) + // throws TranscoderException { + // this.decodedImage = image; + // } + //} +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureLauncherAssetsPanel.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureLauncherAssetsPanel.java new file mode 100644 index 0000000..930e93c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureLauncherAssetsPanel.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 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.assetstudio; + +import org.eclipse.swt.widgets.Composite; + +public class ConfigureLauncherAssetsPanel extends Composite { + + /** + * Create the composite. + * @param parent + * @param style + */ + public ConfigureLauncherAssetsPanel(Composite parent, int style) { + super(parent, style); + + } + + @Override + protected void checkSubclass() { + // Disable the check that prevents subclassing of SWT components + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizard.java new file mode 100644 index 0000000..4aa67fa --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizard.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011 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.assetstudio; + +import static com.android.ide.eclipse.adt.AdtConstants.DOT_PNG; +import static com.android.ide.eclipse.adt.AdtConstants.WS_RESOURCES; +import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP; + +import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper.IProjectFilter; +import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileWizard; +import com.android.util.Pair; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.FileEditorInput; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; + +public class CreateAssetSetWizard extends Wizard implements INewWizard { + private ChooseAssetTypePage chooseAssetPage; + private ConfigureAssetSetPage configureAssetPage; + private IProject mInitialProject; + + public CreateAssetSetWizard() { + setWindowTitle("Create Asset Set"); + } + + @Override + public void addPages() { + chooseAssetPage = new ChooseAssetTypePage(); + chooseAssetPage.setProject(mInitialProject); + configureAssetPage = new ConfigureAssetSetPage(); + + addPage(chooseAssetPage); + addPage(configureAssetPage); + } + + @Override + public boolean performFinish() { + String name = chooseAssetPage.getOutputName(); + Map previews = configureAssetPage.generatePreviews(); + IProject project = getProject(); + + // Write out the images into the project + List createdFiles = new ArrayList(); + for (Map.Entry entry : previews.entrySet()) { + String id = entry.getKey(); + + IPath dest = new Path(WS_RESOURCES + WS_SEP + "drawable-" //$NON-NLS-1$ + + id + WS_SEP + name + DOT_PNG); + IFile file = project.getFile(dest); + if (file.exists()) { + // TODO: Warn that the file already exists and ask the user what to do? + try { + file.delete(true, new NullProgressMonitor()); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + } + + NewXmlFileWizard.createWsParentDirectory(file.getParent()); + BufferedImage image = entry.getValue(); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + ImageIO.write(image, "PNG", stream); //$NON-NLS-1$ + byte[] bytes = stream.toByteArray(); + InputStream is = new ByteArrayInputStream(bytes); + file.create(is, true /*force*/, null /*progress*/); + createdFiles.add(file); + } catch (IOException e) { + AdtPlugin.log(e, null); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + + try { + file.getParent().refreshLocal(1, new NullProgressMonitor()); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + } + + // Attempt to select the newly created files in the Package Explorer + IWorkbench workbench = AdtPlugin.getDefault().getWorkbench(); + IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage(); + IViewPart viewPart = page.findView(JavaUI.ID_PACKAGES); + if (viewPart != null) { + IWorkbenchPartSite site = viewPart.getSite(); + IJavaProject javaProject = null; + try { + javaProject = BaseProjectHelper.getJavaProject(project); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + ISelectionProvider provider = site.getSelectionProvider(); + if (provider != null) { + List pathList = new ArrayList(); + for (IFile file : createdFiles) { + // Create a TreePath for the given file, + // which should be the JavaProject, followed by the folders down to + // the final file. + List segments = new ArrayList(); + segments.add(file); + IContainer folder = file.getParent(); + segments.add(folder); + // res folder + folder = folder.getParent(); + segments.add(folder); + // project + segments.add(javaProject); + + Collections.reverse(segments); + TreePath path = new TreePath(segments.toArray()); + pathList.add(path); + } + + TreePath[] paths = pathList.toArray(new TreePath[pathList.size()]); + provider.setSelection(new TreeSelection(paths)); + } + } + + return true; + } + + IProject getProject() { + if (chooseAssetPage != null) { + return chooseAssetPage.getProject(); + } else { + return mInitialProject; + } + } + + public void init(IWorkbench workbench, IStructuredSelection selection) { + setHelpAvailable(false); + + mInitialProject = guessProject(selection); + if (chooseAssetPage != null) { + chooseAssetPage.setProject(mInitialProject); + } + } + + private IProject guessProject(IStructuredSelection selection) { + if (selection == null) { + return null; + } + + for (Object element : selection.toList()) { + if (element instanceof IAdaptable) { + IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class); + IProject project = res != null ? res.getProject() : null; + + // Is this an Android project? + try { + if (project == null || !project.hasNature(AdtConstants.NATURE_DEFAULT)) { + continue; + } + } catch (CoreException e) { + // checking the nature failed, ignore this resource + continue; + } + + return project; + } else if (element instanceof Pair) { + // Pair of Project/String + @SuppressWarnings("unchecked") + Pair pair = (Pair) element; + return pair.getFirst(); + } + } + + // Try to figure out the project from the active editor + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window != null) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorPart activeEditor = page.getActiveEditor(); + if (activeEditor instanceof AndroidXmlEditor) { + Object input = ((AndroidXmlEditor) activeEditor).getEditorInput(); + if (input instanceof FileEditorInput) { + FileEditorInput fileInput = (FileEditorInput) input; + return fileInput.getFile().getProject(); + } + } + } + } + + IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(new IProjectFilter() { + public boolean accept(IProject project) { + return project.isAccessible(); + } + }); + + if (projects != null && projects.length == 1) { + return projects[0].getProject(); + } + + return null; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java index 4c1127a..1838d14 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java @@ -19,8 +19,8 @@ package com.android.ide.eclipse.adt.internal.resources; import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML; import com.android.ide.common.resources.ResourceItem; -import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; import com.android.resources.ResourceFolderType; @@ -49,14 +49,20 @@ public class ResourceNameValidator implements IInputValidator { */ private boolean mIsFileType; + /** + * True if the resource type can point to image resources + */ + private boolean mIsImageType; + /** If true, allow .xml as a name suffix */ private boolean mAllowXmlExtension; private ResourceNameValidator(boolean allowXmlExtension, Set existing, - boolean isFileType) { + boolean isFileType, boolean isImageType) { mAllowXmlExtension = allowXmlExtension; mExisting = existing; mIsFileType = isFileType; + mIsImageType = isImageType; } public String isValid(String newText) { @@ -70,8 +76,17 @@ public class ResourceNameValidator implements IInputValidator { newText = newText.substring(0, newText.length() - DOT_XML.length()); } - if (newText.indexOf('.') != -1 && !newText.endsWith(AdtConstants.DOT_XML)) { - return String.format("The filename must end with %1$s.", DOT_XML); + if (mAllowXmlExtension && mIsImageType + && ImageUtils.hasImageExtension(newText)) { + newText = newText.substring(0, newText.lastIndexOf('.')); + } + + if (newText.indexOf('.') != -1 && !newText.endsWith(DOT_XML)) { + if (mIsImageType) { + return "The filename must end with .xml or .png"; + } else { + return "The filename must end with .xml"; + } } // Resource names must be valid Java identifiers, since they will @@ -126,7 +141,8 @@ public class ResourceNameValidator implements IInputValidator { public static ResourceNameValidator create(boolean allowXmlExtension, ResourceFolderType type) { boolean isFileType = type != ResourceFolderType.VALUES; - return new ResourceNameValidator(allowXmlExtension, null, isFileType); + return new ResourceNameValidator(allowXmlExtension, null, isFileType, + type == ResourceFolderType.DRAWABLE); } /** @@ -142,7 +158,8 @@ public class ResourceNameValidator implements IInputValidator { public static ResourceNameValidator create(boolean allowXmlExtension, Set existing, ResourceType type) { boolean isFileType = ResourceHelper.isFileBasedResourceType(type); - return new ResourceNameValidator(allowXmlExtension, existing, isFileType); + return new ResourceNameValidator(allowXmlExtension, existing, isFileType, + type == ResourceType.DRAWABLE); } /** @@ -165,6 +182,7 @@ public class ResourceNameValidator implements IInputValidator { } boolean isFileType = ResourceHelper.isFileBasedResourceType(type); - return new ResourceNameValidator(allowXmlExtension, existing, isFileType); + return new ResourceNameValidator(allowXmlExtension, existing, isFileType, + type == ResourceType.DRAWABLE); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java index 87afa11..a375987 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java @@ -247,7 +247,7 @@ public class NewXmlFileWizard extends Wizard implements INewWizard { return createXmlFile(file, xmlns, root, attrs, null); } - private static boolean createWsParentDirectory(IContainer wsPath) { + public static boolean createWsParentDirectory(IContainer wsPath) { if (wsPath.getType() == IResource.FOLDER) { if (wsPath.exists()) { return true; diff --git a/eclipse/scripts/create_adt_symlinks.sh b/eclipse/scripts/create_adt_symlinks.sh index 949362e..5966454 100755 --- a/eclipse/scripts/create_adt_symlinks.sh +++ b/eclipse/scripts/create_adt_symlinks.sh @@ -16,7 +16,7 @@ BACK=`echo $DEST | sed 's@[^/]*@..@g'` mkdir -p $DEST -LIBS="sdkstats androidprefs common layoutlib_api ide_common ninepatch sdklib sdkuilib" +LIBS="sdkstats androidprefs common layoutlib_api ide_common ninepatch sdklib sdkuilib assetstudio" echo "make java libs ..." make -j3 showcommands $LIBS || die "ADT: Fail to build one of $LIBS." -- cgit v1.1