@midscene/shared
Advanced tools
Comparing version 0.7.2 to 0.7.3-beta-20241029030944.0
// src/fs/index.ts | ||
import assert from "assert"; | ||
import { existsSync, readFileSync } from "fs"; | ||
import { dirname, join } from "path"; | ||
var pkg; | ||
function getMidscenePkgInfo(dir) { | ||
if (pkg) { | ||
return pkg; | ||
var pkgCacheMap = {}; | ||
var ifInBrowser = typeof window !== "undefined"; | ||
function getRunningPkgInfo(dir) { | ||
if (ifInBrowser) { | ||
return null; | ||
} | ||
const pkgDir = findNearestPackageJson(dir || process.cwd()); | ||
assert(pkgDir, "package.json not found"); | ||
const pkgJsonFile = join(pkgDir, "package.json"); | ||
if (pkgJsonFile) { | ||
const dirToCheck = dir || process.cwd(); | ||
if (pkgCacheMap[dirToCheck]) { | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
const pkgDir = findNearestPackageJson(dirToCheck); | ||
const pkgJsonFile = pkgDir ? join(pkgDir, "package.json") : null; | ||
if (pkgDir && pkgJsonFile) { | ||
const { name, version } = JSON.parse(readFileSync(pkgJsonFile, "utf-8")); | ||
pkg = { name, version, dir: pkgDir }; | ||
return pkg; | ||
pkgCacheMap[dirToCheck] = { name, version, dir: pkgDir }; | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
return { | ||
name: "midscene-unknown-page-name", | ||
name: "midscene-unknown-package-name", | ||
version: "0.0.0", | ||
dir: pkgDir | ||
dir: dirToCheck | ||
}; | ||
@@ -37,3 +40,3 @@ } | ||
findNearestPackageJson, | ||
getMidscenePkgInfo | ||
getRunningPkgInfo | ||
}; |
@@ -0,26 +1,73 @@ | ||
var __async = (__this, __arguments, generator) => { | ||
return new Promise((resolve, reject) => { | ||
var fulfilled = (value) => { | ||
try { | ||
step(generator.next(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var rejected = (value) => { | ||
try { | ||
step(generator.throw(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); | ||
step((generator = generator.apply(__this, __arguments)).next()); | ||
}); | ||
}; | ||
// src/img/info.ts | ||
import assert from "assert"; | ||
import { Buffer } from "buffer"; | ||
import { Buffer as Buffer2 } from "buffer"; | ||
import { readFileSync } from "fs"; | ||
import Jimp from "jimp"; | ||
async function imageInfo(image) { | ||
let jimpImage; | ||
if (typeof image === "string") { | ||
jimpImage = await Jimp.read(image); | ||
} else if (Buffer.isBuffer(image)) { | ||
jimpImage = await Jimp.read(image); | ||
} else { | ||
throw new Error("Invalid image input: must be a string path or a Buffer"); | ||
} | ||
const { width, height } = jimpImage.bitmap; | ||
assert( | ||
width && height, | ||
`Invalid image: ${typeof image === "string" ? image : "Buffer"}` | ||
); | ||
return { width, height }; | ||
// src/img/get-jimp.ts | ||
var ifInBrowser = typeof window !== "undefined"; | ||
function getJimp() { | ||
return __async(this, null, function* () { | ||
if (ifInBrowser) { | ||
yield import("jimp/browser/lib/jimp.js"); | ||
return window.Jimp; | ||
} | ||
return (yield import("jimp")).default; | ||
}); | ||
} | ||
async function imageInfoOfBase64(imageBase64) { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ""); | ||
return imageInfo(Buffer.from(base64Data, "base64")); | ||
// src/img/info.ts | ||
function imageInfo(image) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
let jimpImage; | ||
if (typeof image === "string") { | ||
jimpImage = yield Jimp.read(image); | ||
} else if (Buffer2.isBuffer(image)) { | ||
jimpImage = yield Jimp.read(image); | ||
} else if (image instanceof Jimp) { | ||
jimpImage = image; | ||
} else { | ||
throw new Error("Invalid image input: must be a string path or a Buffer"); | ||
} | ||
const { width, height } = jimpImage.bitmap; | ||
assert( | ||
width && height, | ||
`Invalid image: ${typeof image === "string" ? image : "Buffer"}` | ||
); | ||
return { width, height, jimpImage }; | ||
}); | ||
} | ||
function imageInfoOfBase64(imageBase64) { | ||
return __async(this, null, function* () { | ||
const buffer = yield bufferFromBase64(imageBase64); | ||
return imageInfo(buffer); | ||
}); | ||
} | ||
function bufferFromBase64(imageBase64) { | ||
return __async(this, null, function* () { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ""); | ||
return Buffer2.from(base64Data, "base64"); | ||
}); | ||
} | ||
function base64Encoded(image, withHeader = true) { | ||
@@ -44,29 +91,50 @@ const imageBuffer = readFileSync(image); | ||
// src/img/transform.ts | ||
import { Buffer as Buffer2 } from "buffer"; | ||
import Jimp2 from "jimp"; | ||
async function saveBase64Image(options) { | ||
const { base64Data, outputPath } = options; | ||
const base64Image = base64Data.split(";base64,").pop() || base64Data; | ||
const imageBuffer = Buffer2.from(base64Image, "base64"); | ||
const image = await Jimp2.read(imageBuffer); | ||
await image.writeAsync(outputPath); | ||
import { Buffer as Buffer3 } from "buffer"; | ||
function saveBase64Image(options) { | ||
return __async(this, null, function* () { | ||
const { base64Data, outputPath } = options; | ||
const base64Image = base64Data.split(";base64,").pop() || base64Data; | ||
const imageBuffer = Buffer3.from(base64Image, "base64"); | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(imageBuffer); | ||
yield image.writeAsync(outputPath); | ||
}); | ||
} | ||
async function transformImgPathToBase64(inputPath) { | ||
const image = await Jimp2.read(inputPath); | ||
const buffer = await image.getBufferAsync(Jimp2.MIME_PNG); | ||
return buffer.toString("base64"); | ||
function transformImgPathToBase64(inputPath) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(inputPath); | ||
const buffer = yield image.getBufferAsync(Jimp.MIME_PNG); | ||
return buffer.toString("base64"); | ||
}); | ||
} | ||
async function resizeImg(inputData, newSize) { | ||
const isBase64 = typeof inputData === "string"; | ||
const imageBuffer = isBase64 ? Buffer2.from(inputData.split(";base64,").pop() || inputData, "base64") : inputData; | ||
const image = await Jimp2.read(imageBuffer); | ||
const { width, height } = image.bitmap; | ||
if (!width || !height) { | ||
throw Error("Undefined width or height from the input image."); | ||
} | ||
const finalNewSize = newSize || calculateNewDimensions(width, height); | ||
image.resize(finalNewSize.width, finalNewSize.height); | ||
const resizedBuffer = await image.getBufferAsync(Jimp2.MIME_PNG); | ||
return isBase64 ? resizedBuffer.toString("base64") : resizedBuffer; | ||
function resizeImg(inputData, newSize) { | ||
return __async(this, null, function* () { | ||
if (typeof inputData === "string") | ||
throw Error("inputData is base64, use resizeImgBase64 instead"); | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(inputData); | ||
const { width, height } = image.bitmap; | ||
if (!width || !height) { | ||
throw Error("Undefined width or height from the input image."); | ||
} | ||
const finalNewSize = newSize || calculateNewDimensions(width, height); | ||
image.resize(finalNewSize.width, finalNewSize.height); | ||
const resizedBuffer = yield image.getBufferAsync(Jimp.MIME_PNG); | ||
return resizedBuffer; | ||
}); | ||
} | ||
function resizeImgBase64(inputData, newSize) { | ||
return __async(this, null, function* () { | ||
const splitFlag = ";base64,"; | ||
const dataSplitted = inputData.split(splitFlag); | ||
if (dataSplitted.length !== 2) { | ||
throw Error("Invalid base64 data"); | ||
} | ||
const imageBuffer = Buffer3.from(dataSplitted[1], "base64"); | ||
const buffer = yield resizeImg(imageBuffer, newSize); | ||
const content = buffer.toString("base64"); | ||
return `${dataSplitted[0]}${splitFlag}${content}`; | ||
}); | ||
} | ||
function calculateNewDimensions(originalWidth, originalHeight) { | ||
@@ -91,23 +159,26 @@ const maxWidth = 2048; | ||
} | ||
async function trimImage(image) { | ||
const jimpImage = await Jimp2.read( | ||
Buffer2.isBuffer(image) ? image : Buffer2.from(image) | ||
); | ||
const { width, height } = jimpImage.bitmap; | ||
if (width <= 3 || height <= 3) { | ||
return null; | ||
} | ||
const trimmedImage = jimpImage.autocrop(); | ||
const { width: trimmedWidth, height: trimmedHeight } = trimmedImage.bitmap; | ||
const trimOffsetLeft = (width - trimmedWidth) / 2; | ||
const trimOffsetTop = (height - trimmedHeight) / 2; | ||
if (trimOffsetLeft === 0 && trimOffsetTop === 0) { | ||
return null; | ||
} | ||
return { | ||
trimOffsetLeft: -trimOffsetLeft, | ||
trimOffsetTop: -trimOffsetTop, | ||
width: trimmedWidth, | ||
height: trimmedHeight | ||
}; | ||
function trimImage(image) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const jimpImage = yield Jimp.read( | ||
Buffer3.isBuffer(image) ? image : Buffer3.from(image) | ||
); | ||
const { width, height } = jimpImage.bitmap; | ||
if (width <= 3 || height <= 3) { | ||
return null; | ||
} | ||
const trimmedImage = jimpImage.autocrop(); | ||
const { width: trimmedWidth, height: trimmedHeight } = trimmedImage.bitmap; | ||
const trimOffsetLeft = (width - trimmedWidth) / 2; | ||
const trimOffsetTop = (height - trimmedHeight) / 2; | ||
if (trimOffsetLeft === 0 && trimOffsetTop === 0) { | ||
return null; | ||
} | ||
return { | ||
trimOffsetLeft: -trimOffsetLeft, | ||
trimOffsetTop: -trimOffsetTop, | ||
width: trimmedWidth, | ||
height: trimmedHeight | ||
}; | ||
}); | ||
} | ||
@@ -117,134 +188,145 @@ | ||
import assert2 from "assert"; | ||
import { Buffer as Buffer3 } from "buffer"; | ||
import Jimp3 from "jimp"; | ||
var createSvgOverlay = (elements, imageWidth, imageHeight) => { | ||
const createPngOverlay = async (elements2, imageWidth2, imageHeight2) => { | ||
const image = new Jimp3(imageWidth2, imageHeight2, 0); | ||
const colors = [ | ||
{ rect: 4278190335, text: 4294967295 } | ||
// red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements2.length; index++) { | ||
const element = elements2[index]; | ||
const color = colors[index % colors.length]; | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth2 - element.rect.left, | ||
element.rect.width + boxPadding * 2 | ||
), | ||
height: Math.min( | ||
imageHeight2 - element.rect.top, | ||
element.rect.height + boxPadding * 2 | ||
) | ||
}; | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function(x, y, idx) { | ||
if (x === paddedRect.left || x === paddedRect.left + paddedRect.width - 1 || y === paddedRect.top || y === paddedRect.top + paddedRect.height - 1) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
} | ||
var cachedFont = null; | ||
var createSvgOverlay = (elements, imageWidth, imageHeight) => __async(void 0, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const image = new Jimp(imageWidth, imageHeight, 0); | ||
const colors = [ | ||
{ rect: 4278190335, text: 4294967295 } | ||
// red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements.length; index++) { | ||
const element = elements[index]; | ||
const color = colors[index % colors.length]; | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth - element.rect.left, | ||
element.rect.width + boxPadding * 2 | ||
), | ||
height: Math.min( | ||
imageHeight - element.rect.top, | ||
element.rect.height + boxPadding * 2 | ||
) | ||
}; | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function(x, y, idx) { | ||
if (x === paddedRect.left || x === paddedRect.left + paddedRect.width - 1 || y === paddedRect.top || y === paddedRect.top + paddedRect.height - 1) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
} | ||
); | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
const checkOverlap = (x, y) => { | ||
return elements2.slice(0, index).some((otherElement) => { | ||
return x < otherElement.rect.left + otherElement.rect.width && x + rectWidth > otherElement.rect.left && y < otherElement.rect.top + otherElement.rect.height && y + rectHeight > otherElement.rect.top; | ||
}); | ||
}; | ||
const isWithinBounds = (x, y) => { | ||
return x >= 0 && x + rectWidth <= imageWidth2 && y >= 0 && y + rectHeight <= imageHeight2; | ||
}; | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
if (!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
) && isWithinBounds( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left + paddedRect.width + 2, | ||
paddedRect.top | ||
) && isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
} | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function(x, y, idx) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
); | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
const checkOverlap = (x, y) => { | ||
return elements.slice(0, index).some((otherElement) => { | ||
return x < otherElement.rect.left + otherElement.rect.width && x + rectWidth > otherElement.rect.left && y < otherElement.rect.top + otherElement.rect.height && y + rectHeight > otherElement.rect.top; | ||
}); | ||
const font = await Jimp3.loadFont(Jimp3.FONT_SANS_16_WHITE); | ||
image.print( | ||
font, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: Jimp3.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: Jimp3.VERTICAL_ALIGN_MIDDLE | ||
}, | ||
rectWidth, | ||
rectHeight | ||
); | ||
}; | ||
const isWithinBounds = (x, y) => { | ||
return x >= 0 && x + rectWidth <= imageWidth && y >= 0 && y + rectHeight <= imageHeight; | ||
}; | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
if (!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
) && isWithinBounds(paddedRect.left, paddedRect.top + paddedRect.height + 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} else if (!checkOverlap(paddedRect.left + paddedRect.width + 2, paddedRect.top) && isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
} | ||
return image.getBufferAsync(Jimp3.MIME_PNG); | ||
}; | ||
return createPngOverlay(elements, imageWidth, imageHeight); | ||
}; | ||
var compositeElementInfoImg = async (options) => { | ||
const { inputImgBase64, elementsPositionInfo } = options; | ||
const imageBuffer = Buffer3.from(inputImgBase64, "base64"); | ||
const image = await Jimp3.read(imageBuffer); | ||
const { width, height } = image.bitmap; | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function(x, y, idx) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
}); | ||
try { | ||
cachedFont = cachedFont || (yield Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)); | ||
} catch (error) { | ||
console.error("Error loading font", error); | ||
} | ||
image.print( | ||
cachedFont, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE | ||
}, | ||
rectWidth, | ||
rectHeight | ||
); | ||
} | ||
return image; | ||
}); | ||
var compositeElementInfoImg = (options) => __async(void 0, null, function* () { | ||
assert2(options.inputImgBase64, "inputImgBase64 is required"); | ||
let width = 0; | ||
let height = 0; | ||
let jimpImage; | ||
const Jimp = yield getJimp(); | ||
if (options.size) { | ||
width = options.size.width; | ||
height = options.size.height; | ||
} | ||
if (!width || !height) { | ||
const info = yield imageInfoOfBase64(options.inputImgBase64); | ||
width = info.width; | ||
height = info.height; | ||
jimpImage = info.jimpImage; | ||
} else { | ||
const imageBuffer = yield bufferFromBase64(options.inputImgBase64); | ||
jimpImage = yield Jimp.read(imageBuffer); | ||
} | ||
if (!width || !height) { | ||
throw Error("Image processing failed because width or height is undefined"); | ||
} | ||
const svgOverlay = await createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height | ||
); | ||
return await Jimp3.read(imageBuffer).then(async (image2) => { | ||
const svgImage = await Jimp3.read(svgOverlay); | ||
return image2.composite(svgImage, 0, 0, { | ||
mode: Jimp3.BLEND_SOURCE_OVER, | ||
const { elementsPositionInfo } = options; | ||
const result = yield Promise.resolve(jimpImage).then((image) => __async(void 0, null, function* () { | ||
const svgOverlay = yield createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height | ||
); | ||
const svgImage = yield Jimp.read(svgOverlay); | ||
const compositeImage = yield image.composite(svgImage, 0, 0, { | ||
mode: Jimp.BLEND_SOURCE_OVER, | ||
opacitySource: 1, | ||
opacityDest: 1 | ||
}); | ||
}).then((compositeImage) => { | ||
return compositeImage.getBufferAsync(Jimp3.MIME_PNG); | ||
}).then((buffer) => { | ||
return buffer.toString("base64"); | ||
}).catch((error) => { | ||
return compositeImage; | ||
})).then((compositeImage) => __async(void 0, null, function* () { | ||
const base64 = yield compositeImage.getBase64Async(Jimp.MIME_PNG); | ||
return base64; | ||
})).catch((error) => { | ||
throw error; | ||
}); | ||
}; | ||
var processImageElementInfo = async (options) => { | ||
return result; | ||
}); | ||
var processImageElementInfo = (options) => __async(void 0, null, function* () { | ||
const base64Image = options.inputImgBase64.split(";base64,").pop(); | ||
@@ -255,3 +337,3 @@ assert2(base64Image, "base64Image is undefined"); | ||
compositeElementInfoImgWithoutTextBase64 | ||
] = await Promise.all([ | ||
] = yield Promise.all([ | ||
compositeElementInfoImg({ | ||
@@ -270,6 +352,7 @@ inputImgBase64: options.inputImgBase64, | ||
}; | ||
}; | ||
}); | ||
export { | ||
base64Encoded, | ||
base64ToPngFormat, | ||
bufferFromBase64, | ||
calculateNewDimensions, | ||
@@ -281,2 +364,3 @@ compositeElementInfoImg, | ||
resizeImg, | ||
resizeImgBase64, | ||
saveBase64Image, | ||
@@ -283,0 +367,0 @@ transformImgPathToBase64, |
// src/index.ts | ||
function src_default() { | ||
return "hello world"; | ||
} | ||
var src_default = {}; | ||
export { | ||
src_default as default | ||
}; |
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
@@ -20,10 +18,2 @@ var __export = (target, all) => { | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
@@ -35,25 +25,28 @@ | ||
findNearestPackageJson: () => findNearestPackageJson, | ||
getMidscenePkgInfo: () => getMidscenePkgInfo | ||
getRunningPkgInfo: () => getRunningPkgInfo | ||
}); | ||
module.exports = __toCommonJS(fs_exports); | ||
var import_node_assert = __toESM(require("assert")); | ||
var import_node_fs = require("fs"); | ||
var import_node_path = require("path"); | ||
var pkg; | ||
function getMidscenePkgInfo(dir) { | ||
if (pkg) { | ||
return pkg; | ||
var pkgCacheMap = {}; | ||
var ifInBrowser = typeof window !== "undefined"; | ||
function getRunningPkgInfo(dir) { | ||
if (ifInBrowser) { | ||
return null; | ||
} | ||
const pkgDir = findNearestPackageJson(dir || process.cwd()); | ||
(0, import_node_assert.default)(pkgDir, "package.json not found"); | ||
const pkgJsonFile = (0, import_node_path.join)(pkgDir, "package.json"); | ||
if (pkgJsonFile) { | ||
const dirToCheck = dir || process.cwd(); | ||
if (pkgCacheMap[dirToCheck]) { | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
const pkgDir = findNearestPackageJson(dirToCheck); | ||
const pkgJsonFile = pkgDir ? (0, import_node_path.join)(pkgDir, "package.json") : null; | ||
if (pkgDir && pkgJsonFile) { | ||
const { name, version } = JSON.parse((0, import_node_fs.readFileSync)(pkgJsonFile, "utf-8")); | ||
pkg = { name, version, dir: pkgDir }; | ||
return pkg; | ||
pkgCacheMap[dirToCheck] = { name, version, dir: pkgDir }; | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
return { | ||
name: "midscene-unknown-page-name", | ||
name: "midscene-unknown-package-name", | ||
version: "0.0.0", | ||
dir: pkgDir | ||
dir: dirToCheck | ||
}; | ||
@@ -75,3 +68,3 @@ } | ||
findNearestPackageJson, | ||
getMidscenePkgInfo | ||
getRunningPkgInfo | ||
}); |
@@ -29,2 +29,22 @@ "use strict"; | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
var __async = (__this, __arguments, generator) => { | ||
return new Promise((resolve, reject) => { | ||
var fulfilled = (value) => { | ||
try { | ||
step(generator.next(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var rejected = (value) => { | ||
try { | ||
step(generator.throw(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); | ||
step((generator = generator.apply(__this, __arguments)).next()); | ||
}); | ||
}; | ||
@@ -36,2 +56,3 @@ // src/img/index.ts | ||
base64ToPngFormat: () => base64ToPngFormat, | ||
bufferFromBase64: () => bufferFromBase64, | ||
calculateNewDimensions: () => calculateNewDimensions, | ||
@@ -43,2 +64,3 @@ compositeElementInfoImg: () => compositeElementInfoImg, | ||
resizeImg: () => resizeImg, | ||
resizeImgBase64: () => resizeImgBase64, | ||
saveBase64Image: () => saveBase64Image, | ||
@@ -54,23 +76,49 @@ transformImgPathToBase64: () => transformImgPathToBase64, | ||
var import_node_fs = require("fs"); | ||
var import_jimp = __toESM(require("jimp")); | ||
async function imageInfo(image) { | ||
let jimpImage; | ||
if (typeof image === "string") { | ||
jimpImage = await import_jimp.default.read(image); | ||
} else if (import_node_buffer.Buffer.isBuffer(image)) { | ||
jimpImage = await import_jimp.default.read(image); | ||
} else { | ||
throw new Error("Invalid image input: must be a string path or a Buffer"); | ||
} | ||
const { width, height } = jimpImage.bitmap; | ||
(0, import_node_assert.default)( | ||
width && height, | ||
`Invalid image: ${typeof image === "string" ? image : "Buffer"}` | ||
); | ||
return { width, height }; | ||
// src/img/get-jimp.ts | ||
var ifInBrowser = typeof window !== "undefined"; | ||
function getJimp() { | ||
return __async(this, null, function* () { | ||
if (ifInBrowser) { | ||
yield import("jimp/browser/lib/jimp.js"); | ||
return window.Jimp; | ||
} | ||
return (yield import("jimp")).default; | ||
}); | ||
} | ||
async function imageInfoOfBase64(imageBase64) { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ""); | ||
return imageInfo(import_node_buffer.Buffer.from(base64Data, "base64")); | ||
// src/img/info.ts | ||
function imageInfo(image) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
let jimpImage; | ||
if (typeof image === "string") { | ||
jimpImage = yield Jimp.read(image); | ||
} else if (import_node_buffer.Buffer.isBuffer(image)) { | ||
jimpImage = yield Jimp.read(image); | ||
} else if (image instanceof Jimp) { | ||
jimpImage = image; | ||
} else { | ||
throw new Error("Invalid image input: must be a string path or a Buffer"); | ||
} | ||
const { width, height } = jimpImage.bitmap; | ||
(0, import_node_assert.default)( | ||
width && height, | ||
`Invalid image: ${typeof image === "string" ? image : "Buffer"}` | ||
); | ||
return { width, height, jimpImage }; | ||
}); | ||
} | ||
function imageInfoOfBase64(imageBase64) { | ||
return __async(this, null, function* () { | ||
const buffer = yield bufferFromBase64(imageBase64); | ||
return imageInfo(buffer); | ||
}); | ||
} | ||
function bufferFromBase64(imageBase64) { | ||
return __async(this, null, function* () { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ""); | ||
return import_node_buffer.Buffer.from(base64Data, "base64"); | ||
}); | ||
} | ||
function base64Encoded(image, withHeader = true) { | ||
@@ -95,28 +143,49 @@ const imageBuffer = (0, import_node_fs.readFileSync)(image); | ||
var import_node_buffer2 = require("buffer"); | ||
var import_jimp2 = __toESM(require("jimp")); | ||
async function saveBase64Image(options) { | ||
const { base64Data, outputPath } = options; | ||
const base64Image = base64Data.split(";base64,").pop() || base64Data; | ||
const imageBuffer = import_node_buffer2.Buffer.from(base64Image, "base64"); | ||
const image = await import_jimp2.default.read(imageBuffer); | ||
await image.writeAsync(outputPath); | ||
function saveBase64Image(options) { | ||
return __async(this, null, function* () { | ||
const { base64Data, outputPath } = options; | ||
const base64Image = base64Data.split(";base64,").pop() || base64Data; | ||
const imageBuffer = import_node_buffer2.Buffer.from(base64Image, "base64"); | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(imageBuffer); | ||
yield image.writeAsync(outputPath); | ||
}); | ||
} | ||
async function transformImgPathToBase64(inputPath) { | ||
const image = await import_jimp2.default.read(inputPath); | ||
const buffer = await image.getBufferAsync(import_jimp2.default.MIME_PNG); | ||
return buffer.toString("base64"); | ||
function transformImgPathToBase64(inputPath) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(inputPath); | ||
const buffer = yield image.getBufferAsync(Jimp.MIME_PNG); | ||
return buffer.toString("base64"); | ||
}); | ||
} | ||
async function resizeImg(inputData, newSize) { | ||
const isBase64 = typeof inputData === "string"; | ||
const imageBuffer = isBase64 ? import_node_buffer2.Buffer.from(inputData.split(";base64,").pop() || inputData, "base64") : inputData; | ||
const image = await import_jimp2.default.read(imageBuffer); | ||
const { width, height } = image.bitmap; | ||
if (!width || !height) { | ||
throw Error("Undefined width or height from the input image."); | ||
} | ||
const finalNewSize = newSize || calculateNewDimensions(width, height); | ||
image.resize(finalNewSize.width, finalNewSize.height); | ||
const resizedBuffer = await image.getBufferAsync(import_jimp2.default.MIME_PNG); | ||
return isBase64 ? resizedBuffer.toString("base64") : resizedBuffer; | ||
function resizeImg(inputData, newSize) { | ||
return __async(this, null, function* () { | ||
if (typeof inputData === "string") | ||
throw Error("inputData is base64, use resizeImgBase64 instead"); | ||
const Jimp = yield getJimp(); | ||
const image = yield Jimp.read(inputData); | ||
const { width, height } = image.bitmap; | ||
if (!width || !height) { | ||
throw Error("Undefined width or height from the input image."); | ||
} | ||
const finalNewSize = newSize || calculateNewDimensions(width, height); | ||
image.resize(finalNewSize.width, finalNewSize.height); | ||
const resizedBuffer = yield image.getBufferAsync(Jimp.MIME_PNG); | ||
return resizedBuffer; | ||
}); | ||
} | ||
function resizeImgBase64(inputData, newSize) { | ||
return __async(this, null, function* () { | ||
const splitFlag = ";base64,"; | ||
const dataSplitted = inputData.split(splitFlag); | ||
if (dataSplitted.length !== 2) { | ||
throw Error("Invalid base64 data"); | ||
} | ||
const imageBuffer = import_node_buffer2.Buffer.from(dataSplitted[1], "base64"); | ||
const buffer = yield resizeImg(imageBuffer, newSize); | ||
const content = buffer.toString("base64"); | ||
return `${dataSplitted[0]}${splitFlag}${content}`; | ||
}); | ||
} | ||
function calculateNewDimensions(originalWidth, originalHeight) { | ||
@@ -141,23 +210,26 @@ const maxWidth = 2048; | ||
} | ||
async function trimImage(image) { | ||
const jimpImage = await import_jimp2.default.read( | ||
import_node_buffer2.Buffer.isBuffer(image) ? image : import_node_buffer2.Buffer.from(image) | ||
); | ||
const { width, height } = jimpImage.bitmap; | ||
if (width <= 3 || height <= 3) { | ||
return null; | ||
} | ||
const trimmedImage = jimpImage.autocrop(); | ||
const { width: trimmedWidth, height: trimmedHeight } = trimmedImage.bitmap; | ||
const trimOffsetLeft = (width - trimmedWidth) / 2; | ||
const trimOffsetTop = (height - trimmedHeight) / 2; | ||
if (trimOffsetLeft === 0 && trimOffsetTop === 0) { | ||
return null; | ||
} | ||
return { | ||
trimOffsetLeft: -trimOffsetLeft, | ||
trimOffsetTop: -trimOffsetTop, | ||
width: trimmedWidth, | ||
height: trimmedHeight | ||
}; | ||
function trimImage(image) { | ||
return __async(this, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const jimpImage = yield Jimp.read( | ||
import_node_buffer2.Buffer.isBuffer(image) ? image : import_node_buffer2.Buffer.from(image) | ||
); | ||
const { width, height } = jimpImage.bitmap; | ||
if (width <= 3 || height <= 3) { | ||
return null; | ||
} | ||
const trimmedImage = jimpImage.autocrop(); | ||
const { width: trimmedWidth, height: trimmedHeight } = trimmedImage.bitmap; | ||
const trimOffsetLeft = (width - trimmedWidth) / 2; | ||
const trimOffsetTop = (height - trimmedHeight) / 2; | ||
if (trimOffsetLeft === 0 && trimOffsetTop === 0) { | ||
return null; | ||
} | ||
return { | ||
trimOffsetLeft: -trimOffsetLeft, | ||
trimOffsetTop: -trimOffsetTop, | ||
width: trimmedWidth, | ||
height: trimmedHeight | ||
}; | ||
}); | ||
} | ||
@@ -167,134 +239,145 @@ | ||
var import_node_assert2 = __toESM(require("assert")); | ||
var import_node_buffer3 = require("buffer"); | ||
var import_jimp3 = __toESM(require("jimp")); | ||
var createSvgOverlay = (elements, imageWidth, imageHeight) => { | ||
const createPngOverlay = async (elements2, imageWidth2, imageHeight2) => { | ||
const image = new import_jimp3.default(imageWidth2, imageHeight2, 0); | ||
const colors = [ | ||
{ rect: 4278190335, text: 4294967295 } | ||
// red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements2.length; index++) { | ||
const element = elements2[index]; | ||
const color = colors[index % colors.length]; | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth2 - element.rect.left, | ||
element.rect.width + boxPadding * 2 | ||
), | ||
height: Math.min( | ||
imageHeight2 - element.rect.top, | ||
element.rect.height + boxPadding * 2 | ||
) | ||
}; | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function(x, y, idx) { | ||
if (x === paddedRect.left || x === paddedRect.left + paddedRect.width - 1 || y === paddedRect.top || y === paddedRect.top + paddedRect.height - 1) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
} | ||
var cachedFont = null; | ||
var createSvgOverlay = (elements, imageWidth, imageHeight) => __async(void 0, null, function* () { | ||
const Jimp = yield getJimp(); | ||
const image = new Jimp(imageWidth, imageHeight, 0); | ||
const colors = [ | ||
{ rect: 4278190335, text: 4294967295 } | ||
// red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements.length; index++) { | ||
const element = elements[index]; | ||
const color = colors[index % colors.length]; | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth - element.rect.left, | ||
element.rect.width + boxPadding * 2 | ||
), | ||
height: Math.min( | ||
imageHeight - element.rect.top, | ||
element.rect.height + boxPadding * 2 | ||
) | ||
}; | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function(x, y, idx) { | ||
if (x === paddedRect.left || x === paddedRect.left + paddedRect.width - 1 || y === paddedRect.top || y === paddedRect.top + paddedRect.height - 1) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
} | ||
); | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
const checkOverlap = (x, y) => { | ||
return elements2.slice(0, index).some((otherElement) => { | ||
return x < otherElement.rect.left + otherElement.rect.width && x + rectWidth > otherElement.rect.left && y < otherElement.rect.top + otherElement.rect.height && y + rectHeight > otherElement.rect.top; | ||
}); | ||
}; | ||
const isWithinBounds = (x, y) => { | ||
return x >= 0 && x + rectWidth <= imageWidth2 && y >= 0 && y + rectHeight <= imageHeight2; | ||
}; | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
if (!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
) && isWithinBounds( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left + paddedRect.width + 2, | ||
paddedRect.top | ||
) && isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
} | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function(x, y, idx) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
); | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
const checkOverlap = (x, y) => { | ||
return elements.slice(0, index).some((otherElement) => { | ||
return x < otherElement.rect.left + otherElement.rect.width && x + rectWidth > otherElement.rect.left && y < otherElement.rect.top + otherElement.rect.height && y + rectHeight > otherElement.rect.top; | ||
}); | ||
const font = await import_jimp3.default.loadFont(import_jimp3.default.FONT_SANS_16_WHITE); | ||
image.print( | ||
font, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: import_jimp3.default.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: import_jimp3.default.VERTICAL_ALIGN_MIDDLE | ||
}, | ||
rectWidth, | ||
rectHeight | ||
); | ||
}; | ||
const isWithinBounds = (x, y) => { | ||
return x >= 0 && x + rectWidth <= imageWidth && y >= 0 && y + rectHeight <= imageHeight; | ||
}; | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
if (!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} else if (!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2 | ||
) && isWithinBounds(paddedRect.left, paddedRect.top + paddedRect.height + 2)) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} else if (!checkOverlap(paddedRect.left + paddedRect.width + 2, paddedRect.top) && isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
} | ||
return image.getBufferAsync(import_jimp3.default.MIME_PNG); | ||
}; | ||
return createPngOverlay(elements, imageWidth, imageHeight); | ||
}; | ||
var compositeElementInfoImg = async (options) => { | ||
const { inputImgBase64, elementsPositionInfo } = options; | ||
const imageBuffer = import_node_buffer3.Buffer.from(inputImgBase64, "base64"); | ||
const image = await import_jimp3.default.read(imageBuffer); | ||
const { width, height } = image.bitmap; | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function(x, y, idx) { | ||
this.bitmap.data[idx + 0] = color.rect >> 24 & 255; | ||
this.bitmap.data[idx + 1] = color.rect >> 16 & 255; | ||
this.bitmap.data[idx + 2] = color.rect >> 8 & 255; | ||
this.bitmap.data[idx + 3] = color.rect & 255; | ||
}); | ||
try { | ||
cachedFont = cachedFont || (yield Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)); | ||
} catch (error) { | ||
console.error("Error loading font", error); | ||
} | ||
image.print( | ||
cachedFont, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE | ||
}, | ||
rectWidth, | ||
rectHeight | ||
); | ||
} | ||
return image; | ||
}); | ||
var compositeElementInfoImg = (options) => __async(void 0, null, function* () { | ||
(0, import_node_assert2.default)(options.inputImgBase64, "inputImgBase64 is required"); | ||
let width = 0; | ||
let height = 0; | ||
let jimpImage; | ||
const Jimp = yield getJimp(); | ||
if (options.size) { | ||
width = options.size.width; | ||
height = options.size.height; | ||
} | ||
if (!width || !height) { | ||
const info = yield imageInfoOfBase64(options.inputImgBase64); | ||
width = info.width; | ||
height = info.height; | ||
jimpImage = info.jimpImage; | ||
} else { | ||
const imageBuffer = yield bufferFromBase64(options.inputImgBase64); | ||
jimpImage = yield Jimp.read(imageBuffer); | ||
} | ||
if (!width || !height) { | ||
throw Error("Image processing failed because width or height is undefined"); | ||
} | ||
const svgOverlay = await createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height | ||
); | ||
return await import_jimp3.default.read(imageBuffer).then(async (image2) => { | ||
const svgImage = await import_jimp3.default.read(svgOverlay); | ||
return image2.composite(svgImage, 0, 0, { | ||
mode: import_jimp3.default.BLEND_SOURCE_OVER, | ||
const { elementsPositionInfo } = options; | ||
const result = yield Promise.resolve(jimpImage).then((image) => __async(void 0, null, function* () { | ||
const svgOverlay = yield createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height | ||
); | ||
const svgImage = yield Jimp.read(svgOverlay); | ||
const compositeImage = yield image.composite(svgImage, 0, 0, { | ||
mode: Jimp.BLEND_SOURCE_OVER, | ||
opacitySource: 1, | ||
opacityDest: 1 | ||
}); | ||
}).then((compositeImage) => { | ||
return compositeImage.getBufferAsync(import_jimp3.default.MIME_PNG); | ||
}).then((buffer) => { | ||
return buffer.toString("base64"); | ||
}).catch((error) => { | ||
return compositeImage; | ||
})).then((compositeImage) => __async(void 0, null, function* () { | ||
const base64 = yield compositeImage.getBase64Async(Jimp.MIME_PNG); | ||
return base64; | ||
})).catch((error) => { | ||
throw error; | ||
}); | ||
}; | ||
var processImageElementInfo = async (options) => { | ||
return result; | ||
}); | ||
var processImageElementInfo = (options) => __async(void 0, null, function* () { | ||
const base64Image = options.inputImgBase64.split(";base64,").pop(); | ||
@@ -305,3 +388,3 @@ (0, import_node_assert2.default)(base64Image, "base64Image is undefined"); | ||
compositeElementInfoImgWithoutTextBase64 | ||
] = await Promise.all([ | ||
] = yield Promise.all([ | ||
compositeElementInfoImg({ | ||
@@ -320,3 +403,3 @@ inputImgBase64: options.inputImgBase64, | ||
}; | ||
}; | ||
}); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
@@ -326,2 +409,3 @@ 0 && (module.exports = { | ||
base64ToPngFormat, | ||
bufferFromBase64, | ||
calculateNewDimensions, | ||
@@ -333,2 +417,3 @@ compositeElementInfoImg, | ||
resizeImg, | ||
resizeImgBase64, | ||
saveBase64Image, | ||
@@ -335,0 +420,0 @@ transformImgPathToBase64, |
@@ -26,4 +26,2 @@ "use strict"; | ||
module.exports = __toCommonJS(src_exports); | ||
function src_default() { | ||
return "hello world"; | ||
} | ||
var src_default = {}; |
@@ -1,3 +0,3 @@ | ||
declare function export_default(): string; | ||
declare const _default: {}; | ||
export { export_default as default }; | ||
export { _default as default }; |
{ | ||
"name": "@midscene/shared", | ||
"version": "0.7.2", | ||
"version": "0.7.3-beta-20241029030944.0", | ||
"repository": "https://github.com/web-infra-dev/midscene", | ||
"homepage": "https://midscenejs.com/", | ||
"types": "./dist/types/index.d.ts", | ||
"types": "./src/index.ts", | ||
"type": "commonjs", | ||
"main": "./dist/lib/index.js", | ||
@@ -11,20 +12,30 @@ "module": "./dist/es/index.js", | ||
".": { | ||
"types": "./dist/types/index.d.ts", | ||
"import": "./dist/es/index.js", | ||
"require": "./dist/lib/index.js" | ||
"types": "./dist/lib/index.d.ts", | ||
"require": "./dist/lib/index.js", | ||
"import": "./dist/es/index.js" | ||
}, | ||
"./constants": { | ||
"types": "./dist/types/constants.d.ts", | ||
"import": "./dist/es/constants.js", | ||
"require": "./dist/lib/constants.js" | ||
"types": "./dist/lib/constants.d.ts", | ||
"require": "./dist/lib/constants.js", | ||
"import": "./dist/es/constants.js" | ||
}, | ||
"./fs": { | ||
"types": "./dist/lib/fs.d.ts", | ||
"require": "./dist/lib/fs.js", | ||
"import": "./dist/es/fs.js" | ||
}, | ||
"./img": { | ||
"types": "./dist/types/img.d.ts", | ||
"import": "./dist/es/img.js", | ||
"require": "./dist/lib/img.js" | ||
"types": "./dist/lib/img.d.ts", | ||
"require": "./dist/lib/img.js", | ||
"import": "./dist/es/img.js" | ||
}, | ||
"./fs": { | ||
"types": "./dist/types/fs.d.ts", | ||
"import": "./dist/es/fs.js", | ||
"require": "./dist/lib/fs.js" | ||
"./browser/img": { | ||
"types": "./dist/browser/img.d.ts", | ||
"require": "./dist/browser/img.js", | ||
"import": "./dist/browser/img.js" | ||
}, | ||
"./utils": { | ||
"types": "./dist/lib/utils.d.ts", | ||
"require": "./dist/lib/utils.js", | ||
"import": "./dist/es/utils.js" | ||
} | ||
@@ -35,12 +46,18 @@ }, | ||
".": [ | ||
"./dist/types/index.d.ts" | ||
"./dist/lib/index.d.ts" | ||
], | ||
"constants": [ | ||
"./dist/types/constants.d.ts" | ||
"./dist/lib/constants.d.ts" | ||
], | ||
"img": [ | ||
"./dist/types/img.d.ts" | ||
"./dist/lib/img.d.ts" | ||
], | ||
"browser/img": [ | ||
"./dist/browser/img.d.ts" | ||
], | ||
"fs": [ | ||
"./dist/types/fs.d.ts" | ||
"./dist/lib/fs.d.ts" | ||
], | ||
"utils": [ | ||
"./dist/lib/utils.d.ts" | ||
] | ||
@@ -47,0 +64,0 @@ } |
@@ -11,21 +11,25 @@ import assert from 'node:assert'; | ||
let pkg: PkgInfo | undefined; | ||
export function getMidscenePkgInfo(dir: string): PkgInfo { | ||
if (pkg) { | ||
return pkg; | ||
const pkgCacheMap: Record<string, PkgInfo> = {}; | ||
const ifInBrowser = typeof window !== 'undefined'; | ||
export function getRunningPkgInfo(dir?: string): PkgInfo | null { | ||
if (ifInBrowser) { | ||
return null; | ||
} | ||
const dirToCheck = dir || process.cwd(); | ||
if (pkgCacheMap[dirToCheck]) { | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
const pkgDir = findNearestPackageJson(dir || process.cwd()); | ||
assert(pkgDir, 'package.json not found'); | ||
const pkgJsonFile = join(pkgDir, 'package.json'); | ||
const pkgDir = findNearestPackageJson(dirToCheck); | ||
const pkgJsonFile = pkgDir ? join(pkgDir, 'package.json') : null; | ||
if (pkgJsonFile) { | ||
if (pkgDir && pkgJsonFile) { | ||
const { name, version } = JSON.parse(readFileSync(pkgJsonFile, 'utf-8')); | ||
pkg = { name, version, dir: pkgDir }; | ||
return pkg; | ||
pkgCacheMap[dirToCheck] = { name, version, dir: pkgDir }; | ||
return pkgCacheMap[dirToCheck]; | ||
} | ||
return { | ||
name: 'midscene-unknown-page-name', | ||
name: 'midscene-unknown-package-name', | ||
version: '0.0.0', | ||
dir: pkgDir, | ||
dir: dirToCheck, | ||
}; | ||
@@ -32,0 +36,0 @@ } |
import assert from 'node:assert'; | ||
import { Buffer } from 'node:buffer'; | ||
import type { Buffer } from 'node:buffer'; | ||
import type { Rect } from '@/types'; | ||
import Jimp from 'jimp'; | ||
import type Jimp from 'jimp'; | ||
import type { NodeType } from '../constants'; | ||
import getJimp from './get-jimp'; | ||
import { bufferFromBase64, imageInfo, imageInfoOfBase64 } from './index'; | ||
@@ -25,166 +27,159 @@ // Define picture path | ||
const createSvgOverlay = ( | ||
let cachedFont: any = null; | ||
const createSvgOverlay = async ( | ||
elements: Array<ElementType>, | ||
imageWidth: number, | ||
imageHeight: number, | ||
) => { | ||
const createPngOverlay = async ( | ||
elements: Array<ElementType>, | ||
imageWidth: number, | ||
imageHeight: number, | ||
) => { | ||
const image = new Jimp(imageWidth, imageHeight, 0x00000000); | ||
): Promise<Jimp> => { | ||
const Jimp = await getJimp(); | ||
const image = new Jimp(imageWidth, imageHeight, 0x00000000); | ||
// Define color array | ||
const colors = [ | ||
{ rect: 0xff0000ff, text: 0xffffffff }, // red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
// Define color array | ||
const colors = [ | ||
{ rect: 0xff0000ff, text: 0xffffffff }, // red, white | ||
// { rect: 0x0000ffff, text: 0xffffffff }, // blue, white | ||
// { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white | ||
]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements.length; index++) { | ||
const element = elements[index]; | ||
const color = colors[index % colors.length]; | ||
const boxPadding = 5; | ||
for (let index = 0; index < elements.length; index++) { | ||
const element = elements[index]; | ||
const color = colors[index % colors.length]; | ||
// Add 5px padding to the rect | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth - element.rect.left, | ||
element.rect.width + boxPadding * 2, | ||
), | ||
height: Math.min( | ||
imageHeight - element.rect.top, | ||
element.rect.height + boxPadding * 2, | ||
), | ||
}; | ||
// Add 5px padding to the rect | ||
const paddedRect = { | ||
left: Math.max(0, element.rect.left - boxPadding), | ||
top: Math.max(0, element.rect.top - boxPadding), | ||
width: Math.min( | ||
imageWidth - element.rect.left, | ||
element.rect.width + boxPadding * 2, | ||
), | ||
height: Math.min( | ||
imageHeight - element.rect.top, | ||
element.rect.height + boxPadding * 2, | ||
), | ||
}; | ||
// Draw rectangle | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function (x, y, idx) { | ||
if ( | ||
x === paddedRect.left || | ||
x === paddedRect.left + paddedRect.width - 1 || | ||
y === paddedRect.top || | ||
y === paddedRect.top + paddedRect.height - 1 | ||
) { | ||
this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R | ||
this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G | ||
this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B | ||
this.bitmap.data[idx + 3] = color.rect & 0xff; // A | ||
} | ||
}, | ||
); | ||
// Draw rectangle | ||
image.scan( | ||
paddedRect.left, | ||
paddedRect.top, | ||
paddedRect.width, | ||
paddedRect.height, | ||
function (x, y, idx) { | ||
if ( | ||
x === paddedRect.left || | ||
x === paddedRect.left + paddedRect.width - 1 || | ||
y === paddedRect.top || | ||
y === paddedRect.top + paddedRect.height - 1 | ||
) { | ||
this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R | ||
this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G | ||
this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B | ||
this.bitmap.data[idx + 3] = color.rect & 0xff; // A | ||
} | ||
}, | ||
); | ||
// Calculate text position | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
// Calculate text position | ||
const textWidth = element.indexId.toString().length * 8; | ||
const textHeight = 12; | ||
const rectWidth = textWidth + 5; | ||
const rectHeight = textHeight + 4; | ||
let rectX = paddedRect.left - rectWidth; | ||
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2; | ||
// Check if this new position overlaps with any existing boxes | ||
// Function to check if a given position overlaps with any existing boxes | ||
const checkOverlap = (x: number, y: number) => { | ||
// Check against all previously processed elements | ||
return elements.slice(0, index).some((otherElement) => { | ||
// Check if the rectangles overlap | ||
return ( | ||
x < otherElement.rect.left + otherElement.rect.width && | ||
x + rectWidth > otherElement.rect.left && | ||
y < otherElement.rect.top + otherElement.rect.height && | ||
y + rectHeight > otherElement.rect.top | ||
); | ||
}); | ||
}; | ||
// Function to check if a given position is within the image bounds | ||
const isWithinBounds = (x: number, y: number) => { | ||
// Check if this new position overlaps with any existing boxes | ||
// Function to check if a given position overlaps with any existing boxes | ||
const checkOverlap = (x: number, y: number) => { | ||
// Check against all previously processed elements | ||
return elements.slice(0, index).some((otherElement) => { | ||
// Check if the rectangles overlap | ||
return ( | ||
x >= 0 && | ||
x + rectWidth <= imageWidth && | ||
y >= 0 && | ||
y + rectHeight <= imageHeight | ||
x < otherElement.rect.left + otherElement.rect.width && | ||
x + rectWidth > otherElement.rect.left && | ||
y < otherElement.rect.top + otherElement.rect.height && | ||
y + rectHeight > otherElement.rect.top | ||
); | ||
}; | ||
}); | ||
}; | ||
// Check left side (original position) | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
// If the original position overlaps or is out of bounds, try alternative positions | ||
// Function to check if a given position is within the image bounds | ||
const isWithinBounds = (x: number, y: number) => { | ||
return ( | ||
x >= 0 && | ||
x + rectWidth <= imageWidth && | ||
y >= 0 && | ||
y + rectHeight <= imageHeight | ||
); | ||
}; | ||
// Check top position | ||
if ( | ||
!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && | ||
isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2) | ||
) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} | ||
// Check bottom position | ||
else if ( | ||
!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2, | ||
) && | ||
isWithinBounds( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2, | ||
) | ||
) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} | ||
// Check right position | ||
else if ( | ||
!checkOverlap( | ||
paddedRect.left + paddedRect.width + 2, | ||
paddedRect.top, | ||
) && | ||
isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top) | ||
) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} | ||
// If all sides are overlapped or out of bounds, place it inside the box at the top | ||
else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
// Check left side (original position) | ||
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) { | ||
// If the original position overlaps or is out of bounds, try alternative positions | ||
// Check top position | ||
if ( | ||
!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && | ||
isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2) | ||
) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top - rectHeight - 2; | ||
} | ||
// Note: If the original left position doesn't overlap and is within bounds, we keep it as is | ||
// Check bottom position | ||
else if ( | ||
!checkOverlap( | ||
paddedRect.left, | ||
paddedRect.top + paddedRect.height + 2, | ||
) && | ||
isWithinBounds(paddedRect.left, paddedRect.top + paddedRect.height + 2) | ||
) { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + paddedRect.height + 2; | ||
} | ||
// Check right position | ||
else if ( | ||
!checkOverlap(paddedRect.left + paddedRect.width + 2, paddedRect.top) && | ||
isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top) | ||
) { | ||
rectX = paddedRect.left + paddedRect.width + 2; | ||
rectY = paddedRect.top; | ||
} | ||
// If all sides are overlapped or out of bounds, place it inside the box at the top | ||
else { | ||
rectX = paddedRect.left; | ||
rectY = paddedRect.top + 2; | ||
} | ||
} | ||
// Note: If the original left position doesn't overlap and is within bounds, we keep it as is | ||
// Draw text background | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function (x, y, idx) { | ||
this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R | ||
this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G | ||
this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B | ||
this.bitmap.data[idx + 3] = color.rect & 0xff; // A | ||
}); | ||
// Draw text (simplified, as Jimp doesn't have built-in text drawing) | ||
const font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE); | ||
image.print( | ||
font, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE, | ||
}, | ||
rectWidth, | ||
rectHeight, | ||
); | ||
// Draw text background | ||
image.scan(rectX, rectY, rectWidth, rectHeight, function (x, y, idx) { | ||
this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R | ||
this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G | ||
this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B | ||
this.bitmap.data[idx + 3] = color.rect & 0xff; // A | ||
}); | ||
// Draw text (simplified, as Jimp doesn't have built-in text drawing) | ||
try { | ||
cachedFont = cachedFont || (await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)); | ||
} catch (error) { | ||
console.error('Error loading font', error); | ||
} | ||
image.print( | ||
cachedFont, | ||
rectX, | ||
rectY, | ||
{ | ||
text: element.indexId.toString(), | ||
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER, | ||
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE, | ||
}, | ||
rectWidth, | ||
rectHeight, | ||
); | ||
} | ||
return image.getBufferAsync(Jimp.MIME_PNG); | ||
}; | ||
return createPngOverlay(elements, imageWidth, imageHeight); | ||
return image; | ||
}; | ||
@@ -195,23 +190,42 @@ | ||
elementsPositionInfo: Array<ElementType>; | ||
size?: { width: number; height: number }; | ||
}) => { | ||
const { inputImgBase64, elementsPositionInfo } = options; | ||
const imageBuffer = Buffer.from(inputImgBase64, 'base64'); | ||
const image = await Jimp.read(imageBuffer); | ||
const { width, height } = image.bitmap; | ||
assert(options.inputImgBase64, 'inputImgBase64 is required'); | ||
let width = 0; | ||
let height = 0; | ||
let jimpImage: Jimp; | ||
const Jimp = await getJimp(); | ||
if (options.size) { | ||
width = options.size.width; | ||
height = options.size.height; | ||
} | ||
if (!width || !height) { | ||
const info = await imageInfoOfBase64(options.inputImgBase64); | ||
width = info.width; | ||
height = info.height; | ||
jimpImage = info.jimpImage; | ||
} else { | ||
const imageBuffer = await bufferFromBase64(options.inputImgBase64); | ||
jimpImage = await Jimp.read(imageBuffer); | ||
} | ||
if (!width || !height) { | ||
throw Error('Image processing failed because width or height is undefined'); | ||
} | ||
// Create svg overlay | ||
const svgOverlay = await createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height, | ||
); | ||
const { elementsPositionInfo } = options; | ||
return await Jimp.read(imageBuffer) | ||
const result = await Promise.resolve(jimpImage) | ||
.then(async (image: Jimp) => { | ||
// Create svg overlay | ||
const svgOverlay = await createSvgOverlay( | ||
elementsPositionInfo, | ||
width, | ||
height, | ||
); | ||
const svgImage = await Jimp.read(svgOverlay); | ||
return image.composite(svgImage, 0, 0, { | ||
const compositeImage = await image.composite(svgImage, 0, 0, { | ||
mode: Jimp.BLEND_SOURCE_OVER, | ||
@@ -221,12 +235,13 @@ opacitySource: 1, | ||
}); | ||
return compositeImage; | ||
}) | ||
.then((compositeImage: Jimp) => { | ||
return compositeImage.getBufferAsync(Jimp.MIME_PNG); | ||
.then(async (compositeImage: Jimp) => { | ||
const base64 = await compositeImage.getBase64Async(Jimp.MIME_PNG); | ||
return base64; | ||
}) | ||
.then((buffer: Buffer) => { | ||
return buffer.toString('base64'); | ||
}) | ||
.catch((error: unknown) => { | ||
throw error; | ||
}); | ||
return result; | ||
}; | ||
@@ -233,0 +248,0 @@ |
export { | ||
imageInfo, | ||
imageInfoOfBase64, | ||
bufferFromBase64, | ||
base64Encoded, | ||
@@ -11,2 +12,3 @@ base64ToPngFormat, | ||
resizeImg, | ||
resizeImgBase64, | ||
transformImgPathToBase64, | ||
@@ -13,0 +15,0 @@ saveBase64Image, |
import assert from 'node:assert'; | ||
import { Buffer } from 'node:buffer'; | ||
import { readFileSync } from 'node:fs'; | ||
import Jimp from 'jimp'; | ||
import type Jimp from 'jimp'; | ||
import getJimp from './get-jimp'; | ||
@@ -11,2 +12,6 @@ export interface Size { | ||
export interface ImageInfo extends Size { | ||
jimpImage: Jimp; | ||
} | ||
/** | ||
@@ -19,3 +24,6 @@ * Retrieves the dimensions of an image asynchronously | ||
*/ | ||
export async function imageInfo(image: string | Buffer): Promise<Size> { | ||
export async function imageInfo( | ||
image: string | Buffer | Jimp, | ||
): Promise<ImageInfo> { | ||
const Jimp = await getJimp(); | ||
let jimpImage: Jimp; | ||
@@ -26,2 +34,4 @@ if (typeof image === 'string') { | ||
jimpImage = await Jimp.read(image); | ||
} else if (image instanceof Jimp) { | ||
jimpImage = image; | ||
} else { | ||
@@ -35,3 +45,3 @@ throw new Error('Invalid image input: must be a string path or a Buffer'); | ||
); | ||
return { width, height }; | ||
return { width, height, jimpImage }; | ||
} | ||
@@ -46,8 +56,16 @@ | ||
*/ | ||
export async function imageInfoOfBase64(imageBase64: string): Promise<Size> { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ''); | ||
export async function imageInfoOfBase64( | ||
imageBase64: string, | ||
): Promise<ImageInfo> { | ||
// const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ''); | ||
// Call the imageInfo function to get the dimensions of the image | ||
return imageInfo(Buffer.from(base64Data, 'base64')); | ||
const buffer = await bufferFromBase64(imageBase64); | ||
return imageInfo(buffer); | ||
} | ||
export async function bufferFromBase64(imageBase64: string): Promise<Buffer> { | ||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, ''); | ||
return Buffer.from(base64Data, 'base64'); | ||
} | ||
/** | ||
@@ -54,0 +72,0 @@ * Encodes an image file to a base64 encoded string |
import { Buffer } from 'node:buffer'; | ||
import Jimp from 'jimp'; | ||
import getJimp from './get-jimp'; | ||
/** | ||
/** | ||
* Saves a Base64-encoded image to a file | ||
@@ -24,2 +25,3 @@ * | ||
// Use Jimp to process the image and save it to the specified location | ||
const Jimp = await getJimp(); | ||
const image = await Jimp.read(imageBuffer); | ||
@@ -36,2 +38,3 @@ await image.writeAsync(outputPath); | ||
// Use Jimp to process images and generate base64 data | ||
const Jimp = await getJimp(); | ||
const image = await Jimp.read(inputPath); | ||
@@ -50,3 +53,3 @@ const buffer = await image.getBufferAsync(Jimp.MIME_PNG); | ||
export async function resizeImg( | ||
inputData: string | Buffer, | ||
inputData: Buffer, | ||
newSize?: { | ||
@@ -56,9 +59,8 @@ width: number; | ||
}, | ||
): Promise<string | Buffer> { | ||
const isBase64 = typeof inputData === 'string'; | ||
const imageBuffer = isBase64 | ||
? Buffer.from(inputData.split(';base64,').pop() || inputData, 'base64') | ||
: inputData; | ||
): Promise<Buffer> { | ||
if (typeof inputData === 'string') | ||
throw Error('inputData is base64, use resizeImgBase64 instead'); | ||
const image = await Jimp.read(imageBuffer); | ||
const Jimp = await getJimp(); | ||
const image = await Jimp.read(inputData); | ||
const { width, height } = image.bitmap; | ||
@@ -75,5 +77,24 @@ | ||
return isBase64 ? resizedBuffer.toString('base64') : resizedBuffer; | ||
return resizedBuffer; | ||
} | ||
export async function resizeImgBase64( | ||
inputData: string, | ||
newSize?: { | ||
width: number; | ||
height: number; | ||
}, | ||
): Promise<string> { | ||
const splitFlag = ';base64,'; | ||
const dataSplitted = inputData.split(splitFlag); | ||
if (dataSplitted.length !== 2) { | ||
throw Error('Invalid base64 data'); | ||
} | ||
const imageBuffer = Buffer.from(dataSplitted[1], 'base64'); | ||
const buffer = await resizeImg(imageBuffer, newSize); | ||
const content = buffer.toString('base64'); | ||
return `${dataSplitted[0]}${splitFlag}${content}`; | ||
} | ||
/** | ||
@@ -135,2 +156,3 @@ * Calculates new dimensions for an image while maintaining its aspect ratio. | ||
} | null> { | ||
const Jimp = await getJimp(); | ||
const jimpImage = await Jimp.read( | ||
@@ -137,0 +159,0 @@ Buffer.isBuffer(image) ? image : Buffer.from(image), |
@@ -1,3 +0,1 @@ | ||
export default function () { | ||
return 'hello world'; | ||
} | ||
export default {}; |
101811
46
2745
7