📜 ⬆️ ⬇️

Drag and drop images in Flash in the browser

During the testing of your service, there was a sufficient amount of feedback that the old-school method of uploading files to the application does not take away. People wanted to drag and drop and tried to drag pictures right from the desktop. The application occupies our entire browser screen and is written on a flash, so there was no direct way to solve the problem.

After thinking and googling decided to implement D & D at least for chrome like this:
When the user switches from the tab with the application, i.e. it loses focus, on top of the flash drive a div is placed on which the event of catching dropped files is hung.
Then, through the ExternalInterface, the image in the form of a ByteArray is transmitted to flash, where it is decoded and displayed.


Display div over flash
')
#over_holder_full { background-color: #eee; opacity: 0.6; position: absolute; width: 100%; height: 100%; z-index: 7; display: none; } #flash_conainer { width: 100%; height: 100%; position: absolute; z-index: 0; } <div id="over_holder_full"></div> <div id="flash_conainer"> <div id="myContent"> <h1>Alternative content</h1> </div> </div> 


Showing #over_holder_full when losing focus, which is drag and drop

 window.addEventListener('blur', function() { fullDragArea.style.display = "block"; console.log("not focused"); }); window.addEventListener('focus', function() { fullDragArea.style.display = "none"; console.log("focus"); }); 


Catching a file dropped by #over_holder_full

 fullDragArea = $id("over_holder_full"); // is XHR2 available? var xhr = new XMLHttpRequest(); if (xhr.upload) { fullDragArea.addEventListener("dragover", FileDragHover, false); fullDragArea.addEventListener("drop", FileSelectHandler, false); // <--     //.... } 


Image transfer in flash

 // file selection function FileSelectHandler(e) { fullDragArea.style.display = "none"; // fetch FileList object var files = e.target.files || e.dataTransfer.files; //set grey preview in flash setPreview(pageX, pageY); // process all File objects setTimeout(function(){//<--     setPreview     for (var i = 0, f; f = files[i]; i++) { ParseFile(f); }}, 100); } // output file information function ParseFile(file) { var arrBuffer; if (file.type.indexOf("image") == 0) { var reader = new FileReader(); reader.onload = function(e) { //console.log("arrBuffer + " + e.target.result.byteLength); var dataview = new DataView(e.target.result); var ints = new Int32Array(e.target.result.byteLength / 4); //<--       for (var i = 0; i < ints.length; i++) { ints[i] = dataview.getInt32(i * 4);//<--    4  (        ByteArray) } console.log("ints" + ints.length); // display an image setImage(pageX, pageY, ints); } reader.readAsArrayBuffer(file); } } 


Functions connecting JavaScript and Flash

 function setImage(pageX, pageY, int32Arr) { if (swfReady){ var res = []; for (var i = 0; i < int32Arr.length; i++) { res[i] = int32Arr[i]; //<--   ..  externalinterface      ,  Int32Array   } getSWF("DefaultLauncher").setImage(pageX, pageY, res);//    -   } } function setPreview(pageX, pageY) { if (swfReady) { console.log("setPreview"); getSWF("DefaultLauncher").setPreview(pageX, pageY); } } 


Take the image on the flush side

 var exManager:EXManager = new EXManager(); exManager.setImageCallback = function(pageX:Number, pageY:Number, listBytes:Array):void{ var ba:ByteArray = new ByteArray(); for(var i:int = 0; i<listBytes.length; i++){ ba.writeInt(listBytes[i]); //  ByteArray } var myDecoder:JPEGDecoder = new JPEGDecoder(); //        ByteArray myDecoder.parse(ba); var colorComponents:uint = myDecoder.colorComponents; var numComponents:uint = myDecoder.numComponents; var pixels:Vector.<uint> = myDecoder.pixels; var width:uint = myDecoder.width; var height:uint = myDecoder.height; var bitmap:BitmapData = new BitmapData ( width, height, false ); bitmap.setVector ( bitmap.rect, pixels ); var bmp:Bitmap = new Bitmap(bitmap); var oldW:Number = bmp.width; bmp.width = bmp.width > 500 ? 500 : bmp.width; bmp.height = bmp.height*(bmp.width / oldW); bmp.x = pageX; bmp.y = pageY; stage.addChild(bmp); } exManager.setPreviewCallback = function(pageX:Number, pageY:Number):void{ var sp:Sprite = new Sprite(); sp.graphics.beginFill(0x666666, 0.8); sp.graphics.drawRect(0,0,100,80); sp.x = pageX; sp.y = pageY; stage.addChild(sp); } 


Sources can be downloaded here.

Comment:
This example only works with images with a JPG extension, but it can be easily extended to any other formats.

Because of the wmode: opaque property, which is necessary to display a div on top of it, the scroll doesn't work in the flash drive. If there are solutions I will be glad to hear them.

To run the example you need to place it at least on the local server.

Update:
As suggested, in order to overcome the glitch with the mouseWheel event, you need to add the following to js:

 function wheel(event){ var delta = 0; if (!event) event = window.event; //  IE. //   delta if (event.wheelDelta) { // IE, Opera, safari, chrome -    120 delta = event.wheelDelta/120; } else if (event.detail) { // Mozilla,    3 delta = -event.detail/3; } //    mousewheel if (delta && typeof wheelHandle == 'function') { wheelHandle(delta); //    -   ( ). if (event.preventDefault) event.preventDefault(); event.returnValue = false; //  IE } } function wheelHandle(delta){ if (swfReady){ getSWF("DefaultLauncher").externalMouseWheelHandler(delta); } } function pageInit() { jsReady = true; //   mousewheel if (window.addEventListener) // mozilla, safari, chrome window.addEventListener('DOMMouseScroll', wheel, false); // IE, Opera. window.onmousewheel = document.onmousewheel = wheel; } 


And also add in flash:
 private function externalMouseWheelHandler(delta:int):void { var globalPoint:Point = new Point(stage.mouseX, stage.mouseY); var objects:Array = stage.getObjectsUnderPoint(globalPoint); if (!objects || !objects.length) { return; } var target:DisplayObject = objects[objects.length - 1] as DisplayObject; if (!target) { return; } target = (target is InteractiveObject) ? target : target.parent; if (!target) { return; } var localPoint:Point = target.globalToLocal(globalPoint); var mouseEvent:MouseEvent = new MouseEvent(MouseEvent.MOUSE_WHEEL); mouseEvent.localX = localPoint.x; mouseEvent.localY = localPoint.y; mouseEvent.delta = delta; target.dispatchEvent(mouseEvent); } 


Update 2:
After some experiments, it became clear that it is better to transfer data in chunks, as well as read from the buffer not via getInt32 but through getInt8 , since the length of the file is not necessary to be a multiple of 4, as expected in the first case

Javascript
 function setImage(bufer) { if (swfReady){ var dataview = new DataView(bufer); var byteLength = bufer.byteLength; //    4 var numBytes = 10000; var startPos = 0; var finishPos; var i = 0; while(i < byteLength){ finishPos = ((startPos + numBytes) > byteLength) ? byteLength : startPos + numBytes; var res = []; for (i = startPos; i < finishPos; i++) { res[i - startPos] = dataview.getInt8(i); //  getInt32  getInt8 } startPos = finishPos; getSWF().sendData(res); } getSWF().sendDataFinish(); } } function setPreview(pageX, pageY, fileName) { if (swfReady){ getSWF().sendDataStart(pageX, pageY, fileName); } } 


ActionScript
 _exManager.sendDataStartCb = function(pageX:Number, pageY:Number, fileName:String):void { prevtime = getTimer(); }; _exManager.sendDataCb = function(listBytes:Array):void { for (var i:int = 0; i < listBytes.length; i++) { ba.writeByte(listBytes[i]);//      } }; _exManager.sendDataFinishCb = function():void { loadFromByteArray(ba); ba.clear(); }; 

Source: https://habr.com/ru/post/143728/


All Articles