From ccc884f5f5a65adfdd7e403ea3790cd76dc1ca0a Mon Sep 17 00:00:00 2001 From: hu de yi Date: Mon, 14 Oct 2024 09:48:42 +0800 Subject: [PATCH] clipTile support return blob url --- src/cavnas.js | 14 +++- src/tileclip.js | 184 ++++++++++++++++++++++++++++-------------------- src/worker.js | 15 ++-- 3 files changed, 127 insertions(+), 86 deletions(-) diff --git a/src/cavnas.js b/src/cavnas.js index 761cb3c..38234be 100644 --- a/src/cavnas.js +++ b/src/cavnas.js @@ -20,8 +20,8 @@ export function getCanvasContext(canvas) { return ctx; } -export function getBlankTile() { - const canvas = getCanvas(); +export function getBlankTile(tileSize) { + const canvas = getCanvas(tileSize); const ctx = getCanvasContext(canvas); clearCanvas(ctx); // ctx.fillText('404', 100, 100); @@ -64,3 +64,13 @@ export function imageClip(canvas, polygons, image) { ctx.restore(); return bitImage; } + +export function toBlobURL(imagebitmap) { + const canvas = getCanvas(); + canvas.width = imagebitmap.width; + canvas.height = imagebitmap.height; + const ctx = getCanvasContext(canvas); + clearCanvas(ctx); + ctx.drawImage(imagebitmap, 0, 0); + return canvas.convertToBlob(); +} diff --git a/src/tileclip.js b/src/tileclip.js index 14abe3d..72004f5 100644 --- a/src/tileclip.js +++ b/src/tileclip.js @@ -1,6 +1,6 @@ import geojsonbbox from '@maptalks/geojson-bbox'; import lineclip from 'lineclip'; -import { getBlankTile, getCanvas, imageClip } from './cavnas'; +import { getBlankTile, getCanvas, imageClip, toBlobURL } from './cavnas'; import { bboxInBBOX, bboxIntersect } from './bbox'; const GeoJSONCache = {}; @@ -102,88 +102,116 @@ function transformPixels(projection, tileBBOX, tileSize, coordinates) { } export function clip(options = {}) { - const { tile, tileBBOX, projection, tileSize, maskId } = options; - if (!tile) { - return new Error('tile is null.It should be a ImageBitmap'); - } - if (!tileBBOX) { - return new Error('tileBBOX is null'); - } - if (!projection) { - return new Error('projection is null'); - } - if (!tileSize) { - return new Error('tileSize is null'); - } - if (!maskId) { - return new Error('maskId is null'); - } - const feature = GeoJSONCache[maskId]; - if (!feature) { - return new Error('not find mask by maskId:' + maskId); - } - const canvas = getCanvas(tileSize); - if (!canvas) { - return new Error('not find canvas.The current environment does not support OffscreenCanvas'); - } - const bbox = feature.bbox; - if (!bbox) { - return tile; - } - const { coordinates, type } = feature.geometry; - if (!coordinates.length) { - return tile; - } - if (!bboxIntersect(bbox, tileBBOX)) { - return getBlankTile(); - } - let polygons = coordinates; - if (type === 'Polygon') { - polygons = [polygons]; - } - - let newCoordinates; - if (bboxInBBOX(bbox, tileBBOX)) { - newCoordinates = transformCoordinates(projection, polygons); - const pixels = transformPixels(projection, tileBBOX, tileSize, newCoordinates); - const image = imageClip(canvas, pixels, tile); - return image; - } + return new Promise((resolve, reject) => { + const { tile, tileBBOX, projection, tileSize, maskId, returnBlobURL } = options; + if (!tile) { + reject(new Error('tile is null.It should be a ImageBitmap')); + return; + } + if (!tileBBOX) { + reject(new Error('tileBBOX is null')); + return; + } + if (!projection) { + reject(new Error('projection is null')); + return; + } + if (!tileSize) { + reject(new Error('tileSize is null')); + return; + } + if (!maskId) { + reject(new Error('maskId is null')); + return; + } + const feature = GeoJSONCache[maskId]; + if (!feature) { + reject(new Error('not find mask by maskId:' + maskId)); + return; + } + const canvas = getCanvas(tileSize); + if (!canvas) { + reject(new Error('not find canvas.The current environment does not support OffscreenCanvas')); + return; + } - const validateClipRing = (result) => { - if (result.length > 0) { - let minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity; - for (let j = 0, len1 = result.length; j < len1; j++) { - const [x, y] = result[j]; - minx = Math.min(x, minx); - miny = Math.min(y, miny); - maxx = Math.max(x, maxx); - maxy = Math.max(y, maxy); - } - if (minx !== maxx && miny !== maxy) { - return true; + const returnImage = (image) => { + if (!returnBlobURL) { + resolve(image); + } else { + toBlobURL(image).then(blob => { + const url = URL.createObjectURL(blob); + resolve(url); + }).catch(error => { + reject(error); + }); } + }; + const bbox = feature.bbox; + if (!bbox) { + returnImage(tile); + return; } - return false; - }; + const { coordinates, type } = feature.geometry; + if (!coordinates.length) { + returnImage(tile); + return; + } + if (!bboxIntersect(bbox, tileBBOX)) { + returnImage(getBlankTile(tileSize)); + return; + } + let polygons = coordinates; + if (type === 'Polygon') { + polygons = [polygons]; + } + + let newCoordinates; + if (bboxInBBOX(bbox, tileBBOX)) { + newCoordinates = transformCoordinates(projection, polygons); + const pixels = transformPixels(projection, tileBBOX, tileSize, newCoordinates); + const image = imageClip(canvas, pixels, tile); + returnImage(image); + return; + } + + const validateClipRing = (result) => { + if (result.length > 0) { + let minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity; + for (let j = 0, len1 = result.length; j < len1; j++) { + const [x, y] = result[j]; + minx = Math.min(x, minx); + miny = Math.min(y, miny); + maxx = Math.max(x, maxx); + maxy = Math.max(y, maxy); + } + if (minx !== maxx && miny !== maxy) { + return true; + } + } + return false; + }; - const clipRings = []; - for (let i = 0, len = polygons.length; i < len; i++) { - const polygon = polygons[i]; - for (let j = 0, len1 = polygon.length; j < len1; j++) { - const ring = polygon[j]; - const result = lineclip.polygon(ring, tileBBOX); - if (validateClipRing(result)) { - clipRings.push([result]); + const clipRings = []; + for (let i = 0, len = polygons.length; i < len; i++) { + const polygon = polygons[i]; + for (let j = 0, len1 = polygon.length; j < len1; j++) { + const ring = polygon[j]; + const result = lineclip.polygon(ring, tileBBOX); + if (validateClipRing(result)) { + clipRings.push([result]); + } } } - } - if (clipRings.length === 0) { - return getBlankTile(); - } + if (clipRings.length === 0) { + returnImage(getBlankTile()); + return; + } + + newCoordinates = transformCoordinates(projection, clipRings); + const pixels = transformPixels(projection, tileBBOX, tileSize, newCoordinates); + const image = imageClip(canvas, pixels, tile); + returnImage(image); + }); - newCoordinates = transformCoordinates(projection, clipRings); - const pixels = transformPixels(projection, tileBBOX, tileSize, newCoordinates); - const image = imageClip(canvas, pixels, tile); - return image; } diff --git a/src/worker.js b/src/worker.js index d2f048d..4bc8753 100644 --- a/src/worker.js +++ b/src/worker.js @@ -17,12 +17,15 @@ export const onmessage = function (message, postResponse) { return; } if (type === 'clipTile') { - const image = clip(data); - if (image instanceof Error) { - postResponse(image); - return; - } - postResponse(null, image, [image]); + clip(data).then(image => { + const buffers = []; + if (image instanceof ImageBitmap) { + buffers.push(image); + } + postResponse(null, image, buffers); + }).catch(error => { + postResponse(error); + }); return; } if (type === 'injectMask') {