Speed up Image loadFromBytes (thanks D-MAN)
This commit is contained in:
@@ -2,13 +2,16 @@ package lime._internal.backend.html5;
|
|||||||
|
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
import js.html.AnchorElement;
|
import js.html.AnchorElement;
|
||||||
|
import js.html.Blob;
|
||||||
import js.html.ErrorEvent;
|
import js.html.ErrorEvent;
|
||||||
import js.html.Event;
|
import js.html.Event;
|
||||||
import js.html.Image as JSImage;
|
import js.html.Image as JSImage;
|
||||||
import js.html.ProgressEvent;
|
import js.html.ProgressEvent;
|
||||||
|
import js.html.URL;
|
||||||
import js.html.XMLHttpRequest;
|
import js.html.XMLHttpRequest;
|
||||||
import js.html.XMLHttpRequestResponseType;
|
import js.html.XMLHttpRequestResponseType;
|
||||||
import js.Browser;
|
import js.Browser;
|
||||||
|
import lime._internal.format.Base64;
|
||||||
import lime.app.Future;
|
import lime.app.Future;
|
||||||
import lime.app.Promise;
|
import lime.app.Promise;
|
||||||
import lime.graphics.Image;
|
import lime.graphics.Image;
|
||||||
@@ -21,6 +24,8 @@ import lime.utils.AssetType;
|
|||||||
@:access(lime.graphics.Image)
|
@:access(lime.graphics.Image)
|
||||||
class HTML5HTTPRequest
|
class HTML5HTTPRequest
|
||||||
{
|
{
|
||||||
|
private static inline var OPTION_REVOKE_URL:Int = 1 << 0;
|
||||||
|
|
||||||
private static var activeRequests = 0;
|
private static var activeRequests = 0;
|
||||||
private static var originElement:AnchorElement;
|
private static var originElement:AnchorElement;
|
||||||
private static var originHostname:String;
|
private static var originHostname:String;
|
||||||
@@ -172,7 +177,8 @@ class HTML5HTTPRequest
|
|||||||
instance: this,
|
instance: this,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
promise: promise,
|
promise: promise,
|
||||||
type: AssetType.BINARY
|
type: AssetType.BINARY,
|
||||||
|
options: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +192,7 @@ class HTML5HTTPRequest
|
|||||||
if (activeRequests < requestLimit)
|
if (activeRequests < requestLimit)
|
||||||
{
|
{
|
||||||
activeRequests++;
|
activeRequests++;
|
||||||
__loadImage(uri, promise);
|
__loadImage(uri, promise, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -195,13 +201,46 @@ class HTML5HTTPRequest
|
|||||||
instance: null,
|
instance: null,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
promise: promise,
|
promise: promise,
|
||||||
type: AssetType.IMAGE
|
type: AssetType.IMAGE,
|
||||||
|
options: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.future;
|
return promise.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function loadImageFromBytes(bytes:Bytes, type:String):Future<Image>
|
||||||
|
{
|
||||||
|
var uri = __createBlobURIFromBytes(bytes, type);
|
||||||
|
if (uri != null)
|
||||||
|
{
|
||||||
|
var promise = new Promise<Image>();
|
||||||
|
|
||||||
|
if (activeRequests < requestLimit)
|
||||||
|
{
|
||||||
|
activeRequests++;
|
||||||
|
__loadImage(uri, promise, OPTION_REVOKE_URL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
requestQueue.add(
|
||||||
|
{
|
||||||
|
instance: null,
|
||||||
|
uri: uri,
|
||||||
|
promise: promise,
|
||||||
|
type: AssetType.IMAGE,
|
||||||
|
options: OPTION_REVOKE_URL
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.future;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return loadImage("data:" + type + ";base64," + Base64.encode(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function loadText(uri:String):Future<String>
|
public function loadText(uri:String):Future<String>
|
||||||
{
|
{
|
||||||
var promise = new Promise<String>();
|
var promise = new Promise<String>();
|
||||||
@@ -218,7 +257,8 @@ class HTML5HTTPRequest
|
|||||||
instance: this,
|
instance: this,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
promise: promise,
|
promise: promise,
|
||||||
type: AssetType.TEXT
|
type: AssetType.TEXT,
|
||||||
|
options: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +276,7 @@ class HTML5HTTPRequest
|
|||||||
switch (queueItem.type)
|
switch (queueItem.type)
|
||||||
{
|
{
|
||||||
case IMAGE:
|
case IMAGE:
|
||||||
__loadImage(queueItem.uri, queueItem.promise);
|
__loadImage(queueItem.uri, queueItem.promise, queueItem.options);
|
||||||
|
|
||||||
case TEXT:
|
case TEXT:
|
||||||
queueItem.instance.__loadText(queueItem.uri, queueItem.promise);
|
queueItem.instance.__loadText(queueItem.uri, queueItem.promise);
|
||||||
@@ -272,6 +312,11 @@ class HTML5HTTPRequest
|
|||||||
parent.responseStatus = request.status;
|
parent.responseStatus = request.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static inline function __createBlobURIFromBytes(bytes:Bytes, type:String):String
|
||||||
|
{
|
||||||
|
return URL.createObjectURL(new Blob([bytes.getData()], {type: type}));
|
||||||
|
}
|
||||||
|
|
||||||
private static function __fixHostname(hostname:String):String
|
private static function __fixHostname(hostname:String):String
|
||||||
{
|
{
|
||||||
return hostname == null ? "" : hostname;
|
return hostname == null ? "" : hostname;
|
||||||
@@ -301,10 +346,15 @@ class HTML5HTTPRequest
|
|||||||
return (protocol == null || protocol == "") ? "http:" : protocol;
|
return (protocol == null || protocol == "") ? "http:" : protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function __isInMemoryURI(uri:String):Bool
|
||||||
|
{
|
||||||
|
return StringTools.startsWith(uri, "data:") || StringTools.startsWith(uri, "blob:");
|
||||||
|
}
|
||||||
|
|
||||||
private static function __isSameOrigin(path:String):Bool
|
private static function __isSameOrigin(path:String):Bool
|
||||||
{
|
{
|
||||||
if (path == null || path == "") return true;
|
if (path == null || path == "") return true;
|
||||||
if (StringTools.startsWith(path, "data:")) return true;
|
if (__isInMemoryURI(path)) return true;
|
||||||
|
|
||||||
if (originElement == null)
|
if (originElement == null)
|
||||||
{
|
{
|
||||||
@@ -380,7 +430,7 @@ class HTML5HTTPRequest
|
|||||||
load(uri, progress, readyStateChange);
|
load(uri, progress, readyStateChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function __loadImage(uri:String, promise:Promise<Image>):Void
|
private static function __loadImage(uri:String, promise:Promise<Image>, options:Int):Void
|
||||||
{
|
{
|
||||||
var image = new JSImage();
|
var image = new JSImage();
|
||||||
|
|
||||||
@@ -394,10 +444,11 @@ class HTML5HTTPRequest
|
|||||||
supportsImageProgress = untyped __js__("'onprogress' in image");
|
supportsImageProgress = untyped __js__("'onprogress' in image");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportsImageProgress || StringTools.startsWith(uri, "data:"))
|
if (supportsImageProgress || __isInMemoryURI(uri))
|
||||||
{
|
{
|
||||||
image.addEventListener("load", function(event)
|
image.addEventListener("load", function(event)
|
||||||
{
|
{
|
||||||
|
__revokeBlobURI(uri, options);
|
||||||
var buffer = new ImageBuffer(null, image.width, image.height);
|
var buffer = new ImageBuffer(null, image.width, image.height);
|
||||||
buffer.__srcImage = cast image;
|
buffer.__srcImage = cast image;
|
||||||
|
|
||||||
@@ -414,6 +465,8 @@ class HTML5HTTPRequest
|
|||||||
|
|
||||||
image.addEventListener("error", function(event)
|
image.addEventListener("error", function(event)
|
||||||
{
|
{
|
||||||
|
__revokeBlobURI(uri, options);
|
||||||
|
|
||||||
activeRequests--;
|
activeRequests--;
|
||||||
processQueue();
|
processQueue();
|
||||||
|
|
||||||
@@ -489,6 +542,14 @@ class HTML5HTTPRequest
|
|||||||
binary = false;
|
binary = false;
|
||||||
load(uri, progress, readyStateChange);
|
load(uri, progress, readyStateChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function __revokeBlobURI(uri:String, options:Int):Void
|
||||||
|
{
|
||||||
|
if ((options & OPTION_REVOKE_URL) != 0)
|
||||||
|
{
|
||||||
|
URL.revokeObjectURL(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:dox(hide) typedef QueueItem =
|
@:dox(hide) typedef QueueItem =
|
||||||
@@ -497,4 +558,5 @@ class HTML5HTTPRequest
|
|||||||
var type:AssetType;
|
var type:AssetType;
|
||||||
var promise:Dynamic;
|
var promise:Dynamic;
|
||||||
var uri:String;
|
var uri:String;
|
||||||
|
var options:Int;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,7 +387,8 @@ class Image
|
|||||||
sourceRect.offset(sourceImage.offsetX, sourceImage.offsetY);
|
sourceRect.offset(sourceImage.offsetX, sourceImage.offsetY);
|
||||||
destPoint.offset(offsetX, offsetY);
|
destPoint.offset(offsetX, offsetY);
|
||||||
|
|
||||||
buffer.__srcBitmapData.copyChannel(sourceImage.buffer.src, sourceRect.__toFlashRectangle(), destPoint.__toFlashPoint(), srcChannel, dstChannel);
|
buffer.__srcBitmapData.copyChannel(sourceImage.buffer.src, sourceRect.__toFlashRectangle(), destPoint.__toFlashPoint(), srcChannel,
|
||||||
|
dstChannel);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@@ -616,20 +617,16 @@ class Image
|
|||||||
@param bitmapData A source `bitmapData` to use
|
@param bitmapData A source `bitmapData` to use
|
||||||
@return A new `Image` instance
|
@return A new `Image` instance
|
||||||
**/
|
**/
|
||||||
#if flash
|
public static function fromBitmapData(bitmapData:#if flash BitmapData #else Dynamic #end):Image
|
||||||
public static function fromBitmapData(bitmapData:BitmapData):Image {
|
{
|
||||||
#else
|
if (bitmapData == null) return null;
|
||||||
public static function fromBitmapData(bitmapData:Dynamic):Image {
|
#if flash
|
||||||
#end
|
var buffer = new ImageBuffer(null, bitmapData.width, bitmapData.height);
|
||||||
if (bitmapData == null) return null;
|
buffer.__srcBitmapData = bitmapData;
|
||||||
#if flash
|
return new Image(buffer);
|
||||||
var buffer = new ImageBuffer(null, bitmapData.width, bitmapData.height);
|
#else
|
||||||
|
return bitmapData.image;
|
||||||
buffer.__srcBitmapData = bitmapData;
|
#end
|
||||||
return new Image(buffer);
|
|
||||||
#else
|
|
||||||
return bitmapData.image;
|
|
||||||
#end
|
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
@@ -664,18 +661,15 @@ class Image
|
|||||||
@param canvas A `CanvasElement`
|
@param canvas A `CanvasElement`
|
||||||
@return A new `Image` instance
|
@return A new `Image` instance
|
||||||
**/
|
**/
|
||||||
#if (js && html5)
|
public static function fromCanvas(canvas:#if (js && html5) CanvasElement #else Dynamic #end):Image
|
||||||
public static function fromCanvas(canvas:CanvasElement):Image {
|
{
|
||||||
#else
|
if (canvas == null) return null;
|
||||||
public static function fromCanvas(canvas:Dynamic):Image {
|
var buffer = new ImageBuffer(null, canvas.width, canvas.height);
|
||||||
#end
|
buffer.src = canvas;
|
||||||
if (canvas == null) return null;
|
var image = new Image(buffer);
|
||||||
var buffer = new ImageBuffer(null, canvas.width, canvas.height);
|
|
||||||
buffer.src = canvas;
|
|
||||||
var image = new Image(buffer);
|
|
||||||
|
|
||||||
image.type = CANVAS;
|
image.type = CANVAS;
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
@@ -710,18 +704,15 @@ class Image
|
|||||||
@param image An `ImageElement` instance
|
@param image An `ImageElement` instance
|
||||||
@return A new `Image` instance
|
@return A new `Image` instance
|
||||||
**/
|
**/
|
||||||
#if (js && html5)
|
public static function fromImageElement(image:#if (js && html5) ImageElement #else Dynamic #end):Image
|
||||||
public static function fromImageElement(image:ImageElement):Image {
|
{
|
||||||
#else
|
if (image == null) return null;
|
||||||
public static function fromImageElement(image:Dynamic):Image {
|
var buffer = new ImageBuffer(null, image.width, image.height);
|
||||||
#end
|
buffer.src = image;
|
||||||
if (image == null) return null;
|
var _image = new Image(buffer);
|
||||||
var buffer = new ImageBuffer(null, image.width, image.height);
|
|
||||||
buffer.src = image;
|
|
||||||
var _image = new Image(buffer);
|
|
||||||
|
|
||||||
_image.type = CANVAS;
|
_image.type = CANVAS;
|
||||||
return _image;
|
return _image;
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
@@ -967,8 +958,11 @@ class Image
|
|||||||
// throw "Image tried to read PNG/JPG Bytes, but found an invalid header.";
|
// throw "Image tried to read PNG/JPG Bytes, but found an invalid header.";
|
||||||
return Future.withValue(null);
|
return Future.withValue(null);
|
||||||
}
|
}
|
||||||
|
#if !display
|
||||||
|
return HTML5HTTPRequest.loadImageFromBytes(bytes, type);
|
||||||
|
#else
|
||||||
return loadFromBase64(Base64.encode(bytes), type);
|
return loadFromBase64(Base64.encode(bytes), type);
|
||||||
|
#end
|
||||||
#elseif flash
|
#elseif flash
|
||||||
var promise = new Promise<Image>();
|
var promise = new Promise<Image>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user