![]() |
|
||||||||||
|
|||||
|
Так быстро и не расскажешь. Лучше пример посмотреть, сейчас быстренько соберу чёнить
__________________
return this... |
|
|||||
|
FB4.7 SectorBuilder.rar
Main.as package { import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.JPEGEncoderOptions; import flash.display.Sprite; import flash.net.FileReference; import flash.utils.ByteArray; import utils.SeparateBuilder; import utils.SeparateEvent; import view.RandomView; [SWF(width="960",height="640",frameRate="60",backgroundColor="#FFFFFF")] public class Main extends Sprite { private var _viewport:Sprite; private var rview:DisplayObject private var _separe:SeparateBuilder; public function Main() { _viewport = new Sprite(); addChild( _viewport ); createRandomView(); adaptViewPort(); createSeparator(); createScreenshot(); } private function adaptViewPort():void { _viewport.width = stage.stageWidth; _viewport.height = stage.stageHeight; } private function createRandomView():void { rview = new RandomView(5000,5000); _viewport.addChild( rview ); } private function createSeparator():void { _separe = new SeparateBuilder(500); _separe.addEventListener( SeparateEvent.INIT, separateHandler ); _separe.addEventListener( SeparateEvent.COMPLETE, separateHandler ); _separe.addEventListener( SeparateEvent.PROCESSING, separateHandler ); } private function createScreenshot():void { _separe.work( rview ); } protected function separateHandler(event:SeparateEvent):void { switch (event.type) { case SeparateEvent.INIT: trace('Start'); break; case SeparateEvent.PROCESSING : trace('Processing : '+ event.data); break; case SeparateEvent.COMPLETE : trace('Complete'); encode( _separe.bitmapData ); break; } } private function encode(bitmapData:BitmapData):void { var jpeg:JPEGEncoderOptions = new JPEGEncoderOptions(); jpeg.quality = 4; var byteArray:ByteArray = bitmapData.encode( bitmapData.rect, jpeg); save( byteArray ); } private function save(byteArray:ByteArray):void { var fr:FileReference = new FileReference(); fr.save( byteArray , 'screenshot_'+new Date().time+'.jpg' ); } } } package utils { import flash.display.BitmapData; import flash.display.DisplayObject; import flash.events.EventDispatcher; import flash.geom.Point; import flash.utils.ByteArray; import flash.utils.setTimeout; import net.alexscript.hack.Extruder; public class SeparateBuilder extends EventDispatcher { private var _blockSize:Number; private var _height:Number; private var _target:DisplayObject; private var _byteArray:ByteArray; private var _map:Point; private var _iteration:uint; private var _cache:BitmapData; public function SeparateBuilder(blockSize:Number=500) { super(); _blockSize = blockSize; } public function work(view:DisplayObject):void { if (_target) { throw new Error('SeparateBuilder is work'); } target = view; } public function get bitmapData():BitmapData { return _cache; } private function set target(value:DisplayObject):void { _target = value; _iteration = 0; _byteArray = new ByteArray(); _cache = new BitmapData(_target.width, _target.height,true); calculation(); say( SeparateEvent.INIT ); processing(); } private function calculation():void { _map = new Point( Math.floor( target.width / _blockSize ), Math.floor( target.height / _blockSize ) ); if ( target.width > _map.x * _blockSize ) _map.x++; if ( target.height > _map.y * _blockSize ) _map.y++; trace( 'Map Sector : ',_map); } private function get target():DisplayObject { return _target; } private function processing():void { var sector:Point = new Point( _iteration % _map.x, Math.floor(_iteration/_map.x) ); snap( sector ); var length:Number = _map.x * _map.y; var percent:Number= 100/(length/_iteration); say( SeparateEvent.PROCESSING , String( Math.floor(percent) ) ); if ( ++_iteration < length ) setTimeout( processing, 1 ); else complete(); } private function snap(sector:Point):void { var anker:Point = new Point( sector.x*_blockSize, sector.y*_blockSize ); var zone:Point = new Point(_blockSize,_blockSize); if ( (anker.x+zone.x) > target.width ) zone.x = target.width - anker.x; if ( (anker.y+zone.y) > target.height ) zone.y = target.height - anker.y; var bd:BitmapData = Extruder.get( target, anker.x, anker.y , zone.x, zone.y ); _cache.copyPixels( bd, bd.rect, anker); } private function complete():void { _target = null; say( SeparateEvent.COMPLETE ); } private function say(type:String, data:String=''):void { this.dispatchEvent( new SeparateEvent( type, data ) ); } } } package utils { import flash.events.DataEvent; public class SeparateEvent extends DataEvent { public static var INIT:String = 'init'; public static var PROCESSING:String = 'processing'; public static var COMPLETE:String = 'complete'; public function SeparateEvent(type:String, data:String='') { super(type, true, false, data); } } } package view { import flash.display.Sprite; import flash.geom.Point; public class RandomView extends Sprite { private var _h:Number; private var _w:Number; public function RandomView(h:Number=5000,w:Number=5000) { super(); _h = h; _w = w; graphics.beginFill(0xAAAAAA,1); graphics.drawRect(0,0,_w,_h); graphics.endFill(); var rnd:Number = Math.floor(Math.random()*10)+10; while (--rnd) draw(); } private function draw():void { var color:uint = Math.random()*0xFFFFFF; var size:Number = Math.min(_h,_w)*.1; var body:Point = new Point( Math.random()*(_w-size*2),Math.random()*(_h-size*2)); body.x += size; body.y += size; with (graphics) { beginFill(color,1); switch( Math.floor(Math.random()*2) ) { case 0: drawRect(body.x,body.y, size, size); break; case 1: drawCircle(body.x,body.y,size); break; } endFill(); } } } } package net.alexscript.hack { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.PixelSnapping; import flash.geom.Matrix; import flash.geom.Rectangle; public class Extruder { public function Extruder() { } public static function get( ARG_object:DisplayObject, ARG_x:Number = 0, ARG_y:Number = 0, ARG_width:Number = 0, ARG_height:Number = 0,transpend:Boolean=true):BitmapData { if (!ARG_width) ARG_width = (ARG_object.mask) ? ARG_object.mask.width : ARG_object.width; if (!ARG_height) ARG_height = (ARG_object.mask) ? ARG_object.mask.height : ARG_object.height; var cropArea:Rectangle = new Rectangle(0, 0, ARG_width, ARG_height); var fillColor:uint = transpend ? 0x00000000 : 0x0; var bmpd:BitmapData = new BitmapData(ARG_width, ARG_height,true,fillColor); var croppedBitmap:Bitmap = new Bitmap(bmpd, PixelSnapping.ALWAYS, true); var cropMatrix:Matrix = new Matrix(); cropMatrix.translate(-ARG_x, -ARG_y); bmpd.draw( ARG_object, cropMatrix, null, null, cropArea, true ); return bmpd; } } }
__________________
return this... |
|
|||||
|
P.S. Нативный енкодер так же немного подвисает ( 5000x5000 - 660 ms, 15000х15000 - 5700 ms), если хотите полностью избавиться от подвисания, учите мат.часть используйте copyPixelsToByteArray, после чего пережимайте в jpeg естественно с разделением на блоки
Добавлено через 3 минуты или же используйте массив мелких JPEG, повырезать из них заголовки, склеить байтерреи и добавить общий заголовок Добавлено через 36 минут или
__________________
return this... |
|
|||||
|
Регистрация: Sep 2010
Сообщений: 167
|
Щас всё это читаю, изучаю - конечно, сложно. После AS2 и всякого рода игровых интерфейсов, это и правда что-то новенькое. Мозг взорван
![]() Добавлено через 2 часа 58 минут Примеров масса, и пока что не всё понятно. С нарезкой слишком сложно (я даже тему переименовал), надо очень долго разбираться. Пока что мне подойдёт вариант с кодированием в файл отдельный потоком. Как я понимаю, в этом случае многопоточность будет использоваться для передачи содержимого моего гигантского спрайта в новый поток, который будет преобразовывать его в JPEG, и отдавать массив байтов обратно, чтобы основной ролик выводил его в FileReference. Но ведь я не смогу передать целый Sprite на обработку, верно? Т.е. в основном потоке сначала придётся вызвать BitmapData.Draw (что даёт лаг на 3 секунды), чтобы получить его массив байтов, а вот уже BitmapData.encode мжно будет исполнять в другом потоке? Последний раз редактировалось Alex626; 01.06.2015 в 01:25. |
|
|||||
|
Регистрация: Nov 2005
Сообщений: 149
|
мне кажется, самым простым вариантом было бы воспользоваться "асинхрннными" декодерами:
там можно задать скорость кодирования. получать сообщения о прогрессе в jpg https://github.com/alinke/DIYMagicMi...syncEncoder.as в png http://www.bit-101.com/blog/?p=2581 вот кусок кода из рабочего примера if (_typeEncoding == "jpg") { var j:JPEGAsyncEncoder = new JPEGAsyncEncoder(85); j.PixelsPerIteration = 300; j.addEventListener(JPEGAsyncCompleteEvent.JPEGASYNC_COMPLETE, handleJPEGEncoder); j.addEventListener(ProgressEvent.PROGRESS, handleProgress); j.encode(_bitmap.bitmapData); } if (_typeEncoding == "png") { var p:PNGEncoderAsync = new PNGEncoderAsync(); p.addEventListener(ProgressEvent.PROGRESS, handleProgress); p.addEventListener(Event.COMPLETE, handlePNGEncoder); p.encode(_bitmap.bitmapData); } |
|
|||||
|
Регистрация: Sep 2010
Сообщений: 167
|
Спасибо, сейчас протестирую.
Добавлено через 1 час 48 минут Опробовал. Круто. Но медленно очень. Беда прям. Вот если бы он работал через обычный энкодер, но в отдельном потоке.... Последний раз редактировалось Alex626; 06.06.2015 в 02:01. |
|
|||||
|
Регистрация: Nov 2005
Сообщений: 149
|
не знаю, что за конкретная задача стоит, но если картинка действительно большая, то хоть в отдельном потоке, хоть где, время все равно будет занимать существенно много.
может, "обмануть" юзера? на необходимое время повесить для него сообщение, показать прогресс? Это объективно долгий процесс. разве что, есть библиотека на Алхимии - http://blog.inspirit.ru/async-png-encoding-and-merging/ - но она существенно тоже не поможет - проверено |
|
|||||
|
Регистрация: Sep 2010
Сообщений: 167
|
Цитата:
А как-то можно обойти ограничение размера BitmapData.Draw? У меня в системе памяти не хватает на масштабы более 234% (это где-то 20.000 х 20.000 пикс.). |
![]() |
![]() |
Часовой пояс GMT +4, время: 07:53. |
|
|
« Предыдущая тема | Следующая тема » |
|
|