我正在制作一个Node.js
应用程序Jimp
。我有一个选择图像的一部分的功能。它在该区域中绘制一个矩形,在中间写入选择的编号,然后在矩形选择的外部绘制虚线边框。虚线边框似乎在增加,我不知道为什么。这是文件的完整代码:
imageManipulationUtil.js
:
const Jimp = require("jimp");
module.exports = async (readPath, writePath, comments, callback) => {
const originalImage = await Jimp.read(readPath);
const font = await Jimp.loadFont(Jimp.FONT_SANS_32_BLACK);
// Please ignore this part. Focus on the other part (the functions I mentioned above).
const addedWidth = 500;
const commentsHeight = comments.reduce((commentsHeight, { comment }, i) => {
comments[i].comment = `${i + 1}. ${comment}`;
const textWidth = Jimp.measureText(font, comment);
const textHeight = Jimp.measureTextHeight(font, comment);
const lines = Math.ceil(textWidth / addedWidth);
const height = textHeight * lines;
return commentsHeight + height;
}, 0);
const imageHeight = commentsHeight + 10;
if (imageHeight > originalImage.getHeight())
originalImage.resize(Jimp.AUTO, imageHeight);
const newImage = new Jimp(
originalImage.getWidth() + addedWidth,
originalImage.getHeight(),
0xffffffff
);
// Some other code for another purpose
// !!! Important code START !!!
drawSelectionRects(comments, font, newImage);
async function drawSelectionRects(comments, font, image) {
comments.forEach(({ dimensions }) => {
image.scanQuiet(
dimensions.x,
dimensions.y,
dimensions.width,
dimensions.height,
(x, y, idx) => {
const color = {
r: image.bitmap.data[idx + 0],
g: image.bitmap.data[idx + 1],
b: image.bitmap.data[idx + 2],
a: image.bitmap.data[idx + 3] / 255,
};
const selectionColor = {
r: 187,
g: 187,
b: 187,
a: 187,
};
const newColor = blendColors(color, selectionColor);
const hexColor = Jimp.rgbaToInt(
newColor.r,
newColor.g,
newColor.b,
255
);
image.setPixelColor(hexColor, x, y);
}
);
dashedBorder(
image,
{ lineDash: [20, 5], lineWidth: 3, color: 0x1a53ffbb },
dimensions
);
});
comments.forEach(({ dimensions }, i) => {
const text = `${i + 1}`;
let textX =
dimensions.x + (dimensions.width - Jimp.measureText(font, text)) / 2;
let textY =
dimensions.y +
(dimensions.height - Jimp.measureTextHeight(font, text)) / 2;
image.print(font, textX, textY, text);
});
}
function blendColors(c1, c2) {
const stepPoint = c2.a / 255;
const r = c1.r + stepPoint * (c2.r - c1.r);
const g = c1.g + stepPoint * (c2.g - c1.g);
const b = c1.b + stepPoint * (c2.b - c1.b);
return { r, g, b };
}
function dashedBorder(
image,
{ lineDash, lineWidth, color },
{ x, y, width, height }
) {
let drawing = true,
passed = 0;
color = Jimp.intToRGBA(color);
// Top border
for (let i = x; i < x + width; i++) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x, y));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
i,
y - k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Right border
for (let j = y; j < y + height; j++) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x + width, y));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
x + width + k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Bottom border
for (let i = x + width; i > x; i--) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(i, y + height));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
i,
y + height + k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
drawing = true;
// Left border
for (let j = y + height; j > y + lineWidth; j--) {
if (drawing) {
const pixelColor = Jimp.intToRGBA(image.getPixelColor(x, j));
const newColor = blendColors(pixelColor, color);
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(newColor.r, newColor.g, newColor.b, 255),
x - k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
}
newImage.write(writePath);
callback();
};
// !!! Important code END !!!
该代码导出了一个带有一些参数的函数。最重要的参数是评论参数(特别是评论的维度)。注释参数是一个对象数组。对象有一个dimensions
关键,这是这个问题中的重要关键。
让我认为图像正在成倍增加的问题是,在某些地方边框比其他部分更透明。最初我认为这只是因为我使用的图像,但后来我切换它并注意到这是一个真正的问题。
新的完整代码:
const Jimp = require("jimp");
function dashedBorder(
image,
{ lineDash, lineWidth, color },
{ x, y, width, height }
) {
let drawing = true,
passed = 0,
outsideWidth = lineWidth - 1;
color = Jimp.intToRGBA(color);
// Top border
for (let i = x - outsideWidth; i < x + width + outsideWidth; i++) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
i,
y - k
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Right border
for (
let j = y + lineWidth - outsideWidth;
j < y + height - (lineWidth - outsideWidth);
j++
) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
x + width + k - 1,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Bottom border
for (let i = x + width + lineWidth - outsideWidth; i > x - lineWidth; i--) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
i,
y + height + k - 1
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
// Left border
for (let j = y + height - outsideWidth; j > y; j--) {
if (drawing) {
for (let k = 0; k < lineWidth; k++) {
image.setPixelColor(
Jimp.rgbaToInt(color.r, color.g, color.b, 255),
x - k,
j
);
}
}
passed++;
if (
(passed >= lineDash[0] && drawing) ||
(passed >= lineDash[1] && !drawing)
) {
drawing = !drawing;
passed = 0;
}
}
}
(async () => {
let image = await Jimp.read("./test.png");
dashedBorder(
image,
{ lineWidth: 3, lineDash: [20, 5], color: 0x1a53ffbb },
{ x: 0, y: 0, width: image.bitmap.width, height: image.bitmap.height }
);
image.write("./test-border.png");
})();