Skip to content

Commit

Permalink
clipTile support return blob url
Browse files Browse the repository at this point in the history
  • Loading branch information
deyihu committed Oct 14, 2024
1 parent 60fdf37 commit ccc884f
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 86 deletions.
14 changes: 12 additions & 2 deletions src/cavnas.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
184 changes: 106 additions & 78 deletions src/tileclip.js
Original file line number Diff line number Diff line change
@@ -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 = {};
Expand Down Expand Up @@ -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;
}
15 changes: 9 additions & 6 deletions src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down

0 comments on commit ccc884f

Please sign in to comment.