GoogleEarthEnterpriseImageryProvider.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. import Credit from "../Core/Credit.js";
  2. import decodeGoogleEarthEnterpriseData from "../Core/decodeGoogleEarthEnterpriseData.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import DeveloperError from "../Core/DeveloperError.js";
  6. import Event from "../Core/Event.js";
  7. import GeographicTilingScheme from "../Core/GeographicTilingScheme.js";
  8. import GoogleEarthEnterpriseMetadata from "../Core/GoogleEarthEnterpriseMetadata.js";
  9. import loadImageFromTypedArray from "../Core/loadImageFromTypedArray.js";
  10. import CesiumMath from "../Core/Math.js";
  11. import Rectangle from "../Core/Rectangle.js";
  12. import Request from "../Core/Request.js";
  13. import Resource from "../Core/Resource.js";
  14. import RuntimeError from "../Core/RuntimeError.js";
  15. import TileProviderError from "../Core/TileProviderError.js";
  16. import protobuf from "../ThirdParty/protobufjs.js";
  17. /**
  18. * @private
  19. */
  20. function GoogleEarthEnterpriseDiscardPolicy() {
  21. this._image = new Image();
  22. }
  23. /**
  24. * Determines if the discard policy is ready to process images.
  25. * @returns {Boolean} True if the discard policy is ready to process images; otherwise, false.
  26. */
  27. GoogleEarthEnterpriseDiscardPolicy.prototype.isReady = function () {
  28. return true;
  29. };
  30. /**
  31. * Given a tile image, decide whether to discard that image.
  32. *
  33. * @param {HTMLImageElement} image An image to test.
  34. * @returns {Boolean} True if the image should be discarded; otherwise, false.
  35. */
  36. GoogleEarthEnterpriseDiscardPolicy.prototype.shouldDiscardImage = function (
  37. image
  38. ) {
  39. return image === this._image;
  40. };
  41. /**
  42. * @typedef {Object} GoogleEarthEnterpriseImageryProvider.ConstructorOptions
  43. *
  44. * Initialization options for the GoogleEarthEnterpriseImageryProvider constructor
  45. *
  46. * @property {Resource|String} url The url of the Google Earth Enterprise server hosting the imagery.
  47. * @property {GoogleEarthEnterpriseMetadata} metadata A metadata object that can be used to share metadata requests with a GoogleEarthEnterpriseTerrainProvider.
  48. * @property {Ellipsoid} [ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  49. * @property {TileDiscardPolicy} [tileDiscardPolicy] The policy that determines if a tile
  50. * is invalid and should be discarded. If this value is not specified, a default
  51. * is to discard tiles that fail to download.
  52. * @property {Credit|String} [credit] A credit for the data source, which is displayed on the canvas.
  53. */
  54. /**
  55. * Provides tiled imagery using the Google Earth Enterprise REST API.
  56. *
  57. * Notes: This provider is for use with the 3D Earth API of Google Earth Enterprise,
  58. * {@link GoogleEarthEnterpriseMapsProvider} should be used with 2D Maps API.
  59. *
  60. * @alias GoogleEarthEnterpriseImageryProvider
  61. * @constructor
  62. *
  63. * @param {GoogleEarthEnterpriseImageryProvider.ConstructorOptions} options Object describing initialization options
  64. *
  65. * @see GoogleEarthEnterpriseTerrainProvider
  66. * @see ArcGisMapServerImageryProvider
  67. * @see GoogleEarthEnterpriseMapsProvider
  68. * @see OpenStreetMapImageryProvider
  69. * @see SingleTileImageryProvider
  70. * @see TileMapServiceImageryProvider
  71. * @see WebMapServiceImageryProvider
  72. * @see WebMapTileServiceImageryProvider
  73. * @see UrlTemplateImageryProvider
  74. *
  75. *
  76. * @example
  77. * const geeMetadata = new GoogleEarthEnterpriseMetadata('http://www.earthenterprise.org/3d');
  78. * const gee = new Cesium.GoogleEarthEnterpriseImageryProvider({
  79. * metadata : geeMetadata
  80. * });
  81. *
  82. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  83. */
  84. function GoogleEarthEnterpriseImageryProvider(options) {
  85. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  86. //>>includeStart('debug', pragmas.debug);
  87. if (!(defined(options.url) || defined(options.metadata))) {
  88. throw new DeveloperError("options.url or options.metadata is required.");
  89. }
  90. //>>includeEnd('debug');
  91. /**
  92. * The default alpha blending value of this provider, with 0.0 representing fully transparent and
  93. * 1.0 representing fully opaque.
  94. *
  95. * @type {Number|undefined}
  96. * @default undefined
  97. */
  98. this.defaultAlpha = undefined;
  99. /**
  100. * The default alpha blending value on the night side of the globe of this provider, with 0.0 representing fully transparent and
  101. * 1.0 representing fully opaque.
  102. *
  103. * @type {Number|undefined}
  104. * @default undefined
  105. */
  106. this.defaultNightAlpha = undefined;
  107. /**
  108. * The default alpha blending value on the day side of the globe of this provider, with 0.0 representing fully transparent and
  109. * 1.0 representing fully opaque.
  110. *
  111. * @type {Number|undefined}
  112. * @default undefined
  113. */
  114. this.defaultDayAlpha = undefined;
  115. /**
  116. * The default brightness of this provider. 1.0 uses the unmodified imagery color. Less than 1.0
  117. * makes the imagery darker while greater than 1.0 makes it brighter.
  118. *
  119. * @type {Number|undefined}
  120. * @default undefined
  121. */
  122. this.defaultBrightness = undefined;
  123. /**
  124. * The default contrast of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces
  125. * the contrast while greater than 1.0 increases it.
  126. *
  127. * @type {Number|undefined}
  128. * @default undefined
  129. */
  130. this.defaultContrast = undefined;
  131. /**
  132. * The default hue of this provider in radians. 0.0 uses the unmodified imagery color.
  133. *
  134. * @type {Number|undefined}
  135. * @default undefined
  136. */
  137. this.defaultHue = undefined;
  138. /**
  139. * The default saturation of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces the
  140. * saturation while greater than 1.0 increases it.
  141. *
  142. * @type {Number|undefined}
  143. * @default undefined
  144. */
  145. this.defaultSaturation = undefined;
  146. /**
  147. * The default gamma correction to apply to this provider. 1.0 uses the unmodified imagery color.
  148. *
  149. * @type {Number|undefined}
  150. * @default undefined
  151. */
  152. this.defaultGamma = undefined;
  153. /**
  154. * The default texture minification filter to apply to this provider.
  155. *
  156. * @type {TextureMinificationFilter}
  157. * @default undefined
  158. */
  159. this.defaultMinificationFilter = undefined;
  160. /**
  161. * The default texture magnification filter to apply to this provider.
  162. *
  163. * @type {TextureMagnificationFilter}
  164. * @default undefined
  165. */
  166. this.defaultMagnificationFilter = undefined;
  167. let metadata;
  168. if (defined(options.metadata)) {
  169. metadata = options.metadata;
  170. } else {
  171. const resource = Resource.createIfNeeded(options.url);
  172. metadata = new GoogleEarthEnterpriseMetadata(resource);
  173. }
  174. this._metadata = metadata;
  175. this._tileDiscardPolicy = options.tileDiscardPolicy;
  176. this._tilingScheme = new GeographicTilingScheme({
  177. numberOfLevelZeroTilesX: 2,
  178. numberOfLevelZeroTilesY: 2,
  179. rectangle: new Rectangle(
  180. -CesiumMath.PI,
  181. -CesiumMath.PI,
  182. CesiumMath.PI,
  183. CesiumMath.PI
  184. ),
  185. ellipsoid: options.ellipsoid,
  186. });
  187. let credit = options.credit;
  188. if (typeof credit === "string") {
  189. credit = new Credit(credit);
  190. }
  191. this._credit = credit;
  192. this._tileWidth = 256;
  193. this._tileHeight = 256;
  194. this._maximumLevel = 23;
  195. // Install the default tile discard policy if none has been supplied.
  196. if (!defined(this._tileDiscardPolicy)) {
  197. this._tileDiscardPolicy = new GoogleEarthEnterpriseDiscardPolicy();
  198. }
  199. this._errorEvent = new Event();
  200. this._ready = false;
  201. const that = this;
  202. let metadataError;
  203. this._readyPromise = metadata.readyPromise
  204. .then(function (result) {
  205. if (!metadata.imageryPresent) {
  206. const e = new RuntimeError(
  207. `The server ${metadata.url} doesn't have imagery`
  208. );
  209. metadataError = TileProviderError.handleError(
  210. metadataError,
  211. that,
  212. that._errorEvent,
  213. e.message,
  214. undefined,
  215. undefined,
  216. undefined,
  217. e
  218. );
  219. return Promise.reject(e);
  220. }
  221. TileProviderError.handleSuccess(metadataError);
  222. that._ready = result;
  223. return result;
  224. })
  225. .catch(function (e) {
  226. metadataError = TileProviderError.handleError(
  227. metadataError,
  228. that,
  229. that._errorEvent,
  230. e.message,
  231. undefined,
  232. undefined,
  233. undefined,
  234. e
  235. );
  236. return Promise.reject(e);
  237. });
  238. }
  239. Object.defineProperties(GoogleEarthEnterpriseImageryProvider.prototype, {
  240. /**
  241. * Gets the name of the Google Earth Enterprise server url hosting the imagery.
  242. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  243. * @type {String}
  244. * @readonly
  245. */
  246. url: {
  247. get: function () {
  248. return this._metadata.url;
  249. },
  250. },
  251. /**
  252. * Gets the proxy used by this provider.
  253. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  254. * @type {Proxy}
  255. * @readonly
  256. */
  257. proxy: {
  258. get: function () {
  259. return this._metadata.proxy;
  260. },
  261. },
  262. /**
  263. * Gets the width of each tile, in pixels. This function should
  264. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  265. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  266. * @type {Number}
  267. * @readonly
  268. */
  269. tileWidth: {
  270. get: function () {
  271. //>>includeStart('debug', pragmas.debug);
  272. if (!this._ready) {
  273. throw new DeveloperError(
  274. "tileWidth must not be called before the imagery provider is ready."
  275. );
  276. }
  277. //>>includeEnd('debug');
  278. return this._tileWidth;
  279. },
  280. },
  281. /**
  282. * Gets the height of each tile, in pixels. This function should
  283. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  284. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  285. * @type {Number}
  286. * @readonly
  287. */
  288. tileHeight: {
  289. get: function () {
  290. //>>includeStart('debug', pragmas.debug);
  291. if (!this._ready) {
  292. throw new DeveloperError(
  293. "tileHeight must not be called before the imagery provider is ready."
  294. );
  295. }
  296. //>>includeEnd('debug');
  297. return this._tileHeight;
  298. },
  299. },
  300. /**
  301. * Gets the maximum level-of-detail that can be requested. This function should
  302. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  303. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  304. * @type {Number|undefined}
  305. * @readonly
  306. */
  307. maximumLevel: {
  308. get: function () {
  309. //>>includeStart('debug', pragmas.debug);
  310. if (!this._ready) {
  311. throw new DeveloperError(
  312. "maximumLevel must not be called before the imagery provider is ready."
  313. );
  314. }
  315. //>>includeEnd('debug');
  316. return this._maximumLevel;
  317. },
  318. },
  319. /**
  320. * Gets the minimum level-of-detail that can be requested. This function should
  321. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  322. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  323. * @type {Number}
  324. * @readonly
  325. */
  326. minimumLevel: {
  327. get: function () {
  328. //>>includeStart('debug', pragmas.debug);
  329. if (!this._ready) {
  330. throw new DeveloperError(
  331. "minimumLevel must not be called before the imagery provider is ready."
  332. );
  333. }
  334. //>>includeEnd('debug');
  335. return 0;
  336. },
  337. },
  338. /**
  339. * Gets the tiling scheme used by this provider. This function should
  340. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  341. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  342. * @type {TilingScheme}
  343. * @readonly
  344. */
  345. tilingScheme: {
  346. get: function () {
  347. //>>includeStart('debug', pragmas.debug);
  348. if (!this._ready) {
  349. throw new DeveloperError(
  350. "tilingScheme must not be called before the imagery provider is ready."
  351. );
  352. }
  353. //>>includeEnd('debug');
  354. return this._tilingScheme;
  355. },
  356. },
  357. /**
  358. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  359. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  360. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  361. * @type {Rectangle}
  362. * @readonly
  363. */
  364. rectangle: {
  365. get: function () {
  366. //>>includeStart('debug', pragmas.debug);
  367. if (!this._ready) {
  368. throw new DeveloperError(
  369. "rectangle must not be called before the imagery provider is ready."
  370. );
  371. }
  372. //>>includeEnd('debug');
  373. return this._tilingScheme.rectangle;
  374. },
  375. },
  376. /**
  377. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  378. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  379. * returns undefined, no tiles are filtered. This function should
  380. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  381. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  382. * @type {TileDiscardPolicy}
  383. * @readonly
  384. */
  385. tileDiscardPolicy: {
  386. get: function () {
  387. //>>includeStart('debug', pragmas.debug);
  388. if (!this._ready) {
  389. throw new DeveloperError(
  390. "tileDiscardPolicy must not be called before the imagery provider is ready."
  391. );
  392. }
  393. //>>includeEnd('debug');
  394. return this._tileDiscardPolicy;
  395. },
  396. },
  397. /**
  398. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  399. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  400. * are passed an instance of {@link TileProviderError}.
  401. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  402. * @type {Event}
  403. * @readonly
  404. */
  405. errorEvent: {
  406. get: function () {
  407. return this._errorEvent;
  408. },
  409. },
  410. /**
  411. * Gets a value indicating whether or not the provider is ready for use.
  412. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  413. * @type {Boolean}
  414. * @readonly
  415. */
  416. ready: {
  417. get: function () {
  418. return this._ready;
  419. },
  420. },
  421. /**
  422. * Gets a promise that resolves to true when the provider is ready for use.
  423. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  424. * @type {Promise.<Boolean>}
  425. * @readonly
  426. */
  427. readyPromise: {
  428. get: function () {
  429. return this._readyPromise;
  430. },
  431. },
  432. /**
  433. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  434. * the source of the imagery. This function should not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  435. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  436. * @type {Credit}
  437. * @readonly
  438. */
  439. credit: {
  440. get: function () {
  441. return this._credit;
  442. },
  443. },
  444. /**
  445. * Gets a value indicating whether or not the images provided by this imagery provider
  446. * include an alpha channel. If this property is false, an alpha channel, if present, will
  447. * be ignored. If this property is true, any images without an alpha channel will be treated
  448. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  449. * and texture upload time.
  450. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  451. * @type {Boolean}
  452. * @readonly
  453. */
  454. hasAlphaChannel: {
  455. get: function () {
  456. return false;
  457. },
  458. },
  459. });
  460. /**
  461. * Gets the credits to be displayed when a given tile is displayed.
  462. *
  463. * @param {Number} x The tile X coordinate.
  464. * @param {Number} y The tile Y coordinate.
  465. * @param {Number} level The tile level;
  466. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  467. *
  468. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  469. */
  470. GoogleEarthEnterpriseImageryProvider.prototype.getTileCredits = function (
  471. x,
  472. y,
  473. level
  474. ) {
  475. //>>includeStart('debug', pragmas.debug);
  476. if (!this._ready) {
  477. throw new DeveloperError(
  478. "getTileCredits must not be called before the imagery provider is ready."
  479. );
  480. }
  481. //>>includeEnd('debug');
  482. const metadata = this._metadata;
  483. const info = metadata.getTileInformation(x, y, level);
  484. if (defined(info)) {
  485. const credit = metadata.providers[info.imageryProvider];
  486. if (defined(credit)) {
  487. return [credit];
  488. }
  489. }
  490. return undefined;
  491. };
  492. /**
  493. * Requests the image for a given tile. This function should
  494. * not be called before {@link GoogleEarthEnterpriseImageryProvider#ready} returns true.
  495. *
  496. * @param {Number} x The tile X coordinate.
  497. * @param {Number} y The tile Y coordinate.
  498. * @param {Number} level The tile level.
  499. * @param {Request} [request] The request object. Intended for internal use only.
  500. * @returns {Promise.<ImageryTypes>|undefined} A promise for the image that will resolve when the image is available, or
  501. * undefined if there are too many active requests to the server, and the request should be retried later.
  502. *
  503. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  504. */
  505. GoogleEarthEnterpriseImageryProvider.prototype.requestImage = function (
  506. x,
  507. y,
  508. level,
  509. request
  510. ) {
  511. //>>includeStart('debug', pragmas.debug);
  512. if (!this._ready) {
  513. throw new DeveloperError(
  514. "requestImage must not be called before the imagery provider is ready."
  515. );
  516. }
  517. //>>includeEnd('debug');
  518. const invalidImage = this._tileDiscardPolicy._image; // Empty image or undefined depending on discard policy
  519. const metadata = this._metadata;
  520. const quadKey = GoogleEarthEnterpriseMetadata.tileXYToQuadKey(x, y, level);
  521. const info = metadata.getTileInformation(x, y, level);
  522. if (!defined(info)) {
  523. if (metadata.isValid(quadKey)) {
  524. const metadataRequest = new Request({
  525. throttle: request.throttle,
  526. throttleByServer: request.throttleByServer,
  527. type: request.type,
  528. priorityFunction: request.priorityFunction,
  529. });
  530. metadata.populateSubtree(x, y, level, metadataRequest);
  531. return undefined; // No metadata so return undefined so we can be loaded later
  532. }
  533. return Promise.resolve(invalidImage); // Image doesn't exist
  534. }
  535. if (!info.hasImagery()) {
  536. // Already have info and there isn't any imagery here
  537. return Promise.resolve(invalidImage);
  538. }
  539. const promise = buildImageResource(
  540. this,
  541. info,
  542. x,
  543. y,
  544. level,
  545. request
  546. ).fetchArrayBuffer();
  547. if (!defined(promise)) {
  548. return undefined; // Throttled
  549. }
  550. return promise.then(function (image) {
  551. decodeGoogleEarthEnterpriseData(metadata.key, image);
  552. let a = new Uint8Array(image);
  553. let type;
  554. const protoImagery = metadata.protoImagery;
  555. if (!defined(protoImagery) || !protoImagery) {
  556. type = getImageType(a);
  557. }
  558. if (!defined(type) && (!defined(protoImagery) || protoImagery)) {
  559. const message = decodeEarthImageryPacket(a);
  560. type = message.imageType;
  561. a = message.imageData;
  562. }
  563. if (!defined(type) || !defined(a)) {
  564. return invalidImage;
  565. }
  566. return loadImageFromTypedArray({
  567. uint8Array: a,
  568. format: type,
  569. flipY: true,
  570. });
  571. });
  572. };
  573. /**
  574. * Picking features is not currently supported by this imagery provider, so this function simply returns
  575. * undefined.
  576. *
  577. * @param {Number} x The tile X coordinate.
  578. * @param {Number} y The tile Y coordinate.
  579. * @param {Number} level The tile level.
  580. * @param {Number} longitude The longitude at which to pick features.
  581. * @param {Number} latitude The latitude at which to pick features.
  582. * @return {undefined} Undefined since picking is not supported.
  583. */
  584. GoogleEarthEnterpriseImageryProvider.prototype.pickFeatures = function (
  585. x,
  586. y,
  587. level,
  588. longitude,
  589. latitude
  590. ) {
  591. return undefined;
  592. };
  593. //
  594. // Functions to handle imagery packets
  595. //
  596. function buildImageResource(imageryProvider, info, x, y, level, request) {
  597. const quadKey = GoogleEarthEnterpriseMetadata.tileXYToQuadKey(x, y, level);
  598. let version = info.imageryVersion;
  599. version = defined(version) && version > 0 ? version : 1;
  600. return imageryProvider._metadata.resource.getDerivedResource({
  601. url: `flatfile?f1-0${quadKey}-i.${version.toString()}`,
  602. request: request,
  603. });
  604. }
  605. // Detects if a Uint8Array is a JPEG or PNG
  606. function getImageType(image) {
  607. const jpeg = "JFIF";
  608. if (
  609. image[6] === jpeg.charCodeAt(0) &&
  610. image[7] === jpeg.charCodeAt(1) &&
  611. image[8] === jpeg.charCodeAt(2) &&
  612. image[9] === jpeg.charCodeAt(3)
  613. ) {
  614. return "image/jpeg";
  615. }
  616. const png = "PNG";
  617. if (
  618. image[1] === png.charCodeAt(0) &&
  619. image[2] === png.charCodeAt(1) &&
  620. image[3] === png.charCodeAt(2)
  621. ) {
  622. return "image/png";
  623. }
  624. return undefined;
  625. }
  626. // Decodes an Imagery protobuf into the message
  627. // Partially generated with the help of protobuf.js static generator
  628. function decodeEarthImageryPacket(data) {
  629. const reader = protobuf.Reader.create(data);
  630. const end = reader.len;
  631. const message = {};
  632. while (reader.pos < end) {
  633. const tag = reader.uint32();
  634. let copyrightIds;
  635. switch (tag >>> 3) {
  636. case 1:
  637. message.imageType = reader.uint32();
  638. break;
  639. case 2:
  640. message.imageData = reader.bytes();
  641. break;
  642. case 3:
  643. message.alphaType = reader.uint32();
  644. break;
  645. case 4:
  646. message.imageAlpha = reader.bytes();
  647. break;
  648. case 5:
  649. copyrightIds = message.copyrightIds;
  650. if (!defined(copyrightIds)) {
  651. copyrightIds = message.copyrightIds = [];
  652. }
  653. if ((tag & 7) === 2) {
  654. const end2 = reader.uint32() + reader.pos;
  655. while (reader.pos < end2) {
  656. copyrightIds.push(reader.uint32());
  657. }
  658. } else {
  659. copyrightIds.push(reader.uint32());
  660. }
  661. break;
  662. default:
  663. reader.skipType(tag & 7);
  664. break;
  665. }
  666. }
  667. const imageType = message.imageType;
  668. if (defined(imageType)) {
  669. switch (imageType) {
  670. case 0:
  671. message.imageType = "image/jpeg";
  672. break;
  673. case 4:
  674. message.imageType = "image/png";
  675. break;
  676. default:
  677. throw new RuntimeError(
  678. "GoogleEarthEnterpriseImageryProvider: Unsupported image type."
  679. );
  680. }
  681. }
  682. const alphaType = message.alphaType;
  683. if (defined(alphaType) && alphaType !== 0) {
  684. console.log(
  685. "GoogleEarthEnterpriseImageryProvider: External alpha not supported."
  686. );
  687. delete message.alphaType;
  688. delete message.imageAlpha;
  689. }
  690. return message;
  691. }
  692. export default GoogleEarthEnterpriseImageryProvider;