Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Котяра

Оценить эту запись

Инструмент для обрезки и склеивания набора png

Запись от Котяра размещена 17.09.2009 в 19:34
Обновил(-а) Котяра 23.11.2010 в 14:41

Недавно озадачился скриптиком для обрезки и склеивания битмап изображений ( в данном случае прозрачного png) и генерации xml с координатами обрезки..
попросил помощи здесь:http://www.flasher.ru/forum/showthread.php?t=130000
Ответа не услышал))
пришлось написать самому.
Сделал AIR приложение.
кому интересно вот код, исходники во вложении.
pngConverter.zip - flashDevelop project
allFlashCS3Components.zip - либа с флэшевскими компонентами ( нужно закинуть в папку lib проекта)
Код AS3:
package 
{
	import fl.controls.Button;
	import fl.controls.ComboBox;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filesystem.File;
	import flash.events.FileListEvent;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.utils.ByteArray;
	import org.aswing.image.png.*;
	/**
	 * Интсрумент для обрезки и склеивания набора битмап в "простыню"
	 * на выходе получаем png файл и xml с параметрами обрезки и склеивания
	 * @author k0t0vich
	 */
	public class Main extends Sprite 
	{
 
		private var file:File;
		private var counter:int = 0;
		private var btn:Button;
		private var tfLabel:TextField = new TextField();
		private var tfCols:TextField = new TextField();
		private var encoderCombo:ComboBox = new ComboBox();
		private var colCombo:ComboBox = new ComboBox();
		//var dp:DataProvider = new DataProvider();
		private var fileListArray:Array = [];
		private var fileListCounter:int = 0;
		private var bitmapArray:Array = []; 
		private var trimedBitmapDataArray:Array = []; 
		private var loader:Loader = new Loader();
		private var ext:String = "png";
		private var encoder:AsPngEncoder = new AsPngEncoder();
		private var encoders:Array = [
					new Strategy32BitAlpha(), 
					new Strategy32BitOpaque(), 
					new Strategy8BitMedianCutAlpha(256, 4), 
					new Strategy8BitMedianCutAlpha(128, 4),  
					new Strategy8BitMedianCutAlpha(64), 
					new Strategy8BitMedianCutAlpha(16), 
					new Strategy8BitMedianCutAlpha(8), 
					new Strategy8BitMedianCutAlpha(4), 
					new Strategy8BitMedianCutAlpha(2), 
					new Strategy8BitMedianCutOpaque(256), 
					new Strategy8BitMedianCutOpaque(64), 
					new Strategy8BitMedianCutOpaque(9), 
					new Strategy8BitUniformQuantAlpha(), 
					new Strategy8BitUniformQuant(6, 7, 6), 
					new Strategy8BitUniformQuant(6, 6, 6), 
					new Strategy8BitUniformQuant(8, 8, 4), 
					new Strategy8BitUniformQuant(5, 5, 5), 
					new Strategy8BitUniformQuant(4, 4, 4), 
					new Strategy8BitUniformQuant(2, 2, 2)
					];
 
		private var trimXML:XML = <data/>;
		private var saveFile:File;
		private var encodedPng:ByteArray;
		private var cols:int = 8;
 
 
		public function Main():void 
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;	
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.LOW;
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadPNG);
			drawUI();
			Output.trace("В начале работы необходимо выбрать количество изображений на ряд,\nзатем формат сохранения изображения,\nпосле этого выбирайте папку назначения");
		}
 
		private function drawUI():void
		{
			addChild(new Output());
 
			btn = new Button();
			btn.label = "Выбрать директорию исходных изображений";
			btn.width = 300;
			btn.y =10;
			btn.addEventListener(MouseEvent.CLICK, btn_click);
			addChild(btn);
 
			tfLabel.x = btn.x +btn.width + 10; 
			tfLabel.y = btn.y; 
			tfLabel.text = "Изображений в ряду:";
			tfLabel.autoSize = TextFieldAutoSize.LEFT;
			tfLabel.selectable = false;
			addChild(tfLabel);
 
 
			colCombo.width = 40;
			colCombo.editable = false;
			colCombo.x = tfLabel.x +tfLabel.width+ 10;
			colCombo.y = tfLabel.y;
			for (var i:int = 0; i <32; i++) 
			{
				colCombo.addItem( { label:String(i+1) } );
			}
			colCombo.selectedIndex = 7;
			addChild(colCombo);
 
			encoderCombo.width =240;
			encoderCombo.editable=false;
			encoderCombo.x = colCombo.x+60
			encoderCombo.y = colCombo.y;
			for (i= 0; i < encoders.length; i++) 
			{
				encoderCombo.addItem( { label:encoders[i].toString() } );
			}
			encoderCombo.selectedIndex = 2;
			addChild(encoderCombo);
 
		}
 
 
		private function fileListLoaded(evt:FileListEvent):void 
		{
			fileListArray = evt.files;
			loadNextFile();;
		}
 
		private function loadNextFile():void
		{
			var len:int = fileListArray.length;
			if (fileListCounter == len) { trimImages(); return; }
 
			var file:File = fileListArray[fileListCounter];
			if (String(file.extension).toLowerCase() == ext)
			{	
				loader.load(new URLRequest(file.url));
				var imgXML:XML = <img/>;
				imgXML.@img = file.name;
				trimXML.appendChild(imgXML);
 
			}
			else
			{
				fileListCounter++;
				loadNextFile();
			}
		}
 
		private function trimImages():void
		{
 
			var len:int = bitmapArray.length;
			Output.trace("Обрезка исходных изображений len= "+len);
			for (var i:int = 0; i < len; i++) 
			{
				var sourceBitmapData:BitmapData = bitmapArray[i].bitmapData;
				var rect:Rectangle = sourceBitmapData.getColorBoundsRect(0xFF000000, 0x00000000,false);
				var trimedBitmapData:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
				// запись вырезанных параметров в XML
				var imgXML:XML = trimXML.img[i];
				imgXML.@top = rect.top;
				imgXML.@left = rect.left;
				imgXML.@width = rect.width;
				imgXML.@heigth = rect.height;
 
				trimedBitmapData.copyPixels(sourceBitmapData, rect, new Point());
				trimedBitmapDataArray.push(trimedBitmapData);
				// удаляем
				sourceBitmapData.dispose();
				bitmapArray[i] = null;
 
			}
 
			montageTrimmedBitmaps();
		}
 
 
		private function montageTrimmedBitmaps():void
		{
			Output.trace("Main.montageTrimmedBitmaps");
			// вычисляем размер результирующей битмапы
			var maxH:int = 0;
			var maxW:int = 0;
 
			var h:int = 0;
			var w:int = 0;
			var maxHArray:Array = [];
			var maxWArray:Array = [];
			cols = colCombo.selectedIndex+1;
			var len:int = trimedBitmapDataArray.length;
			var rows:int = Math.ceil(len / cols);
 
 
			for (var i:int = 0; i <rows; i++) 
			{
				maxH = 0;
				maxW = 0;
				for (var j:int = 0; j < cols && i*(cols) + j < len; j++) 
				{
					var bitmapData:BitmapData = trimedBitmapDataArray[i*(cols) + j];
					maxH = Math.max(maxH, bitmapData.height);					
					maxW += bitmapData.width;
				}
				// сохранем в массив, для последующего монтажа
				maxWArray.push(maxW)
				maxHArray.push(maxH);
				h += maxH;
			}
 
			var wlen:int = maxWArray.length;
			for (i = 0; i < wlen; i++) 
			{
				w = Math.max(maxWArray[i], w);
			}
 
 
			// создаём результирующую битмапдату
			Output.trace("w, h : " + w, h);
			if (w > 2880 || h > 2880) Output.trace("Слишком большой размер бимапы > 2880");
			trimXML.@width = w;
			trimXML.@heiht = h;
			var resultBitmapData:BitmapData = new BitmapData(w, h, true, 0);
 
			// текущая точка вставки
			var curX:int = 0;
			var curY:int = 0;
 
			for ( i= 0; i < rows; i++) 
			{	
				curX = 0;
				for (j = 0; j < cols && i*(cols) + j < len; j++) 
				{
					var id:int = i * (cols) + j;
					var point:Point = new Point(curX, curY);
					var imgXML:XML = trimXML.img[id];
					imgXML.@x = curX;
					imgXML.@y = curY;
					//imgXML.@id = id;
					bitmapData= trimedBitmapDataArray[id];
					var rect:Rectangle = new Rectangle(0, 0, bitmapData.width, bitmapData.height);
					resultBitmapData.copyPixels(bitmapData, rect, point);
					curX += bitmapData.width;
 
					// удаляем
					bitmapData.dispose();
					trimedBitmapDataArray[id] = null;
				}
				curY += maxHArray[i];
			}
			//тест
			//addChild(new Bitmap(resultBitmapData));
 
			// запись
			saveBitmapDataAsPng(resultBitmapData);
 
		}
 
		private function saveBitmapDataAsPng(bitmapData:BitmapData):void
		{
			Output.trace("Main.saveBitmapDataAsPng ");
			encodedPng = encoder.encode(bitmapData, encoders[encoderCombo.selectedIndex]);
			saveFile = new File();
			saveFile.addEventListener(Event.SELECT, fileSaveSelected);
			save(new Event("!!"));	
		}
 
		private function saveTrimXML():void
		{
			Output.trace("Main.saveXML");
			saveFile = new File();
			saveFile.addEventListener(Event.SELECT, xmlSaveSelected);
			saveXML(new Event("!!"));	
		}
 
		private function xmlSaveSelected(e:Event):void {
			saveFile.removeEventListener(Event.SELECT, xmlSaveSelected);
			var stream:FileStream = new FileStream();
			if(!saveFile.exists){
				Output.trace("Создан новый файл");
			}
			stream.open(saveFile, FileMode.WRITE);
			stream.writeUTFBytes(trimXML.toXMLString());
			stream.close();
			restart();
		}	
 
 
		/**
		 * Повторное использование - удаление всего лишнего
		 */
		private function restart():void
		{
			fileListArray= [];
			fileListCounter=0;
			bitmapArray= []; 
			trimedBitmapDataArray = [];
			addChild(btn);
			Output.trace("Готов к работе");
		}
 
		private function onLoadPNG(e:Event):void 
		{	
			bitmapArray.push(e.target.content);
			fileListCounter++;
			loadNextFile();
		}
 
 
 
		 private function btn_click(evt:MouseEvent):void {
			removeChild(btn);
			Output.trace("Выберите каталог с изображениями для склейки");
			file = new File();
			file.addEventListener(Event.SELECT, directorySelected);
			file.browseForDirectory("Выберите каталог с изображениями для склейки");
		}
 
		private function directorySelected(evt:Event):void {
			file.getDirectoryListingAsync();
			file.addEventListener( FileListEvent.DIRECTORY_LISTING, fileListLoaded );
		}
 
		// сохранение png
		private function save(e:Event):void{
			saveFile.browseForSave("Сохранить файл как png (в имени файла впишите нужное расширение)");
		}
 
		private function saveXML(e:Event):void{
			saveFile.browseForSave("Сохранить файл как xml (в имени файла впишите нужное расширение)");
		}
 
 
		private function fileSaveSelected(e:Event):void {
			saveFile.removeEventListener(Event.SELECT, fileSaveSelected);
			var stream:FileStream = new FileStream();
			if(!saveFile.exists){
				Output.trace("Создан новый файл");
			}
			stream.open(saveFile, FileMode.WRITE);
			stream.writeBytes(encodedPng);
			stream.close();
			saveTrimXML();
		}		
 
	}
 
}
Размещено в игродел
Комментарии 5 Отправить другу ссылку на эту запись
Всего комментариев 5

Комментарии

Старый 23.09.2009 20:02 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
isNaN(int(e.target.text))
всегда будет false
Старый 25.09.2009 11:52 Котяра вне форума
Котяра
 
Аватар для Котяра
Код:
isNaN(int(e.target.text))
всегда будет false
вообще ф-ция
Код AS3:
private function setCols(e:Event):void 
		{
 
				if (!isNaN(int(e.target.text)))
				{
					cols = int(e.target.text);
				}
				else
				e.target.text = String(cols);
		}
не используется) забыл удалить - осталась от тестового прототипа)
Старый 07.02.2011 13:39 cleptoman вне форума
cleptoman
 
Аватар для cleptoman
докопаюсь по-мелочи )
Цитата:
Интсрумент
Старый 07.02.2011 13:42 cleptoman вне форума
cleptoman
 
Аватар для cleptoman
п.с. топик выкинуло в рандомизаторе. потом только глянул дату )
Старый 07.02.2011 16:07 mayakwd вне форума
mayakwd
 
Аватар для mayakwd
о, хорошо, что "отнекропостил" интересная штуковина.
 

 


Часовой пояс GMT +4, время: 02:12.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.