maplibre-gl 3.4.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +238 -58
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +4 -3
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +9 -9
- package/src/render/glyph_manager.test.ts +10 -9
- package/src/render/glyph_manager.ts +17 -10
- package/src/source/raster_dem_tile_source.ts +21 -9
- package/src/source/raster_dem_tile_worker_source.ts +7 -24
- package/src/style/style.ts +3 -0
- package/src/style/style_glyph.ts +4 -3
- package/src/symbol/quads.ts +4 -2
- package/src/ui/map.test.ts +17 -0
- package/src/util/offscreen_canvas_distorted.test.ts +13 -0
- package/src/util/offscreen_canvas_distorted.ts +39 -0
- package/src/util/util.test.ts +171 -1
- package/src/util/util.ts +150 -0
package/src/util/util.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Point from '@mapbox/point-geometry';
|
|
2
2
|
import UnitBezier from '@mapbox/unitbezier';
|
|
3
3
|
import type {Callback} from '../types/callback';
|
|
4
|
+
import {isOffscreenCanvasDistorted} from './offscreen_canvas_distorted';
|
|
5
|
+
import type {Size} from './image';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Given a value `t` that varies between 0 and 1, return
|
|
@@ -517,3 +519,151 @@ export function arrayBufferToImage(data: ArrayBuffer, callback: (err?: Error | n
|
|
|
517
519
|
const blob: Blob = new Blob([new Uint8Array(data)], {type: 'image/png'});
|
|
518
520
|
img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl;
|
|
519
521
|
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Computes the webcodecs VideoFrame API options to select a rectangle out of
|
|
525
|
+
* an image and write it into the destination rectangle.
|
|
526
|
+
*
|
|
527
|
+
* Rect (x/y/width/height) select the overlapping rectangle from the source image
|
|
528
|
+
* and layout (offset/stride) write that overlapping rectangle to the correct place
|
|
529
|
+
* in the destination image.
|
|
530
|
+
*
|
|
531
|
+
* Offset is the byte offset in the dest image that the first pixel appears at
|
|
532
|
+
* and stride is the number of bytes to the start of the next row:
|
|
533
|
+
* ┌───────────┐
|
|
534
|
+
* │ dest │
|
|
535
|
+
* │ ┌───┼───────┐
|
|
536
|
+
* │offset→│▓▓▓│ source│
|
|
537
|
+
* │ │▓▓▓│ │
|
|
538
|
+
* │ └───┼───────┘
|
|
539
|
+
* │stride ⇠╌╌╌│
|
|
540
|
+
* │╌╌╌╌╌╌→ │
|
|
541
|
+
* └───────────┘
|
|
542
|
+
*
|
|
543
|
+
* @param image - source image containing a width and height attribute
|
|
544
|
+
* @param x - top-left x coordinate to read from the image
|
|
545
|
+
* @param y - top-left y coordinate to read from the image
|
|
546
|
+
* @param width - width of the rectangle to read from the image
|
|
547
|
+
* @param height - height of the rectangle to read from the image
|
|
548
|
+
* @returns the layout and rect options to pass into VideoFrame API
|
|
549
|
+
*/
|
|
550
|
+
function computeVideoFrameParameters(image: Size, x: number, y: number, width: number, height: number): VideoFrameCopyToOptions {
|
|
551
|
+
const destRowOffset = Math.max(-x, 0) * 4;
|
|
552
|
+
const firstSourceRow = Math.max(0, y);
|
|
553
|
+
const firstDestRow = firstSourceRow - y;
|
|
554
|
+
const offset = firstDestRow * width * 4 + destRowOffset;
|
|
555
|
+
const stride = width * 4;
|
|
556
|
+
|
|
557
|
+
const sourceLeft = Math.max(0, x);
|
|
558
|
+
const sourceTop = Math.max(0, y);
|
|
559
|
+
const sourceRight = Math.min(image.width, x + width);
|
|
560
|
+
const sourceBottom = Math.min(image.height, y + height);
|
|
561
|
+
return {
|
|
562
|
+
rect: {
|
|
563
|
+
x: sourceLeft,
|
|
564
|
+
y: sourceTop,
|
|
565
|
+
width: sourceRight - sourceLeft,
|
|
566
|
+
height: sourceBottom - sourceTop
|
|
567
|
+
},
|
|
568
|
+
layout: [{offset, stride}]
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Reads pixels from an ImageBitmap/Image/canvas using webcodec VideoFrame API.
|
|
574
|
+
*
|
|
575
|
+
* @param data - image, imagebitmap, or canvas to parse
|
|
576
|
+
* @param x - top-left x coordinate to read from the image
|
|
577
|
+
* @param y - top-left y coordinate to read from the image
|
|
578
|
+
* @param width - width of the rectangle to read from the image
|
|
579
|
+
* @param height - height of the rectangle to read from the image
|
|
580
|
+
* @returns a promise containing the parsed RGBA pixel values of the image, or the error if an error occurred
|
|
581
|
+
*/
|
|
582
|
+
export async function readImageUsingVideoFrame(
|
|
583
|
+
image: HTMLImageElement | HTMLCanvasElement | ImageBitmap | OffscreenCanvas,
|
|
584
|
+
x: number, y: number, width: number, height: number
|
|
585
|
+
): Promise<Uint8ClampedArray> {
|
|
586
|
+
if (typeof VideoFrame === 'undefined') {
|
|
587
|
+
throw new Error('VideoFrame not supported');
|
|
588
|
+
}
|
|
589
|
+
const frame = new VideoFrame(image, {timestamp: 0});
|
|
590
|
+
try {
|
|
591
|
+
const format = frame?.format;
|
|
592
|
+
if (!format || !(format.startsWith('BGR') || format.startsWith('RGB'))) {
|
|
593
|
+
throw new Error(`Unrecognized format ${format}`);
|
|
594
|
+
}
|
|
595
|
+
const swapBR = format.startsWith('BGR');
|
|
596
|
+
const result = new Uint8ClampedArray(width * height * 4);
|
|
597
|
+
await frame.copyTo(result, computeVideoFrameParameters(image, x, y, width, height));
|
|
598
|
+
if (swapBR) {
|
|
599
|
+
for (let i = 0; i < result.length; i += 4) {
|
|
600
|
+
const tmp = result[i];
|
|
601
|
+
result[i] = result[i + 2];
|
|
602
|
+
result[i + 2] = tmp;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return result;
|
|
606
|
+
} finally {
|
|
607
|
+
frame.close();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
let offscreenCanvas: OffscreenCanvas;
|
|
612
|
+
let offscreenCanvasContext: OffscreenCanvasRenderingContext2D;
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Reads pixels from an ImageBitmap/Image/canvas using OffscreenCanvas
|
|
616
|
+
*
|
|
617
|
+
* @param data - image, imagebitmap, or canvas to parse
|
|
618
|
+
* @param x - top-left x coordinate to read from the image
|
|
619
|
+
* @param y - top-left y coordinate to read from the image
|
|
620
|
+
* @param width - width of the rectangle to read from the image
|
|
621
|
+
* @param height - height of the rectangle to read from the image
|
|
622
|
+
* @returns a promise containing the parsed RGBA pixel values of the image, or the error if an error occurred
|
|
623
|
+
*/
|
|
624
|
+
export function readImageDataUsingOffscreenCanvas(
|
|
625
|
+
imgBitmap: HTMLImageElement | HTMLCanvasElement | ImageBitmap | OffscreenCanvas,
|
|
626
|
+
x: number, y: number, width: number, height: number
|
|
627
|
+
): Uint8ClampedArray {
|
|
628
|
+
const origWidth = imgBitmap.width;
|
|
629
|
+
const origHeight = imgBitmap.height;
|
|
630
|
+
// Lazily initialize OffscreenCanvas
|
|
631
|
+
if (!offscreenCanvas || !offscreenCanvasContext) {
|
|
632
|
+
// Dem tiles are typically 256x256
|
|
633
|
+
offscreenCanvas = new OffscreenCanvas(origWidth, origHeight);
|
|
634
|
+
offscreenCanvasContext = offscreenCanvas.getContext('2d', {willReadFrequently: true});
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
offscreenCanvas.width = origWidth;
|
|
638
|
+
offscreenCanvas.height = origHeight;
|
|
639
|
+
|
|
640
|
+
offscreenCanvasContext.drawImage(imgBitmap, 0, 0, origWidth, origHeight);
|
|
641
|
+
const imgData = offscreenCanvasContext.getImageData(x, y, width, height);
|
|
642
|
+
offscreenCanvasContext.clearRect(0, 0, origWidth, origHeight);
|
|
643
|
+
return imgData.data;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Reads RGBA pixels from an preferring OffscreenCanvas, but falling back to VideoFrame if supported and
|
|
648
|
+
* the browser is mangling OffscreenCanvas getImageData results.
|
|
649
|
+
*
|
|
650
|
+
* @param data - image, imagebitmap, or canvas to parse
|
|
651
|
+
* @param x - top-left x coordinate to read from the image
|
|
652
|
+
* @param y - top-left y coordinate to read from the image
|
|
653
|
+
* @param width - width of the rectangle to read from the image
|
|
654
|
+
* @param height - height of the rectangle to read from the image
|
|
655
|
+
* @returns a promise containing the parsed RGBA pixel values of the image
|
|
656
|
+
*/
|
|
657
|
+
export async function getImageData(
|
|
658
|
+
image: HTMLImageElement | HTMLCanvasElement | ImageBitmap | OffscreenCanvas,
|
|
659
|
+
x: number, y: number, width: number, height: number
|
|
660
|
+
): Promise<Uint8ClampedArray> {
|
|
661
|
+
if (isOffscreenCanvasDistorted()) {
|
|
662
|
+
try {
|
|
663
|
+
return await readImageUsingVideoFrame(image, x, y, width, height);
|
|
664
|
+
} catch (e) {
|
|
665
|
+
// fall back to OffscreenCanvas
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return readImageDataUsingOffscreenCanvas(image, x, y, width, height);
|
|
669
|
+
}
|