Skip to content

Commit b772d52

Browse files
author
Shehata
committed
Use image bitmap and flip during fetch
1 parent 96cbc18 commit b772d52

File tree

5 files changed

+107
-22
lines changed

5 files changed

+107
-22
lines changed

Source/Core/Resource.js

+66-18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ define([
1111
'./deprecationWarning',
1212
'./DeveloperError',
1313
'./freezeObject',
14+
'./FeatureDetection',
1415
'./getAbsoluteUri',
1516
'./getBaseUri',
1617
'./getExtensionFromUri',
@@ -39,6 +40,7 @@ define([
3940
deprecationWarning,
4041
DeveloperError,
4142
freezeObject,
43+
FeatureDetection,
4244
getAbsoluteUri,
4345
getBaseUri,
4446
getExtensionFromUri,
@@ -250,6 +252,7 @@ define([
250252
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
251253
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
252254
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
255+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
253256
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
254257
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
255258
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -336,6 +339,14 @@ define([
336339
this.retryAttempts = defaultValue(options.retryAttempts, 0);
337340
this._retryCount = 0;
338341

342+
/**
343+
* Whether to vertically flip the image during fetch and decode. Only applies when requesting
344+
* an image and the browser supports createImageBitmap.
345+
*
346+
* @type {Boolean}
347+
*/
348+
this.flipImage = defaultValue(options.flipImage, true);
349+
339350
var uri = new Uri(options.url);
340351
parseQuery(uri, this, true, true);
341352

@@ -620,6 +631,7 @@ define([
620631
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}). These will be combined with those of the current instance.
621632
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
622633
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
634+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
623635
* @param {Resource~RetryCallback} [options.retryCallback] The function to call when loading the resource fails.
624636
* @param {Number} [options.retryAttempts] The number of times the retryCallback should be called before giving up.
625637
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -664,6 +676,9 @@ define([
664676
if (defined(options.retryAttempts)) {
665677
resource.retryAttempts = options.retryAttempts;
666678
}
679+
if (defined(options.flipImage)) {
680+
resource.flipImage = options.flipImage;
681+
}
667682

668683
return resource;
669684
};
@@ -714,6 +729,7 @@ define([
714729
result.retryCallback = this.retryCallback;
715730
result.retryAttempts = this.retryAttempts;
716731
result._retryCount = 0;
732+
result.flipImage = this.flipImage;
717733
result.request = this.request.clone();
718734

719735
return result;
@@ -771,6 +787,7 @@ define([
771787
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
772788
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
773789
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
790+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
774791
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
775792
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
776793
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -815,6 +832,7 @@ define([
815832
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
816833
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
817834
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
835+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
818836
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
819837
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
820838
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -851,6 +869,7 @@ define([
851869
*/
852870
Resource.prototype.fetchImage = function (preferBlob) {
853871
preferBlob = defaultValue(preferBlob, false);
872+
var flipImage = this.flipImage;
854873

855874
checkAndResetRequest(this.request);
856875

@@ -860,7 +879,7 @@ define([
860879
// 3. It's a blob URI
861880
// 4. It doesn't have request headers and we preferBlob is false
862881
if (!xhrBlobSupported || this.isDataUri || this.isBlobUri || (!this.hasHeaders && !preferBlob)) {
863-
return fetchImage(this, true);
882+
return fetchImage(this);
864883
}
865884

866885
var blobPromise = this.fetchBlob();
@@ -878,7 +897,8 @@ define([
878897
generatedBlob = blob;
879898
var blobUrl = window.URL.createObjectURL(blob);
880899
generatedBlobResource = new Resource({
881-
url: blobUrl
900+
url: blobUrl,
901+
flipImage: flipImage
882902
});
883903

884904
return fetchImage(generatedBlobResource);
@@ -908,6 +928,7 @@ define([
908928
request.url = resource.url;
909929
request.requestFunction = function() {
910930
var url = resource.url;
931+
var flipImage = resource.flipImage;
911932
var crossOrigin = false;
912933

913934
// data URIs can't have crossorigin set.
@@ -917,7 +938,7 @@ define([
917938

918939
var deferred = when.defer();
919940

920-
Resource._Implementations.createImage(url, crossOrigin, deferred);
941+
Resource._Implementations.createImage(url, crossOrigin, deferred, flipImage);
921942

922943
return deferred.promise;
923944
};
@@ -958,6 +979,7 @@ define([
958979
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
959980
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
960981
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
982+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
961983
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
962984
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
963985
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -1378,6 +1400,7 @@ define([
13781400
* @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}).
13791401
* @param {Object} [options.headers={}] Additional HTTP headers that will be sent.
13801402
* @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource.
1403+
* @param {Boolean} [options.flipImage] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap.
13811404
* @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried.
13821405
* @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up.
13831406
* @param {Request} [options.request] A Request object that will be used. Intended for internal use only.
@@ -1755,26 +1778,51 @@ define([
17551778
*/
17561779
Resource._Implementations = {};
17571780

1758-
Resource._Implementations.createImage = function(url, crossOrigin, deferred) {
1759-
var image = new Image();
1781+
Resource._Implementations.createImage = function(url, crossOrigin, deferred, flipImage) {
1782+
var supportsBitmapOptions = FeatureDetection.supportsImageBitmapOptionsSync();
17601783

1761-
image.onload = function() {
1762-
deferred.resolve(image);
1763-
};
1784+
if (FeatureDetection.supportsFetchApi() && FeatureDetection.supportsCreateImageBitmap() && defined(supportsBitmapOptions)) {
1785+
fetch(url, {
1786+
credentials: (crossOrigin && TrustedServers.contains(url)) ? 'include' : 'same-origin'
1787+
})
1788+
.then(function(response) {
1789+
// Catch error here https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
1790+
return response.blob();
1791+
})
1792+
.then(function(blob) {
1793+
if (!supportsBitmapOptions) {
1794+
return createImageBitmap(blob);
1795+
}
17641796

1765-
image.onerror = function(e) {
1766-
deferred.reject(e);
1767-
};
1797+
return createImageBitmap(blob, {
1798+
imageOrientation: flipImage ? 'flipY' : 'none'
1799+
});
1800+
})
1801+
.then(function (imageBitmap) {
1802+
deferred.resolve(imageBitmap);
1803+
})
1804+
.catch(deferred.reject);
1805+
} else {
1806+
var image = new Image();
17681807

1769-
if (crossOrigin) {
1770-
if (TrustedServers.contains(url)) {
1771-
image.crossOrigin = 'use-credentials';
1772-
} else {
1773-
image.crossOrigin = '';
1808+
image.onload = function() {
1809+
deferred.resolve(image);
1810+
};
1811+
1812+
image.onerror = function(e) {
1813+
deferred.reject(e);
1814+
};
1815+
1816+
if (crossOrigin) {
1817+
if (TrustedServers.contains(url)) {
1818+
image.crossOrigin = 'use-credentials';
1819+
} else {
1820+
image.crossOrigin = '';
1821+
}
17741822
}
1775-
}
17761823

1777-
image.src = url;
1824+
image.src = url;
1825+
}
17781826
};
17791827

17801828
function decodeResponse(loadWithHttpResponse, responseType) {

Source/Core/loadImageFromTypedArray.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
11
define([
22
'../ThirdParty/when',
33
'./Check',
4+
'./defined',
5+
'./defaultValue',
6+
'./FeatureDetection',
47
'./Resource'
58
], function(
69
when,
710
Check,
11+
defined,
12+
defaultValue,
13+
FeatureDetection,
814
Resource) {
915
'use strict';
1016

1117
/**
1218
* @private
1319
*/
14-
function loadImageFromTypedArray(uint8Array, format, request) {
20+
function loadImageFromTypedArray(options) {
21+
var uint8Array = options.uint8Array;
22+
var format = options.format;
23+
var request = options.request;
24+
var flipY = defaultValue(options.flipY, true);
1525
//>>includeStart('debug', pragmas.debug);
1626
Check.typeOf.object('uint8Array', uint8Array);
1727
Check.typeOf.string('format', format);
@@ -21,6 +31,19 @@ define([
2131
type : format
2232
});
2333

34+
// We can avoid the extra fetch when createImageBitmap is supported.
35+
var supportsBitmapOptions = FeatureDetection.supportsImageBitmapOptionsSync();
36+
37+
if (FeatureDetection.supportsCreateImageBitmap() && defined(supportsBitmapOptions)) {
38+
if (supportsBitmapOptions) {
39+
return when(createImageBitmap(blob, {
40+
imageOrientation: flipY ? 'flipY' : 'none'
41+
}));
42+
}
43+
44+
return when(createImageBitmap(blob));
45+
}
46+
2447
var blobUrl = window.URL.createObjectURL(blob);
2548
var resource = new Resource({
2649
url: blobUrl,

Source/Scene/GoogleEarthEnterpriseImageryProvider.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,10 @@ define([
488488
return invalidImage;
489489
}
490490

491-
return loadImageFromTypedArray(a, type);
491+
return loadImageFromTypedArray({
492+
uint8Array: a,
493+
format: type
494+
});
492495
});
493496
};
494497

Source/Scene/Model.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,8 @@ define([
17141714
++model._loadResources.pendingTextureLoads;
17151715

17161716
var imageResource = model._resource.getDerivedResource({
1717-
url : uri
1717+
url : uri,
1718+
flipImage : false
17181719
});
17191720

17201721
var promise;
@@ -2325,7 +2326,11 @@ define([
23252326
++model._loadResources.pendingTextureLoads;
23262327
} else {
23272328
var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
2328-
loadImageFromTypedArray(loadResources.getBuffer(bufferView), gltfTexture.mimeType)
2329+
loadImageFromTypedArray({
2330+
uint8Array: loadResources.getBuffer(bufferView),
2331+
format: gltfTexture.mimeType,
2332+
flipY: false
2333+
})
23292334
.then(onload).otherwise(onerror);
23302335
++loadResources.pendingBufferViewToImage;
23312336
}

Source/Widgets/Viewer/Viewer.js

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ define([
1010
'../../Core/DeveloperError',
1111
'../../Core/Event',
1212
'../../Core/EventHelper',
13+
'../../Core/FeatureDetection',
1314
'../../Core/HeadingPitchRange',
1415
'../../Core/isArray',
1516
'../../Core/Matrix4',
@@ -60,6 +61,7 @@ define([
6061
DeveloperError,
6162
Event,
6263
EventHelper,
64+
FeatureDetection,
6365
HeadingPitchRange,
6466
isArray,
6567
Matrix4,
@@ -361,6 +363,10 @@ define([
361363
}
362364
//>>includeEnd('debug');
363365

366+
// We kick off this asynchronous test here so we can start using
367+
// createImageBitmap if it's supported as soon as possible.
368+
FeatureDetection.supportsImageBitmapOptions();
369+
364370
container = getElement(container);
365371
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
366372

0 commit comments

Comments
 (0)