Showing posts with label app. Show all posts
Showing posts with label app. Show all posts
Saturday, May 6, 2017
Download Real Drum Apk Full Android Latest Version 2014 App Free
You do not need to know drumming, Real Drum comes with 60 lessons rhythms with tutorial for you to learn to play. Also comes with 12 songs to play along, and still allows you to track songs live. For example, you can give the play a music from your library and accompany its on drums.
The application has samples of acoustic percussion. Sounds recorded with studio audio quality. But if you want to change the sound of your battery, you can swap crashes and add percussion instruments. You can also change the arrangement of the pads, adjusting your best way to play.
Features of Real Drum:
* Multitouch
* 13 drum pads
* 19 realistic drum sounds
* Studio audio quality
* Instruments like kick, bass, snare, tom, floor, cymbal, hi-hat, ride, crash, splash, bell, china, stack, block, cowbell and tambourine
* 60 examples of rhythms with tutorial mode
* 12 backing track songs
* Record mode
* Complete acoustic drum kit
* Works with all screen resolutions - Cell Phones and Tablets (HD Images)
* Free
The app is free, but you can remove all advertisements buying a license!
Try the best drums of the Google Play!
Made for drummers, percussionists, professional musicians, amateurs or beginners!
DOWNLAOD APP
Monday, April 10, 2017
Download SHAREit 3 5 0 1144 App PC File Transfer Now

Software Name: SHAREit By Lenovo
Release Date: Jan 2016
Genre: Utility, File Transfer,
Format: setup
Size: 4.95 mb
Language: English
Platform: PC, Android, iOS, Windows Phone
SHAREit is an amazing software from Lenovo, yes the laptop guys you know. But they have really put their efforts in making this one of a kind, high-speed file transfer even for iOS. Like no one has done it even Xender was dodged by iOSs strict rules and tracks. But, SHAREit just works fine on iPhone 6s and other iOS devices. SHAREit uses a great way to transfer gigs of bytes from your PC to another PC or to your Phone or vice versa and amazingly fast way by using the Wifi option of your phone and laptop and it does not need any internet access to do so. Thats one of the great features of the software. SHAREit App download is super easy and you can download it from your Apple store or Google play store on Android and iOS devices respectively. Actually, SHAREit for android was released a bit latter than the other platforms because Lenovo really wanted to make sure that it covers the android portion of users too, and facilitate them in the best way possible. Will this be on future Lenovo laptops and devices pre-installed? maybe! SHAREit app can also be downloaded.
Download Software
Sunday, February 15, 2015
27 Free Perspective App Screen PSD Mockups

If you’re designing an app, you’ll need some screen mock-up templates, to showcase your design. if youre ui designer and develop an mobile app, you should design something app screen showcase and shown to the client included angle perspectives.
So, in this post, Collection of 27 Free PSD Perspective App Screen Mockups. use the smart objects to place your design, you can easily change the background color and the depth size of the screens.
1- App Screen Mock-Up Perspective PSD

2- Perspective App Screen Mock-Up PSD

3- Isometric Perspective MockUp PSD

4- Perspective App Screens Mock-Up PSD

5- Iphone 6 Wrap Around Screen Mockup PSD

6- Free PSD App Screen iOS 7

7- iOS 7 Weather App Design PSD

8- Free 3D Perspective Mockup PSD

9- Perspective App Screen PSD Mock-Up

10- Perspective Tablet Mock-Up PSD

11- Perspective App Screens Mock-Up PSD

12- 3D Mobile App Screens Mock-Up PSD

13- Free PSD Mockup Isometric Mobile App Screen

14- Free PSD Perspective App Screens Mock-Up

15- App Screen Showcase Mockup PSD

16- App Screen Presentation Mock-ups PSD

17- App Screens Perspective MockUp PSD

18- Free PSD Perspective Mockup Template

19- Perspective Mobile Screen Mock-up PSD

20- Android / iPhone Perspective App Mockup PSD

21- iPhone App Front Screen MockUp PSD

22- PSD Perspective Mobile Mock-up Screen

23- Perspective Screen MockUp PSD

24- Free PSD Perspective Screen MockUp

25- Free PSD Mobile Screen MockUp

26- Perspective App Screens PSD Mockup

27- App Screen MockUp PSD

Tuesday, February 10, 2015
Perspective App Screens Mock Up PSD

Type : PSD
Category : Mockups
License : Free
Author : Graphberry
Download
Wednesday, February 4, 2015
KirSizer Flex AIR Image Sizer app Part 6
The "Please wait" indicators are important to show the user that the program has not stopped working, but actually is working.
First lets create this message. Go to declarations tags and add a new TitleWindow object with an id waitWindow and a Label inside of it called waitLabel.
<mx:TitleWindow id="waitWindow" title="Please wait" width="240" height="70" showCloseButton="false">
<s:Group width="100%" height="100%">
<s:Label top="10" left="10" id="waitLabel" width="220" color="0x000000" />
</s:Group>
</mx:TitleWindow>
Now go to the existing folderSelected() function and change the doFolder() function calls to startFolder() function calls, keep all the parameters the same:
private function folderSelected(evt:Event):void {
var file:File = evt.currentTarget as File;
Alert.show("Do you want to select subfolders too?", "Recursive selection?", Alert.YES | Alert.NO, null, warningClose);
function warningClose(ev:CloseEvent):void {
if (ev.detail == Alert.YES) {
startFolder(file, true);
}
if (ev.detail == Alert.NO) {
startFolder(file, false);
}
}
}
The startFolder() function adds and centers the waitWindow window, sets its waitLabels text to "Selecting folders..." and adds a timer for 100 milliseconds (enough time for the message to display). When the timer is complete, a function called onWait is called, which calls doFolder() and removes the pop up window:
private function startFolder(file:File, recurs:Boolean):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting folders...";
var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFolder(file, recurs);
PopUpManager.removePopUp(waitWindow);
}
}
Now lets do the same with files. Go to filesSelected() function and add similar to startFolder() code:
private function filesSelected(evt:FileListEvent):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting files...";
var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFiles(evt.files);
PopUpManager.removePopUp(waitWindow);
}
}
The doFiles() function that is called contains the previous code of filesSelected():
private function doFiles(files:Array):void {
for (var i:int = 0; i < files.length; i++) {
var alreadySelected:Boolean = false;
for (var u:int = 0; u < selectedFiles.length; u++) {
if (selectedFiles[u].type == 0 && selectedFiles[u].path == files[i].nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem({type:0, path:files[i].nativePath});
}
updateTotalFiles();
}
Now, lets implement Ctrl+A selection. Firstly we need to add a keyboard event listener. To do that, we first need to listen to creationComplete event of the root tags:
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="300" height="460"
showStatusBar="false" title="KirSizer" creationComplete="init();">
And the init() function adds the listener:
private function init():void {
addEventListener(KeyboardEvent.KEY_DOWN, keybDown);
}
In keybDown() function we check if the combination is Ctrl+A and create an array of all the indices, then we set this array as the value for tileList.selectedIndices:
private function keybDown(evt:KeyboardEvent):void {
if (evt.ctrlKey && evt.keyCode == 65) {
var arr:Array = [];
for (var i:int = 0; i < selectedFiles.length; i++) {
arr.push(i);
}
tileList.selectedIndices = arr;
}
}
Full code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="300" height="460"
showStatusBar="false" title="KirSizer" creationComplete="init();">
<fx:Declarations>
<mx:ArrayCollection id="measures">
<fx:String>%</fx:String>
<fx:String>px</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="actions">
<fx:String>Fixed width, fixed height</fx:String>
<fx:String>Fixed width, proportional height</fx:String>
<fx:String>Proportional width, fixed height</fx:String>
<fx:String>Proportional sizes to fit specified sizes</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="formats">
<fx:String>Same format as initial file</fx:String>
<fx:String>Convert all to JPG</fx:String>
<fx:String>Convert all to PNG</fx:String>
</mx:ArrayCollection>
<mx:Fade id="fadeIn" alphaFrom="0" alphaTo="1" duration="300"/>
<mx:Fade id="fadeOut" alphaFrom="1" alphaTo="0" duration="300"/>
<mx:TitleWindow id="waitWindow" title="Please wait" width="240" height="70" showCloseButton="false">
<s:Group width="100%" height="100%">
<s:Label top="10" left="10" id="waitLabel" width="220" color="0x000000" />
</s:Group>
</mx:TitleWindow>
</fx:Declarations>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
#contentStack{
backgroundColor: #313131;
}
s|Label{
color: #fcfcfc;
}
s|Button{
chromeColor: #636363;
}
mx|ComboBox{
chromeColor: #636363;
color: #fcfcfc;
contentBackgroundColor: #000000;
rollOverColor: #aaaaaa;
selectionColor: #ffffff;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.events.Event;
import flash.events.FileListEvent;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.net.FileFilter;
import flash.utils.Timer;
import mx.collections.ArrayCollection;
import mx.effects.easing.Linear;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.events.StateChangeEvent;
import mx.managers.PopUpManager;
[Bindable]
private var selectedFiles:ArrayCollection = new ArrayCollection([]);
private function init():void {
addEventListener(KeyboardEvent.KEY_DOWN, keybDown);
}
private function keybDown(evt:KeyboardEvent):void {
if (evt.ctrlKey && evt.keyCode == 65) {
var arr:Array = [];
for (var i:int = 0; i < selectedFiles.length; i++) {
arr.push(i);
}
tileList.selectedIndices = arr;
}
}
private function actionChange():void{
switch (actionCombo.selectedIndex) {
case 0: case 3:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
case 1:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = false;
heightMeasure.enabled = false;
break;
case 2:
newWidth.enabled = false;
widthMeasure.enabled = false;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
}
}
private function addFiles():void {
var file:File = new File();
file.browseForOpenMultiple("Select JPG or PNG files", [new FileFilter("Pictures", "*.jpg;*.jpeg;*.png")]);
file.addEventListener(FileListEvent.SELECT_MULTIPLE, filesSelected);
}
private function filesSelected(evt:FileListEvent):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting files...";
var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFiles(evt.files);
PopUpManager.removePopUp(waitWindow);
}
}
private function addFolder():void {
var file:File = new File();
file.browseForDirectory("Select a directory");
file.addEventListener(Event.SELECT, folderSelected);
}
private function folderSelected(evt:Event):void {
var file:File = evt.currentTarget as File;
Alert.show("Do you want to select subfolders too?", "Recursive selection?", Alert.YES | Alert.NO, null, warningClose);
function warningClose(ev:CloseEvent):void {
if (ev.detail == Alert.YES) {
startFolder(file, true);
}
if (ev.detail == Alert.NO) {
startFolder(file, false);
}
}
}
private function startFolder(file:File, recurs:Boolean):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting folders...";
var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFolder(file, recurs);
PopUpManager.removePopUp(waitWindow);
}
}
private function doFiles(files:Array):void {
for (var i:int = 0; i < files.length; i++) {
var alreadySelected:Boolean = false;
for (var u:int = 0; u < selectedFiles.length; u++) {
if (selectedFiles[u].type == 0 && selectedFiles[u].path == files[i].nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem({type:0, path:files[i].nativePath});
}
updateTotalFiles();
}
private function doFolder(file:File, isRecursive:Boolean):void {
var picturesInFolder:int = 0;
var childFiles:Array = file.getDirectoryListing();
for (var i:int = 0; i < childFiles.length; i++) {
if (childFiles[i].extension == "png" || childFiles[i].extension == "jpg" || childFiles[i].extension == "jpeg") {
picturesInFolder++;
}
if (childFiles[i].isDirectory && isRecursive) {
doFolder(childFiles[i], true);
}
}
if (picturesInFolder > 0) {
var alreadySelected:Boolean = false;
for (var a:int = 0; a < selectedFiles.length; a++) {
if (selectedFiles[a].type == 1 && selectedFiles[a].path == file.nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem( { type:1, path:file.nativePath, name:file.name, num:picturesInFolder } );
updateTotalFiles();
}
}
private function updateTotalFiles():void {
var totalFiles:int = 0;
for (var i:int = 0; i < selectedFiles.length; i++) {
if (selectedFiles[i].type==1) {
totalFiles += selectedFiles[i].num;
}else {
totalFiles++;
}
}
labelSelected.text = totalFiles + " files selected";
}
private function removeSelected():void {
while (tileList.selectedItems.length > 0) {
selectedFiles.removeItemAt(tileList.selectedIndices[0]);
}
updateTotalFiles();
}
]]>
</fx:Script>
<mx:ViewStack id="contentStack" width="100%" height="100%">
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Label id="labelSelected">0 files selected</s:Label>
<mx:TileList id="tileList" width="282" height="100%" dataProvider="{selectedFiles}" itemRenderer="TileRenderer" columnWidth="60" rowHeight="60" columnCount="4" allowMultipleSelection="true" selectionColor="0xff0000" rollOverColor="0xff8888" />
<s:Button label="Add folder" width="100%" click="addFolder();" />
<s:Button label="Add files" width="100%" click="addFiles();" />
<s:Button label="{Remove + tileList.selectedItems.length + items}" width="100%" enabled="{tileList.selectedItems.length>0}" click="removeSelected();" />
<s:Button label="Continue" width="100%" click="contentStack.selectedIndex = 1;" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Button label="Return to file selection" width="100%" click="contentStack.selectedIndex = 0;" />
<s:Label>Resize options:</s:Label>
<mx:ComboBox width="100%" id="actionCombo" height="22" dataProvider="{actions}" selectedIndex="0" editable="false" change="actionChange();"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Width:</s:Label>
<s:NumericStepper id="newWidth" height="22" width="150" minimum="1" value="100" maximum="{(widthMeasure.selectedIndex==0)?(100):(4000)}" />
<mx:ComboBox id="widthMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="0" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Height:</s:Label>
<s:NumericStepper id="newHeight" height="22" width="150" minimum="1" value="100" maximum="{(heightMeasure.selectedIndex==0)?(100):(4000)}"/>
<mx:ComboBox id="heightMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="0" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:Label/>
<s:Label>Output file names:</s:Label>
<s:HGroup verticalAlign="middle">
<s:TextInput width="240" text="%initialName%" />
<s:Button width="35" label="?"/>
</s:HGroup>
<s:Label/>
<s:Label>Output destination:</s:Label>
<s:HGroup verticalAlign="middle">
<s:RadioButton id="oldDestination" label="Same directory" groupName="destinationGroup" selected="true" />
<s:RadioButton id="newDestination" label="Specified directory" groupName="destinationGroup" />
</s:HGroup>
<s:HGroup verticalAlign="middle" width="100%">
<s:TextInput width="100%" enabled="{newDestination.selected}" text="Select destination..." editable="false" />
<s:Button width="80" label="Browse" enabled="{newDestination.selected}"/>
</s:HGroup>
<s:Label/>
<s:Label>Output format:</s:Label>
<mx:ComboBox width="100%" height="22" id="formatCombo" dataProvider="{formats}" selectedIndex="0" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:Label/>
<s:Label>Output JPG quality:</s:Label>
<s:HSlider width="100%" minimum="1" maximum="100" value="100" />
<s:Label/>
<s:Button label="Resize" width="100%" />
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</s:WindowedApplication>
Thanks for reading!
Tuesday, February 3, 2015
Xmas Organizer Download Christmas android app
Christmas Android App
Xmas Organizer
Download Christmas android app
For Smartphones and Tablets.
Xmas Organizer is android app available on Google play store to organize your Christmas . Christmas Android app work like diary. When you see something touchy , beautiful for your loved ones note down it on list. you can make shopping and Xmas gift list which will be easy to manage and buy. Automatic days count to Xmas.

with Xmas Organizer you have many options.

you can add person and the budget .

Create new gift list . you can record your Christmas gift idea , ordered gift , bought Xmas gifts or wrapped record for your gifts .


Xmas Organizer give you complete information about budget and statistics . You will take care of your pocket as well.

You can select theme for apk background. You can set password for this android app. Xmas Organizer allow you to backup and restore your data on memory card.
Download Xmas Organizer
Size : 1.9M
Playstore Rating : 4.4
Require OS : 2.2 and above
Develop by : Simon Meurer
Saturday, January 31, 2015
Creating a Flex AIR Screenshot app Part 6
The path the user can enter can be either an internet URL, or a local path. It is important to know that www.google.com or google.com alone wont work, http:// is required in front of the link. However, we dont know whether the path that the user entered is a local path or path to a file on the internet, and we dont know if http:// or something else is required, so we can just put "http://" by default into the text field, so that the user will just add his link to it (or replace the content completely with the link that he had copied, which is more likely).
So, find urlInput text field and put "http://" as its text value by default:
<s:TextInput width="250" id="urlInput" text="http://" />
The user should be able to enter anything in the address bar, a long as it is not blank, so lets add a check, which disables the two image buttons if the url is blank.
<custom:ImageButton img="@Embed(../lib/b_cut.png)" over="@Embed(../lib/b_cut_over.png)" toolTip="Crop area" click="goCrop();" buttonMode="true" enabled="{urlInput.text!=}" />
<custom:ImageButton img="@Embed(../lib/b_screenshot.png)" over="@Embed(../lib/b_screenshot_over.png)" toolTip="Take screenshot" buttonMode="true" enabled="{urlInput.text!=}" />
Now lets add some loading information to the crop stage window. Well add 2 label objects, one of them will contain the url, and the second one will display "Loading" or "Loaded".
Add these 2 labels, set the first ones id to cropStatus and the second ones text bound to urlString,
<s:NavigatorContent id="crop">
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage}" />
<s:Button label="Continue" enabled="false" />
<s:Label id="cropStatus" />
<s:Label text="{urlString}" />
</mx:HBox>
<mx:HTML width="100%" height="100%" id="cropHTML" />
</s:VGroup>
</s:NavigatorContent>
Now we have to make urlString bindable:
[Bindable]
private var urlString:String;
Go to changeState(). In the second conditional, add lines that set cropStatus text value to Loading, as well as its color to yellow. Add a listener for its COMPLETE event and set onCropLoad function as its handler.
private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
cropHTML.htmlLoader.loadString("");
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
cropStatus.text = "Loading";
cropStatus.setStyle("color", "#ffff00");
cropHTML.addEventListener(Event.COMPLETE, onCropLoad);
}
}
The onCropLoad function sets the text to Loaded and color to white:
private function onCropLoad(evt:Event):void {
cropStatus.text = "Loaded";
cropStatus.setStyle("color", "#ffffff");
}
And thats all for today.
Full code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:custom="*"
xmlns:mx="library://ns.adobe.com/flex/mx" showStatusBar="false"
width="450" height="300" creationComplete="init();">
<fx:Declarations>
<mx:ArrayCollection id="headerTitles">
<fx:Object step="Step one:" description="load a web page." />
<fx:Object step="Step two:" description="set your export preferences." />
<fx:Object step="Step two:" description="select the area you wish to crop." />
<fx:Object step="Step three:" description="set your export preferences for the cropped image." />
<fx:Object step="Final step:" description="please wait while your images are being expored." />
</mx:ArrayCollection>
</fx:Declarations>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
.descriptionText{
fontSize: 24;
color: #fff;
}
#headStep{
fontSize: 30;
fontWeight: bold;
color: #ffffbb;
}
#headDesc{
fontSize: 30;
color: #ffffff;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.events.Event;
import flash.filesystem.File;
import flash.net.URLRequest;
import mx.events.FlexNativeWindowBoundsEvent;
[Bindable]
private var urlString:String;
private function init():void {
addEventListener(FlexNativeWindowBoundsEvent.WINDOW_RESIZE, onResize);
}
private function doBrowse():void{
var file:File = new File();
file.addEventListener(Event.SELECT, browseSelect);
file.browseForOpen("Load a webpage");
function browseSelect(evt:Event):void {
urlInput.text = file.nativePath;
}
}
private function goCrop():void {
stack.selectedChild = crop;
urlString = urlInput.text;
}
private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
cropHTML.htmlLoader.loadString("");
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
cropStatus.text = "Loading";
cropStatus.setStyle("color", "#ffff00");
cropHTML.addEventListener(Event.COMPLETE, onCropLoad);
}
}
private function onCropLoad(evt:Event):void {
cropStatus.text = "Loaded";
cropStatus.setStyle("color", "#ffffff");
}
private function onResize(evt:Event):void {
if (stack.selectedChild == crop) {
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
}
}
]]>
</fx:Script>
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#333333" height="46" width="100%" paddingTop="10" paddingLeft="10">
<s:Label id="headStep" text="{headerTitles.getItemAt(stack.selectedIndex).step}" />
<s:Label id="headDesc" text="{headerTitles.getItemAt(stack.selectedIndex).description}" />
</mx:HBox>
<mx:Box backgroundColor="#666666" width="100%" height="100%" id="contentBox" horizontalAlign="center">
<mx:ViewStack id="stack" change="changeState();">
<s:NavigatorContent id="loadpage">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Enter the link to the page:</s:Label>
<s:HGroup>
<s:TextInput width="250" id="urlInput" text="http://" /><s:Button label="Browse local..." click="doBrowse();" />
</s:HGroup>
<s:HGroup>
<custom:ImageButton img="@Embed(../lib/b_cut.png)" over="@Embed(../lib/b_cut_over.png)" toolTip="Crop area" click="goCrop();" buttonMode="true" enabled="{urlInput.text!=}" />
<custom:ImageButton img="@Embed(../lib/b_screenshot.png)" over="@Embed(../lib/b_screenshot_over.png)" toolTip="Take screenshot" buttonMode="true" enabled="{urlInput.text!=}" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="screenshotsettings">
</s:NavigatorContent>
<s:NavigatorContent id="crop">
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage}" />
<s:Button label="Continue" enabled="false" />
<s:Label id="cropStatus" />
<s:Label text="{urlString}" />
</mx:HBox>
<mx:HTML width="100%" height="100%" id="cropHTML" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="cropsettings">
</s:NavigatorContent>
<s:NavigatorContent id="export">
</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</s:VGroup>
</s:WindowedApplication>
Thanks for reading!
Friday, January 30, 2015
Creating a Flex AIR Screenshot app Part 26
The first thing were going to change is set drawingRect of changeState() in a way so that its coordinates are out of visible area. This will prevent bugs which appear after weve already done a selection once and visit the crop window for a second (or more) time.
Go ot changeState() and add the line to set drawingRect values in the second conditional:
private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
tempHTML.width = 1;
tempHTML.height = 1;
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
tempHTML.htmlLoader.loadString("<html></html>");
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
var bd:BitmapData = new BitmapData(tempHTML.width, tempHTML.height, false);
bd.draw(tempHTML);
var b:Bitmap = new Bitmap(bd, "auto", true);
cropHTML.source = b;
drawArea.addEventListener(MouseEvent.MOUSE_DOWN, drawDown);
addEventListener(MouseEvent.MOUSE_UP, drawUp);
drawArea.addEventListener(MouseEvent.MOUSE_MOVE, drawMove);
displayWidth.filters = [new GlowFilter(0xffffff, 1, 3, 3, 50)];
displayHeight.filters = [new GlowFilter(0xffffff, 1, 3, 3, 50)];
drawArea.addEventListener(MouseEvent.MOUSE_OVER, drawOver);
drawArea.addEventListener(MouseEvent.MOUSE_OUT, drawOut);
drawingRect = [ -50, -50, 0, 0];
drawRectangle();
displayHeight.text = "";
displayWidth.text = "";
cropDraw.graphics.clear();
canExportCrop = false;
}
if (stack.selectedChild == screenshotsettings) {
screenSettings = [set2, set3, set4, set5, set6, set7];
contSize.text = "Full size (" + tempHTML.contentWidth + "x" + tempHTML.contentHeight + ")";
loadScreenshotSettings();
}
if (stack.selectedChild == cropsettings) {
contentBox.setStyle("horizontalAlign", "center");
loadCropSettings();
}
}
Now lets add a Select All button to the crop NavigatorContent object. Set its click event handler to cropSelectAll():
<s:NavigatorContent id="crop">
<s:VGroup width="{contentBox.width}" height="100%" gap="0" horizontalAlign="center">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage;}" />
<s:Button label="Select all" click="cropSelectAll();" />
<s:Button label="Export selection" enabled="{canExportCrop}" click="doExportCrop();" />
</mx:HBox>
<s:Scroller width="{(contentBox.width>cropHTML.width+15)?(cropHTML.width+15):(contentBox.width)}" height="{contentBox.height-24}" id="scrollHTML">
<s:Group>
<mx:Image id="cropHTML" />
<s:SpriteVisualElement id="cropDraw" width="{cropHTML.width}" height="{cropHTML.height}" />
<mx:Box width="{cropHTML.width}" height="{cropHTML.height}" alpha="0" id="drawArea" backgroundColor="#000000" />
<s:Label id="displayWidth" color="#000000" mouseEnabled="false" />
<s:Label id="displayHeight" color="#000000" mouseEnabled="false" />
</s:Group>
</s:Scroller>
</s:VGroup>
</s:NavigatorContent>
The function sets drawingRect values to capture the whole screen, as well as set width of displayHeight and displayWidth text fields:
private function cropSelectAll():void{
drawingRect[0] = 0;
drawingRect[1] = 0;
drawingRect[2] = drawArea.width;
drawingRect[3] = drawArea.height;
displayHeight.width = 40;
displayWidth.width = 40;
drawRectangle();
}
Now, right now the selection is a little bit off (found that during many testing sessions). The cropped window is captured oddly - it is off by 1 pixel. To fix that, go to drawRectangle and in the drawRect() line, substract 1 from the last 2 parameters:
cropDraw.graphics.drawRect(drawingRect[0], drawingRect[1], drawingRect[2]-1, drawingRect[3]-1);
Making the whole function look like this:
private function drawRectangle():void {
displayWidth.x = drawingRect[0];
if (displayWidth.x + displayWidth.width > cropDraw.width) {
displayWidth.x -= displayWidth.width;
}
displayWidth.y = drawingRect[1] - 12;
if (displayWidth.y < 0) {
displayWidth.y += displayWidth.height;
}
displayWidth.text = Math.abs(drawingRect[2]) + "px";
displayHeight.x = drawingRect[0] + drawingRect[2] + 4;
if (displayHeight.x + displayHeight.width > cropDraw.width) {
displayHeight.x -= (displayHeight.width + 4);
}
displayHeight.y = drawingRect[1] + drawingRect[3] - 12;
if (displayHeight.y < 0) {
displayHeight.y += displayHeight.height;
}
displayHeight.text = Math.abs(drawingRect[3]) + "px";
cropDraw.graphics.clear();
cropDraw.graphics.lineStyle(1, 0xff0000);
cropDraw.graphics.beginFill(0x00ff00, 0.15);
cropDraw.graphics.drawRect(drawingRect[0], drawingRect[1], drawingRect[2]-1, drawingRect[3]-1);
cropDraw.graphics.endFill();
if (drawingRect[2] > 0 && drawingRect[3] > 0) {
canExportCrop = true;
}else {
canExportCrop = false;
}
}
Now the selection captures everything that is directly under the selection area, flawlessly.
Thats all for today.
Full code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:custom="*"
xmlns:mx="library://ns.adobe.com/flex/mx" showStatusBar="false"
width="550" height="600" creationComplete="init();">
<fx:Declarations>
<mx:ArrayCollection id="headerTitles">
<fx:Object step="Step one:" description="load a web page." />
<fx:Object step="Loading..." description="please wait." />
<fx:Object step="Step two:" description="set your export preferences." />
<fx:Object step="Step two:" description="select the area you wish to crop." />
<fx:Object step="Step three:" description="set your export preferences for the cropped image." />
<fx:Object step="Exporting:" description="please wait." />
</mx:ArrayCollection>
<s:TitleWindow id="aboutWindow" width="500" height="160" close="closeAbout();" title="About Kirshot">
<s:HGroup>
<mx:Image source="@Embed(../bin/icons/Kirshot128.png)"/>
<s:Group width="372">
<s:VGroup top="10" left="10" right="10" bottom="10" width="100%">
<s:Label width="100%">Kirshot is a free open-source AIR application developed by Kirill Poletaev.</s:Label>
<s:Label width="100%">You can find a step-by-step tutorial series of making this program at kirill-poletaev.blogspot.com.</s:Label>
<s:Label width="100%">Contact me at lirx3m@hotmail.com.</s:Label>
<s:Label width="100%">I hope you enjoy this app and find it useful!</s:Label>
</s:VGroup>
</s:Group>
</s:HGroup>
</s:TitleWindow>
</fx:Declarations>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
.descriptionText{
fontSize: 24;
color: #fff;
}
.descriptionText2{
fontSize: 16;
color: #fff;
}
.settingText{
fontSize: 16;
color: #fff;
}
#headStep{
fontSize: 30;
fontWeight: bold;
color: #ffffbb;
}
#headDesc{
fontSize: 30;
color: #ffffff;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filters.GlowFilter;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Timer;
import mx.controls.HTML;
import mx.core.FlexHTMLLoader;
import mx.events.FlexNativeWindowBoundsEvent;
import mx.controls.Alert;
import mx.events.ResizeEvent;
import mx.graphics.codec.IImageEncoder;
import mx.graphics.codec.JPEGEncoder;
import mx.graphics.codec.PNGEncoder;
import mx.graphics.ImageSnapshot;
import spark.components.Scroller;
import spark.primitives.BitmapImage;
import flash.filesystem.FileMode;
import mx.managers.PopUpManager;
[Bindable]
private var urlString:String;
private var tempHTML:HTML = new HTML();
private var preferences:SharedObject = SharedObject.getLocal("kirshotPreferences");
[Bindable]
private var pref_screensizes:Array;
[Bindable]
private var pref_format:String;
[Bindable]
private var pref_quality:int;
[Bindable]
private var pref_folder:Boolean;
[Bindable]
private var pref_destination:String;
[Bindable]
private var exportText:String;
private var screenGo:String;
private var drawing:Boolean = false;
private var dragging:Boolean = false;
private var resizing:Boolean = false;
private var inDragArea:Boolean = false;
private var inResizeArea:Boolean = false;
private var drawingRect:Array = [];
private var dragOffsetX:int = 0;
private var dragOffsetY:int = 0;
[Bindable]
private var drawPreviousX:int = 0;
[Bindable]
private var drawPreviousY:int = 0;
private var resizeDirection:String;
[Bindable]
private var canExportCrop:Boolean = false;
[Embed(source="../lib/cursor_crop.png")]
private var cropCursor:Class;
[Embed(source="../lib/cursor_move.png")]
private var dragCursor:Class;
[Embed(source="../lib/cursor_resize_vertical.png")]
private var resizeVerticalCursor:Class;
[Embed(source="../lib/cursor_resize_horizontal.png")]
private var resizeHorizontalCursor:Class;
[Embed(source="../lib/cursor_resize_diag1.png")]
private var resizeDiag1Cursor:Class;
[Embed(source="../lib/cursor_resize_diag2.png")]
private var resizeDiag2Cursor:Class;
private var screenSettings:Array;
private var cropBD:BitmapData;
private function init():void {
//preferences.data.firsttime = null;
// Set preferences if loaded for the first time
if (preferences.data.firsttime == null) {
preferences.data.firsttime = true;
preferences.data.screensizes = [
{ checked:true },
{ checked:true, w:1280, h:1024 },
{ checked:true, w:1280, h:800 },
{ checked:true, w:1024, h:768 },
{ checked:false, w:"", h:"" },
{ checked:false, w:"", h:"" },
{ checked:false, w:"", h:"" } ];
preferences.data.format = "JPG";
preferences.data.quality = 100;
preferences.data.folder = true;
preferences.data.destination = File.documentsDirectory.nativePath;
preferences.flush();
}
// Set preferences loaded from local storage
pref_screensizes = preferences.data.screensizes;
pref_format = preferences.data.format;
pref_quality = preferences.data.quality;
pref_folder = preferences.data.folder;
pref_destination = preferences.data.destination;
addElement(tempHTML);
removeElement(tempHTML);
}
private function doBrowse():void{
var file:File = new File();
file.addEventListener(Event.SELECT, browseSelect);
file.browseForOpen("Load a webpage");
function browseSelect(evt:Event):void {
urlInput.text = file.nativePath;
}
}
private function goScreenshot(screen:String):void {
screenGo = screen;
stack.selectedChild = screenshotloading;
urlString = urlInput.text;
addElement(tempHTML);
tempHTML.htmlLoader.useCache = false;
tempHTML.horizontalScrollPolicy = "off";
tempHTML.verticalScrollPolicy = "off";
tempHTML.visible = false;
tempHTML.addEventListener(Event.COMPLETE, onTempLoad);
tempHTML.htmlLoader.load(new URLRequest(urlString));
}
private function onTempLoad(evt:Event):void {
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
if(screenGo=="screenshot"){
stack.selectedChild = screenshotsettings;
}
if (screenGo == "crop") {
if(tempHTML.contentWidth <= 4096 && tempHTML.contentHeight <= 4096){
var t:Timer = new Timer(1000, 1);
t.addEventListener(TimerEvent.TIMER_COMPLETE, tComplete);
t.start();
tempHTML.width = tempHTML.contentWidth;
tempHTML.height = tempHTML.contentHeight;
function tComplete(evt:TimerEvent):void {
stack.selectedChild = crop;
}
}else {
Alert.show("Dimensions of a screenshot cannot exceed 4096 pixels.", "Sorry...");
stack.selectedChild = loadpage;
}
}
}
private function cancelLoading():void {
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
tempHTML.cancelLoad();
stack.selectedChild = loadpage;
removeElement(tempHTML);
}
private function screenshotBack():void {
saveScreenshotSettings();
stack.selectedChild = loadpage;
removeElement(tempHTML);
}
private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
tempHTML.width = 1;
tempHTML.height = 1;
tempHTML.removeEventListener(Event.COMPLETE, onTempLoad);
tempHTML.htmlLoader.loadString("<html></html>");
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
var bd:BitmapData = new BitmapData(tempHTML.width, tempHTML.height, false);
bd.draw(tempHTML);
var b:Bitmap = new Bitmap(bd, "auto", true);
cropHTML.source = b;
drawArea.addEventListener(MouseEvent.MOUSE_DOWN, drawDown);
addEventListener(MouseEvent.MOUSE_UP, drawUp);
drawArea.addEventListener(MouseEvent.MOUSE_MOVE, drawMove);
displayWidth.filters = [new GlowFilter(0xffffff, 1, 3, 3, 50)];
displayHeight.filters = [new GlowFilter(0xffffff, 1, 3, 3, 50)];
drawArea.addEventListener(MouseEvent.MOUSE_OVER, drawOver);
drawArea.addEventListener(MouseEvent.MOUSE_OUT, drawOut);
drawingRect = [ -50, -50, 0, 0];
drawRectangle();
displayHeight.text = "";
displayWidth.text = "";
cropDraw.graphics.clear();
canExportCrop = false;
}
if (stack.selectedChild == screenshotsettings) {
screenSettings = [set2, set3, set4, set5, set6, set7];
contSize.text = "Full size (" + tempHTML.contentWidth + "x" + tempHTML.contentHeight + ")";
loadScreenshotSettings();
}
if (stack.selectedChild == cropsettings) {
contentBox.setStyle("horizontalAlign", "center");
loadCropSettings();
}
}
private function loadScreenshotSettings():void {
set1checkbox.selected = pref_screensizes[0].checked;
for (var i:int = 0; i < screenSettings.length; i++) {
screenSettings[i].checked = pref_screensizes[i + 1].checked;
screenSettings[i].w = pref_screensizes[i + 1].w;
screenSettings[i].h = pref_screensizes[i + 1].h;
}
if (pref_format == "JPG") {
screenRadioJPEG.selected = true;
} else {
screenRadioPNG.selected = true;
}
}
private function saveScreenshotSettings():void {
pref_screensizes[0].checked = set1checkbox.selected;
for (var i:int = 0; i < screenSettings.length; i++) {
pref_screensizes[i + 1].checked = screenSettings[i].checked;
pref_screensizes[i + 1].w = screenSettings[i].w;
pref_screensizes[i + 1].h = screenSettings[i].h;
}
if (screenRadioJPEG.selected == true) {
pref_format == "JPG";
} else {
pref_format == "PNG";
}
preferences.data.screensizes = pref_screensizes;
preferences.data.format = pref_format;
preferences.data.quality = pref_quality;
preferences.data.folder = pref_folder;
preferences.data.destination = pref_destination;
preferences.flush();
}
private function formatChange(newformat:String):void {
pref_format = newformat;
}
private function startExportScreenshot():void {
var canExport:Boolean = true;
for (var i:int = 0; i < screenSettings.length; i++) {
if (screenSettings[i].checked && ((screenSettings[i].w == "" || screenSettings[i].w == 0) || (screenSettings[i].h == "" || screenSettings[i].h == 0))) {
canExport = false;
}
}
if (canExport) {
if ((pref_folder && folderField.text != "") || !pref_folder) {
saveScreenshotSettings();
exportScreen();
}else {
Alert.show("Folder name should not be blank!", "Oops...");
}
}else {
Alert.show("One or more selected screen sizes are not entered or are invalid!", "Oops...");
}
}
private function screenshotDestination():void {
var newDestination:File = new File(pref_destination);
newDestination.browseForDirectory("Select directory");
newDestination.addEventListener(Event.SELECT, destinationSelect);
function destinationSelect(evt:Event):void {
pref_destination = newDestination.nativePath;
}
}
private function exportScreen():void {
var encoder:IImageEncoder;
var bd:BitmapData;
var byteArray:ByteArray;
var folderName:String = (pref_folder)?(folderField.text):("");
var fileName:String;
var file:File;
var fileStream:FileStream;
var screensToExport:Array = [];
stack.selectedChild = export;
if (pref_format == "JPG") {
encoder = new JPEGEncoder(pref_quality);
}
if (pref_format == "PNG") {
encoder = new PNGEncoder();
}
// add full-size screen to array if checked
if (pref_screensizes[0].checked) {
screensToExport = [ { w:tempHTML.contentWidth, h: tempHTML.contentHeight, full:true} ];
}
// add the rest screens to array if checked
for (var i:int = 0; i < screenSettings.length; i++) {
if (pref_screensizes[i + 1].checked) {
screensToExport.push( { w: pref_screensizes[i + 1].w, h:pref_screensizes[i + 1].h } );
}
}
// if nothing is checked, go to first page and stop code
if (screensToExport.length == 0) {
removeElement(tempHTML);
stack.selectedChild = loadpage;
return;
}
// create a timer that repeats itself as many times as many items there are in the array
var timer:Timer = new Timer(2000, screensToExport.length);
timer.addEventListener(TimerEvent.TIMER, onTimer);
// set sizes to the first size of the array
if (screensToExport[0].full) {
tempHTML.horizontalScrollPolicy = "off";
tempHTML.verticalScrollPolicy = "off";
}else {
tempHTML.horizontalScrollPolicy = "auto";
tempHTML.verticalScrollPolicy = "auto";
}
if(screensToExport[0].h <= 4096 && screensToExport[0].w <= 4096){
tempHTML.height = screensToExport[0].h;
tempHTML.width = screensToExport[0].w;
}
updateExportText(screensToExport[0].w, screensToExport[0].h, 1, screensToExport.length);
timer.start();
function onTimer(evt:TimerEvent):void {
// do export for the current size
if(screensToExport[timer.currentCount-1].h <= 4096 && screensToExport[timer.currentCount-1].w <= 4096){
timer.stop();
doExport();
timer.start();
}else {
Alert.show("Cannot export " + screensToExport[timer.currentCount-1].w + "x" + screensToExport[timer.currentCount-1].h + " - dimensions of a screenshot cannot extend 4096.","Sorry");
}
// change the size if this was not the last size in the array
if (timer.currentCount != screensToExport.length) {
tempHTML.horizontalScrollPolicy = "auto";
tempHTML.verticalScrollPolicy = "auto";
if(screensToExport[timer.currentCount].h <= 4096 && screensToExport[timer.currentCount].w <= 4096){
tempHTML.height = screensToExport[timer.currentCount].h;
tempHTML.width = screensToExport[timer.currentCount].w;
}
updateExportText(screensToExport[timer.currentCount].w, screensToExport[timer.currentCount].h, timer.currentCount+1, screensToExport.length);
}else {
// if it was the last size in the array, return to first page
timer.stop();
removeElement(tempHTML);
stack.selectedChild = loadpage;
}
}
function doExport():void {
bd = new BitmapData(tempHTML.width, tempHTML.height, false);
bd.draw(tempHTML, null, null, null, null, true);
byteArray = encoder.encode(bd);
fileName = pref_destination + File.separator + folderName + File.separator + tempHTML.width + "x" + tempHTML.height + "." + pref_format;
file = new File(fileName);
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(byteArray);
fileStream.close();
}
function updateExportText(w:int, h:int, current:int, total:int):void {
exportText = "Exporting " + w + "x" + h + "." + pref_format + " (" + current + "/" + total + ")";
}
}
private function drawDown(evt:MouseEvent):void {
if(!inDragArea && !inResizeArea){
drawing = true;
drawingRect = [evt.target.mouseX, evt.target.mouseY, 1, 1];
drawPreviousX = evt.target.mouseX;
drawPreviousY = evt.target.mouseY;
drawRectangle();
}
if (inDragArea && !inResizeArea) {
dragging = true;
dragOffsetX = evt.target.mouseX - drawingRect[0];
dragOffsetY = evt.target.mouseY - drawingRect[1];
}
if (inResizeArea) {
resizing = true;
setResizingCoordinates();
}
}
private function drawUp(evt:MouseEvent):void{
drawing = false;
dragging = false;
resizing = false;
}
private function drawMove(evt:MouseEvent):void{
if (drawing) {
// bottom - right
if (evt.target.mouseX > drawPreviousX && evt.target.mouseY > drawPreviousY) {
drawingRect[0] = drawPreviousX;
drawingRect[1] = drawPreviousY;
drawingRect[2] = evt.target.mouseX - drawPreviousX;
drawingRect[3] = evt.target.mouseY - drawPreviousY;
drawRectangle();
}
// bottom - left
if (evt.target.mouseX < drawPreviousX && evt.target.mouseY > drawPreviousY) {
drawingRect[0] = evt.target.mouseX;
drawingRect[1] = drawPreviousY;
drawingRect[2] = drawPreviousX - evt.target.mouseX;
drawingRect[3] = evt.target.mouseY - drawPreviousY;
drawRectangle();
}
// top - right
if (evt.target.mouseX > drawPreviousX && evt.target.mouseY < drawPreviousY) {
drawingRect[0] = drawPreviousX;
drawingRect[1] = evt.target.mouseY;
drawingRect[2] = evt.target.mouseX - drawPreviousX;
drawingRect[3] = drawPreviousY - evt.target.mouseY;
drawRectangle();
}
// top - left
if (evt.target.mouseX < drawPreviousX && evt.target.mouseY < drawPreviousY) {
drawingRect[0] = evt.target.mouseX;
drawingRect[1] = evt.target.mouseY;
drawingRect[2] = drawPreviousX - evt.target.mouseX;
drawingRect[3] = drawPreviousY - evt.target.mouseY;
drawRectangle();
}
}
if (dragging) {
var newX:int = evt.target.mouseX - dragOffsetX;
var newY:int = evt.target.mouseY - dragOffsetY;
drawingRect[0] = newX;
drawingRect[1] = newY;
validSelectionPositionCheck();
drawRectangle();
}
if (resizing) {
if (resizeDirection == "downright" && evt.target.mouseX > drawPreviousX && evt.target.mouseY > drawPreviousY) {
drawingRect[2] = evt.target.mouseX - drawPreviousX;
drawingRect[3] = evt.target.mouseY - drawPreviousY;
}
if (resizeDirection == "upleft" && evt.target.mouseX < drawPreviousX && evt.target.mouseY < drawPreviousY) {
drawingRect[0] = evt.target.mouseX;
drawingRect[1] = evt.target.mouseY;
drawingRect[2] = drawPreviousX - evt.target.mouseX;
drawingRect[3] = drawPreviousY - evt.target.mouseY;
}
if (resizeDirection == "downleft" && evt.target.mouseX < drawPreviousX && evt.target.mouseY > drawPreviousY) {
drawingRect[0] = evt.target.mouseX;
drawingRect[1] = drawPreviousY;
drawingRect[2] = drawPreviousX - evt.target.mouseX;
drawingRect[3] = evt.target.mouseY - drawPreviousY;
}
if (resizeDirection == "upright" && evt.target.mouseX > drawPreviousX && evt.target.mouseY < drawPreviousY) {
drawingRect[0] = drawPreviousX;
drawingRect[1] = evt.target.mouseY;
drawingRect[2] = evt.target.mouseX - drawPreviousX;
drawingRect[3] = drawPreviousY - evt.target.mouseY;
}
if (resizeDirection == "top" && evt.target.mouseY < drawPreviousY) {
drawingRect[1] = evt.target.mouseY;
drawingRect[3] = drawPreviousY - evt.target.mouseY;
}
if (resizeDirection == "bottom" && evt.target.mouseY > drawPreviousY) {
drawingRect[1] = drawPreviousY;
drawingRect[3] = evt.target.mouseY - drawPreviousY;
}
if (resizeDirection == "right" && evt.target.mouseX > drawPreviousX) {
drawingRect[0] = drawPreviousX;
drawingRect[2] = evt.target.mouseX - drawPreviousX;
}
if (resizeDirection == "left" && evt.target.mouseX < drawPreviousX) {
drawingRect[0] = evt.target.mouseX;
drawingRect[2] = drawPreviousX - evt.target.mouseX;
}
drawRectangle();
}
if (!drawing && !dragging && !resizing){
cursorManager.removeAllCursors();
var lineClickArea:int = 8;
if (Math.abs(evt.target.mouseX - drawingRect[0])<lineClickArea && Math.abs(evt.target.mouseY - drawingRect[1])<lineClickArea) {
cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "upleft";
}else
if (Math.abs(evt.target.mouseX - (drawingRect[0]+drawingRect[2]))<lineClickArea && Math.abs(evt.target.mouseY - (drawingRect[1]+drawingRect[3]))<lineClickArea) {
cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "downright";
}else
if (Math.abs(evt.target.mouseX - drawingRect[0])<lineClickArea && Math.abs(evt.target.mouseY - (drawingRect[1]+drawingRect[3]))<lineClickArea) {
cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "downleft";
}else
if (Math.abs(evt.target.mouseX - (drawingRect[0]+drawingRect[2]))<lineClickArea && Math.abs(evt.target.mouseY - drawingRect[1])<lineClickArea) {
cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "upright";
}else
if (evt.target.mouseX > drawingRect[0] && evt.target.mouseX < drawingRect[0] + drawingRect[2] && Math.abs(evt.target.mouseY - drawingRect[1])<lineClickArea) {
cursorManager.setCursor(resizeVerticalCursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "top";
}else
if (evt.target.mouseX > drawingRect[0] && evt.target.mouseX < drawingRect[0] + drawingRect[2] && Math.abs(evt.target.mouseY - (drawingRect[1]+drawingRect[3]))<lineClickArea) {
cursorManager.setCursor(resizeVerticalCursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "bottom";
}else
if (evt.target.mouseY > drawingRect[1] && evt.target.mouseY < drawingRect[1] + drawingRect[3] && Math.abs(evt.target.mouseX - drawingRect[0])<lineClickArea) {
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "left";
}else
if (evt.target.mouseY > drawingRect[1] && evt.target.mouseY < drawingRect[1] + drawingRect[3] && Math.abs(evt.target.mouseX - (drawingRect[0] + drawingRect[2]))<lineClickArea) {
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -9);
inDragArea = false;
inResizeArea = true;
resizeDirection = "right";
}else
if (evt.target.mouseX > drawingRect[0] && evt.target.mouseX < drawingRect[0] + drawingRect[2] && evt.target.mouseY > drawingRect[1] && evt.target.mouseY < drawingRect[1] + drawingRect[3]) {
cursorManager.setCursor(dragCursor, 2, -9, -9);
inDragArea = true;
inResizeArea = false;
}else {
cursorManager.setCursor(cropCursor, 2, -9, -9);
inDragArea = false;
inResizeArea = false;
}
}
}
private function setResizingCoordinates():void {
if (resizeDirection == "downright") {
drawPreviousX = drawingRect[0];
drawPreviousY = drawingRect[1];
}else
if (resizeDirection == "upleft") {
drawPreviousX = drawingRect[0] + drawingRect[2];
drawPreviousY = drawingRect[1] + drawingRect[3];
}else
if (resizeDirection == "downleft") {
drawPreviousX = drawingRect[0] + drawingRect[2];
drawPreviousY = drawingRect[1];
}else
if (resizeDirection == "upright") {
drawPreviousX = drawingRect[0];
drawPreviousY = drawingRect[1] + drawingRect[3];
}else
if (resizeDirection == "top") {
drawPreviousY = drawingRect[1] + drawingRect[3];
}else
if (resizeDirection == "bottom") {
drawPreviousY = drawingRect[1];
}else
if (resizeDirection == "left") {
drawPreviousX = drawingRect[0] + drawingRect[2];
}else
if (resizeDirection == "right") {
drawPreviousX = drawingRect[0];
}
}
private function drawRectangle():void {
displayWidth.x = drawingRect[0];
if (displayWidth.x + displayWidth.width > cropDraw.width) {
displayWidth.x -= displayWidth.width;
}
displayWidth.y = drawingRect[1] - 12;
if (displayWidth.y < 0) {
displayWidth.y += displayWidth.height;
}
displayWidth.text = Math.abs(drawingRect[2]) + "px";
displayHeight.x = drawingRect[0] + drawingRect[2] + 4;
if (displayHeight.x + displayHeight.width > cropDraw.width) {
displayHeight.x -= (displayHeight.width + 4);
}
displayHeight.y = drawingRect[1] + drawingRect[3] - 12;
if (displayHeight.y < 0) {
displayHeight.y += displayHeight.height;
}
displayHeight.text = Math.abs(drawingRect[3]) + "px";
cropDraw.graphics.clear();
cropDraw.graphics.lineStyle(1, 0xff0000);
cropDraw.graphics.beginFill(0x00ff00, 0.15);
cropDraw.graphics.drawRect(drawingRect[0], drawingRect[1], drawingRect[2]-1, drawingRect[3]-1);
cropDraw.graphics.endFill();
if (drawingRect[2] > 0 && drawingRect[3] > 0) {
canExportCrop = true;
}else {
canExportCrop = false;
}
}
private function drawOver(evt:MouseEvent):void {
if (dragging) {
cursorManager.setCursor(dragCursor, 2, -9, -9);
} else
if (resizing) {
switch(resizeDirection) {
case "upleft":
case "downright":
cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -9);
break;
case "upright":
case "downleft":
cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -9);
break;
case "left":
case "right":
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -9);
break;
case "top":
case "bottom":
cursorManager.setCursor(resizeVerticalCursor, 2, -9, -9);
break;
}
} else {
cursorManager.setCursor(cropCursor, 2, -9, -9);
}
}
private function drawOut(evt:MouseEvent):void {
cursorManager.removeAllCursors();
}
private function validSelectionPositionCheck():void {
if (drawingRect[0] < 0) {
drawingRect[0] = 0;
}
if (drawingRect[0] > drawArea.width - drawingRect[2]) {
drawingRect[0] = drawArea.width - drawingRect[2];
}
if (drawingRect[1] < 0) {
drawingRect[1] = 0;
}
if (drawingRect[1] > drawArea.height - drawingRect[3]) {
drawingRect[1] = drawArea.height - drawingRect[3];
}
}
private function doExportCrop():void {
cropBD = new BitmapData(drawingRect[2], drawingRect[3], false);
cropBD.draw(cropHTML, new Matrix(1, 0, 0, 1, -drawingRect[0], -drawingRect[1]));
stack.selectedChild = cropsettings;
}
private function loadCropSettings():void {
if (pref_format == "JPG") {
cropRadioJPEG.selected = true;
} else {
cropRadioPNG.selected = true;
}
}
private function cropBack():void {
saveCropSettings();
stack.selectedChild = loadpage;
removeElement(tempHTML);
}
private function saveCropSettings():void {
preferences.data.format = pref_format;
preferences.data.quality = pref_quality;
preferences.flush();
}
private function startExportCrop():void {
var encoder:IImageEncoder;
var byteArray:ByteArray;
var file:File;
var fileStream:FileStream;
if (pref_format == "JPG") {
encoder = new JPEGEncoder(pref_quality);
}
if (pref_format == "PNG") {
encoder = new PNGEncoder();
}
byteArray = encoder.encode(cropBD);
file = File.documentsDirectory.resolvePath("crop");
file.browseForSave("Save cropped image");
file.addEventListener(Event.SELECT, saveSelect);
function saveSelect():void {
file.nativePath += "." + pref_format;
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(byteArray);
fileStream.close();
cropBack();
}
}
private function openAbout():void{
PopUpManager.addPopUp(aboutWindow, this, true);
PopUpManager.centerPopUp(aboutWindow);
}
private function closeAbout():void{
PopUpManager.removePopUp(aboutWindow);
}
private function cropSelectAll():void{
drawingRect[0] = 0;
drawingRect[1] = 0;
drawingRect[2] = drawArea.width;
drawingRect[3] = drawArea.height;
displayHeight.width = 40;
displayWidth.width = 40;
drawRectangle();
}
]]>
</fx:Script>
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#333333" height="46" width="100%" paddingTop="10" paddingLeft="10">
<s:Label id="headStep" text="{headerTitles.getItemAt(stack.selectedIndex).step}" />
<s:Label id="headDesc" text="{headerTitles.getItemAt(stack.selectedIndex).description}" />
</mx:HBox>
<mx:Box backgroundColor="#666666" width="100%" height="100%" id="contentBox" horizontalAlign="center">
<mx:ViewStack id="stack" change="changeState();">
<s:NavigatorContent id="loadpage">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Enter the link to the page:</s:Label>
<s:HGroup>
<s:TextInput width="250" id="urlInput" text="http://" />
<s:Button label="Browse local..." click="doBrowse();" />
<s:Button label="?" click="openAbout();" width="30" />
</s:HGroup>
<s:HGroup>
<custom:ImageButton img="@Embed(../lib/b_screenshot.png)" over="@Embed(../lib/b_screenshot_over.png)" toolTip="Take screenshots" click="goScreenshot(screenshot);" buttonMode="true" enabled="{urlInput.text!=}" />
<custom:ImageButton img="@Embed(../lib/b_cut.png)" over="@Embed(../lib/b_cut_over.png)" toolTip="Crop area" click="goScreenshot(crop);" buttonMode="true" enabled="{urlInput.text!=}" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="screenshotloading">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">The page is being loaded...</s:Label>
<s:Button label="Cancel" click="cancelLoading();" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="screenshotsettings">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText2">Select screenshot screen sizes:</s:Label>
<s:SkinnableContainer backgroundColor="#999999" width="310" height="18" >
<s:CheckBox toolTip="Use this screen size" x="4" id="set1checkbox" />
<s:Label id="contSize" styleName="settingText" x="22" y="3" />
</s:SkinnableContainer>
<custom:ScreenSetting id="set2" />
<custom:ScreenSetting id="set3" />
<custom:ScreenSetting id="set4" />
<custom:ScreenSetting id="set5" />
<custom:ScreenSetting id="set6" />
<custom:ScreenSetting id="set7" />
<s:Label/>
<s:Label styleName="descriptionText2">Export as:</s:Label>
<s:HGroup>
<s:RadioButton id="screenRadioJPEG" label="JPEG" groupName="screenshotFormat" change="formatChange(JPEG);" styleName="descriptionText2" />
<s:RadioButton id="screenRadioPNG" label="PNG" groupName="screenshotFormat" change="formatChange(PNG);" styleName="descriptionText2" />
</s:HGroup>
<s:Label styleName="descriptionText2">Quality:</s:Label>
<s:HSlider id="screenQualitySlider" width="310" minimum="1" maximum="100" liveDragging="true" enabled="{pref_format==JPEG}" value="@{pref_quality}" />
<s:Label/>
<s:Label styleName="descriptionText2">Export destination:</s:Label>
<s:HGroup width="310">
<s:TextInput editable="false" width="100%" toolTip="Destination" text="{pref_destination}" />
<s:Button label="Browse" click="screenshotDestination();" />
</s:HGroup>
<s:CheckBox id="folderCheckbox" label="Create new folder with exported images" styleName="descriptionText2" selected="@{pref_folder}" />
<s:TextInput id="folderField" width="100%" toolTip="Folder name" maxChars="200" enabled="{folderCheckbox.selected}" restrict="a-zA-Z0-9._-=+" />
<s:HGroup>
<s:Button label="Back" click="screenshotBack();" />
<s:Button label="Export" click="startExportScreenshot();" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="crop">
<s:VGroup width="{contentBox.width}" height="100%" gap="0" horizontalAlign="center">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage;}" />
<s:Button label="Select all" click="cropSelectAll();" />
<s:Button label="Export selection" enabled="{canExportCrop}" click="doExportCrop();" />
</mx:HBox>
<s:Scroller width="{(contentBox.width>cropHTML.width+15)?(cropHTML.width+15):(contentBox.width)}" height="{contentBox.height-24}" id="scrollHTML">
<s:Group>
<mx:Image id="cropHTML" />
<s:SpriteVisualElement id="cropDraw" width="{cropHTML.width}" height="{cropHTML.height}" />
<mx:Box width="{cropHTML.width}" height="{cropHTML.height}" alpha="0" id="drawArea" backgroundColor="#000000" />
<s:Label id="displayWidth" color="#000000" mouseEnabled="false" />
<s:Label id="displayHeight" color="#000000" mouseEnabled="false" />
</s:Group>
</s:Scroller>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="cropsettings">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText2">Export as:</s:Label>
<s:HGroup>
<s:RadioButton id="cropRadioJPEG" label="JPEG" groupName="screenshotFormat" change="formatChange(JPEG);" styleName="descriptionText2" />
<s:RadioButton id="cropRadioPNG" label="PNG" groupName="screenshotFormat" change="formatChange(PNG);" styleName="descriptionText2" />
</s:HGroup>
<s:Label styleName="descriptionText2">Quality:</s:Label>
<s:HSlider id="cropQualitySlider" width="310" minimum="1" maximum="100" liveDragging="true" enabled="{pref_format==JPEG}" value="@{pref_quality}" />
<s:Label/>
<s:HGroup>
<s:Button label="Back" click="cropBack();" />
<s:Button label="Export" click="startExportCrop();" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent id="export">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText" text="{exportText}" />
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</s:VGroup>
</s:WindowedApplication>
Thanks for reading!
Tuesday, January 27, 2015
KirSizer Flex AIR Image Sizer app Part 14
When I was testing KirSizer on a big amount of images, I noticed that quite a lot of images already had the correct size and thought that it would take less time if I just checked if the pictures size are already correct and skip them. However, just skipping all files for just having correct sizes is wrong, since KirSizer is not only capable of resizing images, but also renaming them, changing their format and also compress pictures. That is why I decided to include the "Skip" feature as a toggleable option.
I also noticed that the log text can get quite big. To prevent any problems with too large text, I decided to clear the text area every time it reaches 24 lines. This way it is still informative, but takes much less space and perhaps this way it even is more comprehendable.
First well do the text limitation feature. Create a function called checkLineLimit() which checks if the number of lines exceeds 24 and set logAreas text to blank if so.
private function checkLineLimit():void {
if (countLines(logArea.text) > 24) {
logArea.text = "";
}
}
The countLines() function that I used returns an integer value, which equals to the number of elements of the array thats created by splitting the text areas text by new line characters:
private function countLines(text:String):int {
var splittedText:Array = text.split("
");
var lines:int = splittedText.length;
return lines;
}
We call this function in the beginning of nextAction(), in its first if statement:
private function nextAction():void {
if (currentNum < selectedFiles.length) {
checkLineLimit();
var isFolder:Boolean = false;
var folder:File = new File(selectedFiles[currentNum].path);
// if its a folder, create a global array that stores all image files of the folder
if (folderArray.length > 0) isFolder = true;
if (folder.exists && selectedFiles.length > currentNum && selectedFiles[currentNum].type == 1 && folderArray.length == 0) {
isFolder = true;
folderArray = [];
var allContent:Array = folder.getDirectoryListing();
for (var i:int = 0; i < allContent.length; i++) {
if (allContent[i].isDirectory == false && (allContent[i].extension.toLowerCase() == "png" || allContent[i].extension.toLowerCase() == "jpg" || allContent[i].extension.toLowerCase() == "jpeg")) {
folderArray.push(allContent[i]);
}
}
if (selectedFiles[currentNum].num != folderArray.length) {
appendHighlight("ERROR: incorrect amount of image files found in folder " + folder.name + "
", 0xff2222);
errorText += "Not enough or too many image files found in folder " + folder.nativePath + " (some files were removed/added before it was this folders turn to be resized)" + File.lineEnding;
totalErrors++;
}
}
if (!folder.exists && selectedFiles.length > currentNum && selectedFiles[currentNum].type == 1 && folderArray.length == 0) {
appendHighlight("ERROR: folder not found (" + folder.name + ")
", 0xff2222);
errorText += "Folder was not found at " + folder.nativePath + File.lineEnding;
totalErrors++;
currentNum++;
nextAction();
return;
}
resizeNext(isFolder);
}else {
progressBar.setProgress(totalFiles, totalFiles);
appendHighlight("Operation complete!
Errors: " + totalErrors + "
Files resized: " + successFiles + "/" + totalFiles, 0xffff44);
errorText += "----------------------" + File.lineEnding + "Total errors: " + totalErrors + File.lineEnding + "Files resized: " + successFiles + "/" + totalFiles;
buttonError.enabled = true;
buttonReturn.enabled = true;
statusText.setStyle("color", 0x44ff44);
statusText.text = "COMPLETED";
}
}
Now lets work on the skipping feature. Go to the options screens NavigatorContent object and create a new CheckBox object with an id skipCorrect and selected property set to false:
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Button label="Return to file selection" width="100%" click="contentStack.selectedIndex = 0;" />
<s:Label>Resize options:</s:Label>
<mx:ComboBox width="100%" id="actionCombo" height="22" dataProvider="{actions}" selectedIndex="0" editable="false" change="actionChange();"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Width:</s:Label>
<s:NumericStepper id="newWidth" height="22" width="150" minimum="1" value="100" maximum="{(widthMeasure.selectedIndex==0)?(100):(4000)}" />
<mx:ComboBox id="widthMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="1" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Height:</s:Label>
<s:NumericStepper id="newHeight" height="22" width="150" minimum="1" value="100" maximum="{(heightMeasure.selectedIndex==0)?(100):(4000)}"/>
<mx:ComboBox id="heightMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="1" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:CheckBox id="skipCorrect" label="Skip file if the size is correct" selected="false" />
<s:Label/>
<s:Label>Output file names:</s:Label>
<s:HGroup verticalAlign="middle">
<s:TextInput id="nameInput" width="240" text="%initialName%" />
<s:Button width="35" label="?" click="contentStack.selectedIndex = 2;" />
</s:HGroup>
<s:Label>Output destination:</s:Label>
<s:HGroup verticalAlign="middle">
<s:RadioButton id="oldDestination" label="Same directory" groupName="destinationGroup" selected="true" />
<s:RadioButton id="newDestination" label="Specified directory" groupName="destinationGroup" />
</s:HGroup>
<s:HGroup verticalAlign="middle" width="100%">
<s:TextInput width="100%" id="destinationInput" enabled="{newDestination.selected}" text="Select destination..." editable="false" />
<s:Button width="80" label="Browse" enabled="{newDestination.selected}" click="pickDestination();" />
</s:HGroup>
<s:Label/>
<s:Label>Output format:</s:Label>
<mx:ComboBox width="100%" height="22" id="formatCombo" dataProvider="{formats}" selectedIndex="0" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:Label/>
<s:Label>Output JPG quality:</s:Label>
<s:HSlider id="qualitySlider" width="100%" minimum="1" maximum="100" value="100" />
<s:Label/>
<s:Button label="Resize" width="100%" click="beginResize();" />
</s:VGroup>
</s:NavigatorContent>
Now were going to add some major changes to the resizeNext() function.
However, the code that we add will not be very big. Were just going to add a needResize boolean value which is set to false if the new height and width equal the old height and width of the image. We are, however, going to have to move large piece of code from the onTimer() function into the resizeNext() function itself.
We are doing this so that we can calculate new size of the picture before starting the timer and wasting time on it. We just load the image, then set all the variables, such as newExtension, currentW, currentH, newW, newH, ratio, newName and needResize, calculate their values, check if the size has changed, and if it hasnt - dont even bother with the timer and just call nextAction(). Otherwise, start the timer and resize normally.
private function resizeNext(isFolder:Boolean):void {
var file:File;
var canProceed:Boolean = true;
var loader:Loader;
var currentProgress:int = progressBar.value + 1;
progressBar.setProgress(currentProgress, totalFiles);
// if its a file
if (!isFolder){
currentNum++;
file = new File(selectedFiles[currentNum - 1].path);
}
// if its a folder
if (isFolder) {
file = folderArray.pop();
if (folderArray.length == 0) {
currentNum++;
}
}
if(file!=null) logArea.appendText("#" + currentProgress + " (" + file.name + ")
");
// Error: file not found
if (file != null && !file.exists) {
canProceed = false;
appendHighlight("ERROR: File not found
", 0xff2222);
errorText += "File not found at location: " + file.nativePath + File.lineEnding;
totalErrors++;
nextAction();
}
// Error: bad extension
if (file != null && (file.exists && file.extension.toLowerCase() != "png" && file.extension.toLowerCase() != "jpg" && file.extension.toLowerCase() != "jpeg")) {
canProceed = false;
appendHighlight("ERROR: Incorrect extension
", 0xff2222);
errorText += "Incorrect file extension: " + file.nativePath + File.lineEnding;
totalErrors++;
nextAction();
}
if (file == null) {
canProceed = false
nextAction();
};
var newExtension:String;
var currentW:int;
var currentH:int;
var newW:int;
var newH:int;
var ratio:Number;
var newName:String
var needResize:Boolean = true;
// load image
if (canProceed) {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest(file.url));
}
// start timer
function onLoadComplete(evt:Event):void {
// new name
newName = nameInput.text.replace("%initialName%", file.name.substr(0, file.name.lastIndexOf(.)));
newName = newName.replace("%num%", currentProgress);
// new extension
if (formatCombo.selectedIndex == 0) newExtension = file.extension;
if (formatCombo.selectedIndex == 1) newExtension = "jpg";
if (formatCombo.selectedIndex == 2) newExtension = "png";
// new size
currentW = loader.content.width;
currentH = loader.content.height;
if (actionCombo.selectedIndex == 0) {
if (widthMeasure.selectedIndex == 0) newW = newWidth.value/100 * currentW;
if (widthMeasure.selectedIndex == 1) newW = newWidth.value;
if (heightMeasure.selectedIndex == 0) newH = newHeight.value/100 * currentH;
if (heightMeasure.selectedIndex == 1) newH = newHeight.value;
}
if (actionCombo.selectedIndex == 1) {
ratio = currentW / currentH;
if (widthMeasure.selectedIndex == 0) newW = newWidth.value/100 * currentW;
if (widthMeasure.selectedIndex == 1) newW = newWidth.value;
newH = newW / ratio;
}
if (actionCombo.selectedIndex == 2) {
ratio = currentW / currentH;
if (heightMeasure.selectedIndex == 0) newH = newHeight.value/100 * currentH;
if (heightMeasure.selectedIndex == 1) newH = newHeight.value;
newW = newH * ratio;
}
if (actionCombo.selectedIndex == 3) {
ratio = currentW / currentH;
newW = newWidth.value;
newH = newW / ratio;
if (newH > newHeight.value) {
newH = newHeight.value;
newW = ratio * newH;
}
}
if (skipCorrect.selected && currentW == newW && currentH == newH) {
needResize = false;
logArea.appendText("Skipped: " + file.name + "
");
nextAction();
}
if(needResize){
var timer:Timer = new Timer(200, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
timer.start();
}
}
function onTimer(evt:TimerEvent):void {
// log
logArea.appendText("Resized from " + currentW + "x" + currentH + " to " + newW + "x" + newH + "
");
logArea.appendText("Renamed to " + newName + "." + newExtension + "
");
// extract
var matrix:Matrix = new Matrix();
matrix.scale(newW/currentW, newH/currentH);
var bitmapData:BitmapData = new BitmapData(newW, newH, false, 0xffffff);
bitmapData.draw(loader.content, matrix, null, null, null, true);
var encoder:IImageEncoder;
if (newExtension == "jpg") encoder = new JPEGEncoder(qualitySlider.value);
if (newExtension == "png") encoder = new PNGEncoder();
var byteArray:ByteArray = encoder.encode(bitmapData);
var newfile:File;
if (newDestination.selected) newfile = new File(destinationPicked + File.separator + newName + "." + newExtension);
if (oldDestination.selected) newfile = new File(file.parent.nativePath + File.separator + newName + "." + newExtension);
var stream:FileStream = new FileStream();
stream.open(newfile, FileMode.WRITE);
stream.writeBytes(byteArray);
stream.close();
successFiles++;
nextAction();
}
}
Full code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="300" height="460"
showStatusBar="false" title="KirSizer" creationComplete="init();">
<fx:Declarations>
<mx:ArrayCollection id="measures">
<fx:String>%</fx:String>
<fx:String>px</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="actions">
<fx:String>Fixed width, fixed height</fx:String>
<fx:String>Fixed width, proportional height</fx:String>
<fx:String>Proportional width, fixed height</fx:String>
<fx:String>Proportional sizes to fit specified sizes</fx:String>
</mx:ArrayCollection>
<mx:ArrayCollection id="formats">
<fx:String>Same format as initial file</fx:String>
<fx:String>Convert all to JPG</fx:String>
<fx:String>Convert all to PNG</fx:String>
</mx:ArrayCollection>
<mx:Fade id="fadeIn" alphaFrom="0" alphaTo="1" duration="300"/>
<mx:Fade id="fadeOut" alphaFrom="1" alphaTo="0" duration="300"/>
<mx:TitleWindow id="waitWindow" title="Please wait" width="240" height="70" showCloseButton="false">
<s:Group width="100%" height="100%">
<s:Label top="10" left="10" id="waitLabel" width="220" color="0x000000" />
</s:Group>
</mx:TitleWindow>
</fx:Declarations>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
#contentStack{
backgroundColor: #313131;
}
s|Label{
color: #fcfcfc;
}
s|Button{
chromeColor: #636363;
}
mx|ComboBox{
chromeColor: #636363;
color: #fcfcfc;
contentBackgroundColor: #000000;
rollOverColor: #aaaaaa;
selectionColor: #ffffff;
}
#logArea{
contentBackgroundColor: #111111;
focusedTextSelectionColor: #0000ff;
fontFamily: "Courier New";
color: #aaaaaa;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.FileListEvent;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.geom.Matrix;
import flash.net.FileFilter;
import flash.net.URLRequest;
import flash.system.ImageDecodingPolicy;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.Timer;
import mx.collections.ArrayCollection;
import mx.controls.Image;
import mx.effects.easing.Linear;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.events.StateChangeEvent;
import mx.graphics.codec.IImageEncoder;
import mx.graphics.codec.JPEGEncoder;
import mx.graphics.codec.PNGEncoder;
import mx.managers.PopUpManager;
import flashx.textLayout.formats.TextLayoutFormat
[Bindable]
private var selectedFiles:ArrayCollection = new ArrayCollection([]);
private var totalFiles:int;
private var currentNum:int;
private var totalErrors:int;
private var folderArray:Array = [];
private var destinationPicked:String = "";
private var errorText:String;
private var successFiles:int;
private function init():void {
addEventListener(KeyboardEvent.KEY_DOWN, keybDown);
}
private function keybDown(evt:KeyboardEvent):void {
if (evt.ctrlKey && evt.keyCode == 65) {
var arr:Array = [];
for (var i:int = 0; i < selectedFiles.length; i++) {
arr.push(i);
}
tileList.selectedIndices = arr;
}
}
private function actionChange():void{
switch (actionCombo.selectedIndex) {
case 0:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
case 1:
newWidth.enabled = true;
widthMeasure.enabled = true;
newHeight.enabled = false;
heightMeasure.enabled = false;
break;
case 2:
newWidth.enabled = false;
widthMeasure.enabled = false;
newHeight.enabled = true;
heightMeasure.enabled = true;
break;
case 3:
newWidth.enabled = true;
widthMeasure.enabled = false;
newHeight.enabled = true;
heightMeasure.enabled = false;
widthMeasure.selectedIndex = 1;
heightMeasure.selectedIndex = 1;
}
}
private function addFiles():void {
var file:File = new File();
file.browseForOpenMultiple("Select JPG or PNG files", [new FileFilter("Pictures", "*.jpg;*.jpeg;*.png")]);
file.addEventListener(FileListEvent.SELECT_MULTIPLE, filesSelected);
}
private function filesSelected(evt:FileListEvent):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting files...";
var timer:Timer = new Timer(500, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFiles(evt.files);
PopUpManager.removePopUp(waitWindow);
}
}
private function addFolder():void {
var file:File = new File();
file.browseForDirectory("Select a directory");
file.addEventListener(Event.SELECT, folderSelected);
}
private function folderSelected(evt:Event):void {
var file:File = evt.currentTarget as File;
Alert.show("Do you want to select subfolders too?", "Recursive selection?", Alert.YES | Alert.NO, null, warningClose);
function warningClose(ev:CloseEvent):void {
if (ev.detail == Alert.YES) {
startFolder(file, true);
}
if (ev.detail == Alert.NO) {
startFolder(file, false);
}
}
}
private function startFolder(file:File, recurs:Boolean):void {
PopUpManager.addPopUp(waitWindow, this);
PopUpManager.centerPopUp(waitWindow);
waitLabel.text = "Selecting folders...";
var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onWait);
timer.start();
function onWait(ev:TimerEvent):void {
doFolder(file, recurs);
PopUpManager.removePopUp(waitWindow);
}
}
private function doFiles(files:Array):void {
for (var i:int = 0; i < files.length; i++) {
var alreadySelected:Boolean = false;
for (var u:int = 0; u < selectedFiles.length; u++) {
if (selectedFiles[u].type == 0 && selectedFiles[u].path == files[i].nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem({type:0, path:files[i].nativePath});
}
updateTotalFiles();
}
private function doFolder(file:File, isRecursive:Boolean):void {
var picturesInFolder:int = 0;
var childFiles:Array = file.getDirectoryListing();
for (var i:int = 0; i < childFiles.length; i++) {
if (childFiles[i].extension == "png" || childFiles[i].extension == "jpg" || childFiles[i].extension == "jpeg") {
picturesInFolder++;
}
if (childFiles[i].isDirectory && isRecursive) {
doFolder(childFiles[i], true);
}
}
if (picturesInFolder > 0) {
var alreadySelected:Boolean = false;
for (var a:int = 0; a < selectedFiles.length; a++) {
if (selectedFiles[a].type == 1 && selectedFiles[a].path == file.nativePath) {
alreadySelected = true;
}
}
if (!alreadySelected) selectedFiles.addItem( { type:1, path:file.nativePath, name:file.name, num:picturesInFolder } );
updateTotalFiles();
}
}
private function updateTotalFiles():void {
totalFiles = 0;
for (var i:int = 0; i < selectedFiles.length; i++) {
if (selectedFiles[i].type==1) {
totalFiles += selectedFiles[i].num;
}else {
totalFiles++;
}
}
labelSelected.text = totalFiles + " files selected";
}
private function removeSelected():void {
while (tileList.selectedItems.length > 0) {
selectedFiles.removeItemAt(tileList.selectedIndices[0]);
}
updateTotalFiles();
}
private function beginResize():void {
var canProceed:Boolean = true;
if (selectedFiles.length == 0) {
canProceed = false;
Alert.show("No files or folders are selected.", "Cant start resizing!");
}
if (nameInput.text.indexOf(%initialName%) < 0 && nameInput.text.indexOf(%num%) < 0) {
canProceed = false;
Alert.show("No wildcards were used in the name field! They are essential for each output file to have an unique name.", "Cant start resizing!");
}
if (newDestination.selected && destinationPicked == "") {
canProceed = false;
Alert.show("No destination set!", "Cant start resizing!");
}
var testName:String = nameInput.text.replace("%initialName%", "");
testName = testName.replace("%num%", "");
if(testName.indexOf(/)>=0 || testName.indexOf("\")>=0 || testName.indexOf(?)>=0 || testName.indexOf(%)>=0 ||
testName.indexOf(*)>=0 || testName.indexOf(:)>=0 || testName.indexOf(|)>=0 || testName.indexOf(")>=0 ||
testName.indexOf(<) >= 0 || testName.indexOf(>) >= 0 || testName.indexOf(.) >= 0) {
canProceed = false;
Alert.show("Illegal characters in the name field! Make sure file name field does not contain these characters: / ? % * : | " < > . ", "Cant start resizing!");
}
if (canProceed) {
contentStack.selectedIndex = 3;
var timer:Timer = new Timer(400, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
timer.start();
function onTimer(evt:TimerEvent):void {
buttonError.enabled = false;
buttonReturn.enabled = false;
logArea.text = "";
logArea.appendText("Beginning resizing of " + totalFiles + " files...
");
currentNum = 0;
totalErrors = 0;
successFiles = 0;
progressBar.setProgress(0, totalFiles);
errorText = "Error log of resizing operation of " + totalFiles + " files." + File.lineEnding + "Started at: " + new Date() + File.lineEnding;
errorText += "----------------------" + File.lineEnding;
statusText.setStyle("color", 0xffff55);
statusText.text = "IN PROGRESS";
nextAction();
}
}
}
private function resizeNext(isFolder:Boolean):void {
var file:File;
var canProceed:Boolean = true;
var loader:Loader;
var currentProgress:int = progressBar.value + 1;
progressBar.setProgress(currentProgress, totalFiles);
// if its a file
if (!isFolder){
currentNum++;
file = new File(selectedFiles[currentNum - 1].path);
}
// if its a folder
if (isFolder) {
file = folderArray.pop();
if (folderArray.length == 0) {
currentNum++;
}
}
if(file!=null) logArea.appendText("#" + currentProgress + " (" + file.name + ")
");
// Error: file not found
if (file != null && !file.exists) {
canProceed = false;
appendHighlight("ERROR: File not found
", 0xff2222);
errorText += "File not found at location: " + file.nativePath + File.lineEnding;
totalErrors++;
nextAction();
}
// Error: bad extension
if (file != null && (file.exists && file.extension.toLowerCase() != "png" && file.extension.toLowerCase() != "jpg" && file.extension.toLowerCase() != "jpeg")) {
canProceed = false;
appendHighlight("ERROR: Incorrect extension
", 0xff2222);
errorText += "Incorrect file extension: " + file.nativePath + File.lineEnding;
totalErrors++;
nextAction();
}
if (file == null) {
canProceed = false
nextAction();
};
var newExtension:String;
var currentW:int;
var currentH:int;
var newW:int;
var newH:int;
var ratio:Number;
var newName:String
var needResize:Boolean = true;
// load image
if (canProceed) {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest(file.url));
}
// start timer
function onLoadComplete(evt:Event):void {
// new name
newName = nameInput.text.replace("%initialName%", file.name.substr(0, file.name.lastIndexOf(.)));
newName = newName.replace("%num%", currentProgress);
// new extension
if (formatCombo.selectedIndex == 0) newExtension = file.extension;
if (formatCombo.selectedIndex == 1) newExtension = "jpg";
if (formatCombo.selectedIndex == 2) newExtension = "png";
// new size
currentW = loader.content.width;
currentH = loader.content.height;
if (actionCombo.selectedIndex == 0) {
if (widthMeasure.selectedIndex == 0) newW = newWidth.value/100 * currentW;
if (widthMeasure.selectedIndex == 1) newW = newWidth.value;
if (heightMeasure.selectedIndex == 0) newH = newHeight.value/100 * currentH;
if (heightMeasure.selectedIndex == 1) newH = newHeight.value;
}
if (actionCombo.selectedIndex == 1) {
ratio = currentW / currentH;
if (widthMeasure.selectedIndex == 0) newW = newWidth.value/100 * currentW;
if (widthMeasure.selectedIndex == 1) newW = newWidth.value;
newH = newW / ratio;
}
if (actionCombo.selectedIndex == 2) {
ratio = currentW / currentH;
if (heightMeasure.selectedIndex == 0) newH = newHeight.value/100 * currentH;
if (heightMeasure.selectedIndex == 1) newH = newHeight.value;
newW = newH * ratio;
}
if (actionCombo.selectedIndex == 3) {
ratio = currentW / currentH;
newW = newWidth.value;
newH = newW / ratio;
if (newH > newHeight.value) {
newH = newHeight.value;
newW = ratio * newH;
}
}
if (skipCorrect.selected && currentW == newW && currentH == newH) {
needResize = false;
logArea.appendText("Skipped: " + file.name + "
");
nextAction();
}
if(needResize){
var timer:Timer = new Timer(200, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
timer.start();
}
}
function onTimer(evt:TimerEvent):void {
// log
logArea.appendText("Resized from " + currentW + "x" + currentH + " to " + newW + "x" + newH + "
");
logArea.appendText("Renamed to " + newName + "." + newExtension + "
");
// extract
var matrix:Matrix = new Matrix();
matrix.scale(newW/currentW, newH/currentH);
var bitmapData:BitmapData = new BitmapData(newW, newH, false, 0xffffff);
bitmapData.draw(loader.content, matrix, null, null, null, true);
var encoder:IImageEncoder;
if (newExtension == "jpg") encoder = new JPEGEncoder(qualitySlider.value);
if (newExtension == "png") encoder = new PNGEncoder();
var byteArray:ByteArray = encoder.encode(bitmapData);
var newfile:File;
if (newDestination.selected) newfile = new File(destinationPicked + File.separator + newName + "." + newExtension);
if (oldDestination.selected) newfile = new File(file.parent.nativePath + File.separator + newName + "." + newExtension);
var stream:FileStream = new FileStream();
stream.open(newfile, FileMode.WRITE);
stream.writeBytes(byteArray);
stream.close();
successFiles++;
nextAction();
}
}
private function nextAction():void {
if (currentNum < selectedFiles.length) {
checkLineLimit();
var isFolder:Boolean = false;
var folder:File = new File(selectedFiles[currentNum].path);
// if its a folder, create a global array that stores all image files of the folder
if (folderArray.length > 0) isFolder = true;
if (folder.exists && selectedFiles.length > currentNum && selectedFiles[currentNum].type == 1 && folderArray.length == 0) {
isFolder = true;
folderArray = [];
var allContent:Array = folder.getDirectoryListing();
for (var i:int = 0; i < allContent.length; i++) {
if (allContent[i].isDirectory == false && (allContent[i].extension.toLowerCase() == "png" || allContent[i].extension.toLowerCase() == "jpg" || allContent[i].extension.toLowerCase() == "jpeg")) {
folderArray.push(allContent[i]);
}
}
if (selectedFiles[currentNum].num != folderArray.length) {
appendHighlight("ERROR: incorrect amount of image files found in folder " + folder.name + "
", 0xff2222);
errorText += "Not enough or too many image files found in folder " + folder.nativePath + " (some files were removed/added before it was this folders turn to be resized)" + File.lineEnding;
totalErrors++;
}
}
if (!folder.exists && selectedFiles.length > currentNum && selectedFiles[currentNum].type == 1 && folderArray.length == 0) {
appendHighlight("ERROR: folder not found (" + folder.name + ")
", 0xff2222);
errorText += "Folder was not found at " + folder.nativePath + File.lineEnding;
totalErrors++;
currentNum++;
nextAction();
return;
}
resizeNext(isFolder);
}else {
progressBar.setProgress(totalFiles, totalFiles);
appendHighlight("Operation complete!
Errors: " + totalErrors + "
Files resized: " + successFiles + "/" + totalFiles, 0xffff44);
errorText += "----------------------" + File.lineEnding + "Total errors: " + totalErrors + File.lineEnding + "Files resized: " + successFiles + "/" + totalFiles;
buttonError.enabled = true;
buttonReturn.enabled = true;
statusText.setStyle("color", 0x44ff44);
statusText.text = "COMPLETED";
}
}
private function pickDestination():void {
var file:File = new File();
file.browseForDirectory("Select ouput destination");
file.addEventListener(Event.SELECT, outputSelect);
function outputSelect(evt:Event):void {
destinationPicked = file.nativePath;
destinationInput.text = destinationPicked;
}
}
private function saveErrors():void {
var file:File = File.desktopDirectory.resolvePath("errors.txt");
file.browseForSave("Save error log");
file.addEventListener(Event.SELECT, errorSelect);
function errorSelect(evt:Event):void {
if (!file.nativePath.match(/^.*.(txt)$/i)) {
file.nativePath += ".txt";
}
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeUTFBytes(errorText);
fileStream.close();
}
}
private function appendHighlight(text:String, color:uint):void {
var formatHighlight:TextLayoutFormat = new TextLayoutFormat();
formatHighlight.color = color;
var formatNormal:TextLayoutFormat = new TextLayoutFormat();
formatNormal.color = 0xaaaaaa;
var firstAnchor:int = logArea.text.length;
logArea.appendText(text);
var secondAnchor:int = logArea.text.length;
logArea.setFormatOfRange(formatHighlight, firstAnchor, secondAnchor);
logArea.setFormatOfRange(formatNormal, secondAnchor, secondAnchor);
}
private function checkLineLimit():void {
if (countLines(logArea.text) > 24) {
logArea.text = "";
}
}
private function countLines(text:String):int {
var splittedText:Array = text.split("
");
var lines:int = splittedText.length;
return lines;
}
]]>
</fx:Script>
<mx:ViewStack id="contentStack" width="100%" height="100%" >
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Label id="labelSelected">0 files selected</s:Label>
<mx:TileList id="tileList" width="282" height="100%" dataProvider="{selectedFiles}" itemRenderer="TileRenderer" columnWidth="60" rowHeight="60" columnCount="4" allowMultipleSelection="true" selectionColor="0xff0000" rollOverColor="0xff8888" />
<s:Button label="Add folder" width="100%" click="addFolder();" />
<s:Button label="Add files" width="100%" click="addFiles();" />
<s:Button label="{Remove + tileList.selectedItems.length + items}" width="100%" enabled="{tileList.selectedItems.length>0}" click="removeSelected();" />
<s:Button label="Continue" width="100%" click="contentStack.selectedIndex = 1;" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10">
<s:Button label="Return to file selection" width="100%" click="contentStack.selectedIndex = 0;" />
<s:Label>Resize options:</s:Label>
<mx:ComboBox width="100%" id="actionCombo" height="22" dataProvider="{actions}" selectedIndex="0" editable="false" change="actionChange();"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Width:</s:Label>
<s:NumericStepper id="newWidth" height="22" width="150" minimum="1" value="100" maximum="{(widthMeasure.selectedIndex==0)?(100):(4000)}" />
<mx:ComboBox id="widthMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="1" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label width="50">Height:</s:Label>
<s:NumericStepper id="newHeight" height="22" width="150" minimum="1" value="100" maximum="{(heightMeasure.selectedIndex==0)?(100):(4000)}"/>
<mx:ComboBox id="heightMeasure" height="22" width="50" dataProvider="{measures}" selectedIndex="1" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
</s:HGroup>
<s:CheckBox id="skipCorrect" label="Skip file if the size is correct" selected="false" />
<s:Label/>
<s:Label>Output file names:</s:Label>
<s:HGroup verticalAlign="middle">
<s:TextInput id="nameInput" width="240" text="%initialName%" />
<s:Button width="35" label="?" click="contentStack.selectedIndex = 2;" />
</s:HGroup>
<s:Label>Output destination:</s:Label>
<s:HGroup verticalAlign="middle">
<s:RadioButton id="oldDestination" label="Same directory" groupName="destinationGroup" selected="true" />
<s:RadioButton id="newDestination" label="Specified directory" groupName="destinationGroup" />
</s:HGroup>
<s:HGroup verticalAlign="middle" width="100%">
<s:TextInput width="100%" id="destinationInput" enabled="{newDestination.selected}" text="Select destination..." editable="false" />
<s:Button width="80" label="Browse" enabled="{newDestination.selected}" click="pickDestination();" />
</s:HGroup>
<s:Label/>
<s:Label>Output format:</s:Label>
<mx:ComboBox width="100%" height="22" id="formatCombo" dataProvider="{formats}" selectedIndex="0" editable="false"
openEasingFunction="Linear.easeOut" closeEasingFunction="Linear.easeIn" openDuration="300" closeDuration="300"/>
<s:Label/>
<s:Label>Output JPG quality:</s:Label>
<s:HSlider id="qualitySlider" width="100%" minimum="1" maximum="100" value="100" />
<s:Label/>
<s:Button label="Resize" width="100%" click="beginResize();" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="280" top="10" left="10">
<s:VGroup width="100%" height="410" gap="20">
<s:Label fontSize="20" width="100%" fontWeight="bold">Output file names</s:Label>
<s:Label width="100%">You can build names for output files using provided wildcards and combining them with text.</s:Label>
<s:Label width="100%">For example, "%initialName%_new" will generate names like "pic_new.jpg", "img_new.png", etc.</s:Label>
<s:Label width="100%">Available wildcards are:</s:Label>
<s:Label fontSize="18" width="100%" fontWeight="bold">%initialName%</s:Label>
<s:Label width="100%">Puts the initial name of the file thats being resized.</s:Label>
<s:Label fontSize="18" width="100%" fontWeight="bold">%num%</s:Label>
<s:Label width="100%">Gives each file a unique id number starting from 1.</s:Label>
</s:VGroup>
<s:Button label="Back" width="100%" click="contentStack.selectedIndex = 1;" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" hideEffect="fadeOut" showEffect="fadeIn">
<s:VGroup width="280" height="440" top="10" left="10">
<s:Label width="100%" color="0xff3333" fontWeight="bold">Do not add, remove or rename selected files.</s:Label>
<s:Group width="100%">
<mx:ProgressBar id="progressBar" width="100%" mode="manual" label="Resizing %1 / %2" color="0xffffff" />
<s:Label top="20" left="200" textAlign="right" id="statusText" fontWeight="bold"/>
</s:Group>
<s:TextArea id="logArea" editable="false" width="100%" height="100%" />
<s:HGroup>
<s:Button id="buttonError" label="Save error log" click="saveErrors();" width="136" />
<s:Button id="buttonReturn" label="Return" click="contentStack.selectedIndex = 0;" width="136" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</s:WindowedApplication>
Thanks for reading!
Subscribe to:
Comments (Atom)