chore: move nested respondImage() function to top level

Signed-off-by: Martin d'Allens <martin.dallens@liberty-rider.com>
This commit is contained in:
Martin d'Allens 2023-11-19 23:28:42 +01:00 committed by Andrew Calcutt
parent 2525b29cf4
commit 3437a653b3

View file

@ -352,6 +352,175 @@ const calcZForBBox = (bbox, w, h, query) => {
return z; return z;
}; };
const respondImage = (
options,
item,
z,
lon,
lat,
bearing,
pitch,
width,
height,
scale,
format,
res,
next,
opt_overlay,
opt_mode = 'tile',
) => {
if (
Math.abs(lon) > 180 ||
Math.abs(lat) > 85.06 ||
lon !== lon ||
lat !== lat
) {
return res.status(400).send('Invalid center');
}
if (
Math.min(width, height) <= 0 ||
Math.max(width, height) * scale > (options.maxSize || 2048) ||
width !== width ||
height !== height
) {
return res.status(400).send('Invalid size');
}
if (format === 'png' || format === 'webp') {
} else if (format === 'jpg' || format === 'jpeg') {
format = 'jpeg';
} else {
return res.status(400).send('Invalid format');
}
const tileMargin = Math.max(options.tileMargin || 0, 0);
let pool;
if (opt_mode === 'tile' && tileMargin === 0) {
pool = item.map.renderers[scale];
} else {
pool = item.map.renderers_static[scale];
}
pool.acquire((err, renderer) => {
const mlglZ = Math.max(0, z - 1);
const params = {
zoom: mlglZ,
center: [lon, lat],
bearing: bearing,
pitch: pitch,
width: width,
height: height,
};
if (z === 0) {
params.width *= 2;
params.height *= 2;
}
if (z > 2 && tileMargin > 0) {
params.width += tileMargin * 2;
params.height += tileMargin * 2;
}
renderer.render(params, (err, data) => {
pool.release(renderer);
if (err) {
console.error(err);
return res.status(500).header('Content-Type', 'text/plain').send(err);
}
// Fix semi-transparent outlines on raw, premultiplied input
// https://github.com/maptiler/tileserver-gl/issues/350#issuecomment-477857040
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i + 3];
const norm = alpha / 255;
if (alpha === 0) {
data[i] = 0;
data[i + 1] = 0;
data[i + 2] = 0;
} else {
data[i] = data[i] / norm;
data[i + 1] = data[i + 1] / norm;
data[i + 2] = data[i + 2] / norm;
}
}
const image = sharp(data, {
raw: {
width: params.width * scale,
height: params.height * scale,
channels: 4,
},
});
if (z > 2 && tileMargin > 0) {
const [_, y] = mercator.px(params.center, z);
let yoffset = Math.max(
Math.min(0, y - 128 - tileMargin),
y + 128 + tileMargin - Math.pow(2, z + 8),
);
image.extract({
left: tileMargin * scale,
top: (tileMargin + yoffset) * scale,
width: width * scale,
height: height * scale,
});
}
if (z === 0) {
// HACK: when serving zoom 0, resize the 0 tile from 512 to 256
image.resize(width * scale, height * scale);
}
const composite_array = [];
if (opt_overlay) {
composite_array.push({ input: opt_overlay });
}
if (item.watermark) {
const canvas = renderWatermark(width, height, scale, item.watermark);
composite_array.push({ input: canvas.toBuffer() });
}
if (opt_mode === 'static' && item.staticAttributionText) {
const canvas = rendeAttribution(
width,
height,
scale,
item.staticAttributionText,
);
composite_array.push({ input: canvas.toBuffer() });
}
if (composite_array.length > 0) {
image.composite(composite_array);
}
const formatQuality = (options.formatQuality || {})[format];
if (format === 'png') {
image.png({ adaptiveFiltering: false });
} else if (format === 'jpeg') {
image.jpeg({ quality: formatQuality || 80 });
} else if (format === 'webp') {
image.webp({ quality: formatQuality || 90 });
}
image.toBuffer((err, buffer, info) => {
if (!buffer) {
return res.status(404).send('Not found');
}
res.set({
'Last-Modified': item.lastModified,
'Content-Type': `image/${format}`,
});
return res.status(200).send(buffer);
});
});
});
};
const existingFonts = {}; const existingFonts = {};
let maxScaleFactor = 2; let maxScaleFactor = 2;
@ -366,182 +535,6 @@ export const serve_rendered = {
const app = express().disable('x-powered-by'); const app = express().disable('x-powered-by');
const respondImage = (
item,
z,
lon,
lat,
bearing,
pitch,
width,
height,
scale,
format,
res,
next,
opt_overlay,
opt_mode = 'tile',
) => {
if (
Math.abs(lon) > 180 ||
Math.abs(lat) > 85.06 ||
lon !== lon ||
lat !== lat
) {
return res.status(400).send('Invalid center');
}
if (
Math.min(width, height) <= 0 ||
Math.max(width, height) * scale > (options.maxSize || 2048) ||
width !== width ||
height !== height
) {
return res.status(400).send('Invalid size');
}
if (format === 'png' || format === 'webp') {
} else if (format === 'jpg' || format === 'jpeg') {
format = 'jpeg';
} else {
return res.status(400).send('Invalid format');
}
const tileMargin = Math.max(options.tileMargin || 0, 0);
let pool;
if (opt_mode === 'tile' && tileMargin === 0) {
pool = item.map.renderers[scale];
} else {
pool = item.map.renderers_static[scale];
}
pool.acquire((err, renderer) => {
const mlglZ = Math.max(0, z - 1);
const params = {
zoom: mlglZ,
center: [lon, lat],
bearing: bearing,
pitch: pitch,
width: width,
height: height,
};
if (z === 0) {
params.width *= 2;
params.height *= 2;
}
if (z > 2 && tileMargin > 0) {
params.width += tileMargin * 2;
params.height += tileMargin * 2;
}
renderer.render(params, (err, data) => {
pool.release(renderer);
if (err) {
console.error(err);
return res
.status(500)
.header('Content-Type', 'text/plain')
.send(err);
}
// Fix semi-transparent outlines on raw, premultiplied input
// https://github.com/maptiler/tileserver-gl/issues/350#issuecomment-477857040
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i + 3];
const norm = alpha / 255;
if (alpha === 0) {
data[i] = 0;
data[i + 1] = 0;
data[i + 2] = 0;
} else {
data[i] = data[i] / norm;
data[i + 1] = data[i + 1] / norm;
data[i + 2] = data[i + 2] / norm;
}
}
const image = sharp(data, {
raw: {
width: params.width * scale,
height: params.height * scale,
channels: 4,
},
});
if (z > 2 && tileMargin > 0) {
const [_, y] = mercator.px(params.center, z);
let yoffset = Math.max(
Math.min(0, y - 128 - tileMargin),
y + 128 + tileMargin - Math.pow(2, z + 8),
);
image.extract({
left: tileMargin * scale,
top: (tileMargin + yoffset) * scale,
width: width * scale,
height: height * scale,
});
}
if (z === 0) {
// HACK: when serving zoom 0, resize the 0 tile from 512 to 256
image.resize(width * scale, height * scale);
}
const composite_array = [];
if (opt_overlay) {
composite_array.push({ input: opt_overlay });
}
if (item.watermark) {
const canvas = renderWatermark(
width,
height,
scale,
item.watermark,
);
composite_array.push({ input: canvas.toBuffer() });
}
if (opt_mode === 'static' && item.staticAttributionText) {
const canvas = rendeAttribution(
width,
height,
scale,
item.staticAttributionText,
);
composite_array.push({ input: canvas.toBuffer() });
}
if (composite_array.length > 0) {
image.composite(composite_array);
}
const formatQuality = (options.formatQuality || {})[format];
if (format === 'png') {
image.png({ adaptiveFiltering: false });
} else if (format === 'jpeg') {
image.jpeg({ quality: formatQuality || 80 });
} else if (format === 'webp') {
image.webp({ quality: formatQuality || 90 });
}
image.toBuffer((err, buffer, info) => {
if (!buffer) {
return res.status(404).send('Not found');
}
res.set({
'Last-Modified': item.lastModified,
'Content-Type': `image/${format}`,
});
return res.status(200).send(buffer);
});
});
});
};
app.get( app.get(
`/:id/:z(\\d+)/:x(\\d+)/:y(\\d+):scale(${scalePattern})?.:format([\\w]+)`, `/:id/:z(\\d+)/:x(\\d+)/:y(\\d+):scale(${scalePattern})?.:format([\\w]+)`,
(req, res, next) => { (req, res, next) => {
@ -582,6 +575,7 @@ export const serve_rendered = {
z, z,
); );
return respondImage( return respondImage(
options,
item, item,
z, z,
tileCenter[0], tileCenter[0],
@ -664,6 +658,7 @@ export const serve_rendered = {
); );
return respondImage( return respondImage(
options,
item, item,
z, z,
x, x,
@ -745,6 +740,7 @@ export const serve_rendered = {
req.query, req.query,
); );
return respondImage( return respondImage(
options,
item, item,
z, z,
x, x,
@ -879,6 +875,7 @@ export const serve_rendered = {
); );
return respondImage( return respondImage(
options,
item, item,
z, z,
x, x,