Added 'isImage' and 'isType' functions
This commit is contained in:
parent
f355fe3447
commit
f4f9b5c91c
@ -703,6 +703,39 @@ export function detectFileType(buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects whether the given buffer is a file of the type specified.
|
||||||
|
*
|
||||||
|
* @param {string|RegExp} type
|
||||||
|
* @param {Uint8Array} buf
|
||||||
|
* @returns {string|false} The mime type or false if the type does not match
|
||||||
|
*/
|
||||||
|
export function isType(type, buf) {
|
||||||
|
const types = detectFileType(buf);
|
||||||
|
|
||||||
|
if (!(types && types.length)) return false;
|
||||||
|
|
||||||
|
if (typeof type === "string") {
|
||||||
|
return types[0].mime.startsWith(type) ? types[0].mime : false;
|
||||||
|
} else if (type instanceof RegExp) {
|
||||||
|
return type.test(types[0].mime) ? types[0].mime : false;
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid type input.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects whether the given buffer contains an image file.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array} buf
|
||||||
|
* @returns {string|false} The mime type or false if the type does not match
|
||||||
|
*/
|
||||||
|
export function isImage(buf) {
|
||||||
|
return isType("image", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to extract a file from a data stream given its offset and extractor function.
|
* Attempts to extract a file from a data stream given its offset and extractor function.
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@ import Operation from "../Operation";
|
|||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import qr from "qr-image";
|
import qr from "qr-image";
|
||||||
import { toBase64 } from "../lib/Base64";
|
import { toBase64 } from "../lib/Base64";
|
||||||
import Magic from "../lib/Magic";
|
import { isImage } from "../lib/FileType";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,9 +100,9 @@ class GenerateQRCode extends Operation {
|
|||||||
|
|
||||||
if (format === "PNG") {
|
if (format === "PNG") {
|
||||||
let dataURI = "data:";
|
let dataURI = "data:";
|
||||||
const type = Magic.magicFileType(data);
|
const mime = isImage(data);
|
||||||
if (type && type.mime.indexOf("image") === 0){
|
if (mime){
|
||||||
dataURI += type.mime + ";";
|
dataURI += mime + ";";
|
||||||
} else {
|
} else {
|
||||||
throw new OperationError("Invalid PNG file generated by QR image");
|
throw new OperationError("Invalid PNG file generated by QR image");
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import Magic from "../lib/Magic";
|
import { isImage } from "../lib/FileType";
|
||||||
import jsqr from "jsqr";
|
import jsqr from "jsqr";
|
||||||
import jimp from "jimp";
|
import jimp from "jimp";
|
||||||
|
|
||||||
@ -42,64 +42,61 @@ class ParseQRCode extends Operation {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const type = Magic.magicFileType(input);
|
|
||||||
const [normalise] = args;
|
const [normalise] = args;
|
||||||
|
|
||||||
// Make sure that the input is an image
|
// Make sure that the input is an image
|
||||||
if (type && type.mime.indexOf("image") === 0) {
|
if (!isImage(input)) throw new OperationError("Invalid file type.");
|
||||||
let image = input;
|
|
||||||
|
|
||||||
if (normalise) {
|
let image = input;
|
||||||
// Process the image to be easier to read by jsqr
|
|
||||||
// Disables the alpha channel
|
|
||||||
// Sets the image default background to white
|
|
||||||
// Normalises the image colours
|
|
||||||
// Makes the image greyscale
|
|
||||||
// Converts image to a JPEG
|
|
||||||
image = await new Promise((resolve, reject) => {
|
|
||||||
jimp.read(Buffer.from(input))
|
|
||||||
.then(image => {
|
|
||||||
image
|
|
||||||
.rgba(false)
|
|
||||||
.background(0xFFFFFFFF)
|
|
||||||
.normalize()
|
|
||||||
.greyscale()
|
|
||||||
.getBuffer(jimp.MIME_JPEG, (error, result) => {
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
reject(new OperationError("Error reading the image file."));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image instanceof OperationError) {
|
if (normalise) {
|
||||||
throw image;
|
// Process the image to be easier to read by jsqr
|
||||||
}
|
// Disables the alpha channel
|
||||||
|
// Sets the image default background to white
|
||||||
return new Promise((resolve, reject) => {
|
// Normalises the image colours
|
||||||
jimp.read(Buffer.from(image))
|
// Makes the image greyscale
|
||||||
|
// Converts image to a JPEG
|
||||||
|
image = await new Promise((resolve, reject) => {
|
||||||
|
jimp.read(Buffer.from(input))
|
||||||
.then(image => {
|
.then(image => {
|
||||||
if (image.bitmap != null) {
|
image
|
||||||
const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
|
.rgba(false)
|
||||||
if (qrData != null) {
|
.background(0xFFFFFFFF)
|
||||||
resolve(qrData.data);
|
.normalize()
|
||||||
} else {
|
.greyscale()
|
||||||
reject(new OperationError("Couldn't read a QR code from the image."));
|
.getBuffer(jimp.MIME_JPEG, (error, result) => {
|
||||||
}
|
resolve(result);
|
||||||
} else {
|
});
|
||||||
reject(new OperationError("Error reading the image file."));
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
reject(new OperationError("Error reading the image file."));
|
reject(new OperationError("Error reading the image file."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
throw new OperationError("Invalid file type.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (image instanceof OperationError) {
|
||||||
|
throw image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
jimp.read(Buffer.from(image))
|
||||||
|
.then(image => {
|
||||||
|
if (image.bitmap != null) {
|
||||||
|
const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
|
||||||
|
if (qrData != null) {
|
||||||
|
resolve(qrData.data);
|
||||||
|
} else {
|
||||||
|
reject(new OperationError("Couldn't read a QR code from the image."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(new OperationError("Error reading the image file."));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(new OperationError("Error reading the image file."));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { fromHex } from "../lib/Hex";
|
|||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
import { detectFileType } from "../lib/FileType";
|
import { isType, detectFileType } from "../lib/FileType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PlayMedia operation
|
* PlayMedia operation
|
||||||
@ -66,8 +66,7 @@ class PlayMedia extends Operation {
|
|||||||
|
|
||||||
|
|
||||||
// Determine file type
|
// Determine file type
|
||||||
const types = detectFileType(input);
|
if (!isType(/^(audio|video)/, input)) {
|
||||||
if (!(types && types.length && /^audio|video/.test(types[0].mime))) {
|
|
||||||
throw new OperationError("Invalid or unrecognised file type");
|
throw new OperationError("Invalid or unrecognised file type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import { fromHex } from "../lib/Hex";
|
|||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
import {detectFileType} from "../lib/FileType";
|
import {isImage} from "../lib/FileType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render Image operation
|
* Render Image operation
|
||||||
@ -72,8 +72,7 @@ class RenderImage extends Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine file type
|
// Determine file type
|
||||||
const types = detectFileType(input);
|
if (!isImage(input)) {
|
||||||
if (!(types.length && types[0].mime.indexOf("image") === 0)) {
|
|
||||||
throw new OperationError("Invalid file type");
|
throw new OperationError("Invalid file type");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +91,9 @@ class RenderImage extends Operation {
|
|||||||
let dataURI = "data:";
|
let dataURI = "data:";
|
||||||
|
|
||||||
// Determine file type
|
// Determine file type
|
||||||
const types = detectFileType(data);
|
const mime = isImage(data);
|
||||||
if (types.length && types[0].mime.indexOf("image") === 0) {
|
if (mime) {
|
||||||
dataURI += types[0].mime + ";";
|
dataURI += mime + ";";
|
||||||
} else {
|
} else {
|
||||||
throw new OperationError("Invalid file type");
|
throw new OperationError("Invalid file type");
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
import Magic from "../lib/Magic";
|
import {isImage} from "../lib/FileType";
|
||||||
|
|
||||||
import jimp from "jimp";
|
import jimp from "jimp";
|
||||||
|
|
||||||
@ -38,56 +38,53 @@ class SplitColourChannels extends Operation {
|
|||||||
* @returns {List<File>}
|
* @returns {List<File>}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const type = Magic.magicFileType(input);
|
|
||||||
// Make sure that the input is an image
|
// Make sure that the input is an image
|
||||||
if (type && type.mime.indexOf("image") === 0) {
|
if (!isImage(input)) throw new OperationError("Invalid file type.");
|
||||||
const parsedImage = await jimp.read(Buffer.from(input));
|
|
||||||
|
|
||||||
const red = new Promise(async (resolve, reject) => {
|
const parsedImage = await jimp.read(Buffer.from(input));
|
||||||
try {
|
|
||||||
const split = parsedImage
|
|
||||||
.clone()
|
|
||||||
.color([
|
|
||||||
{apply: "blue", params: [-255]},
|
|
||||||
{apply: "green", params: [-255]}
|
|
||||||
])
|
|
||||||
.getBufferAsync(jimp.MIME_PNG);
|
|
||||||
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
|
|
||||||
} catch (err) {
|
|
||||||
reject(new OperationError(`Could not split red channel: ${err}`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const green = new Promise(async (resolve, reject) => {
|
const red = new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const split = parsedImage.clone()
|
const split = parsedImage
|
||||||
.color([
|
.clone()
|
||||||
{apply: "red", params: [-255]},
|
.color([
|
||||||
{apply: "blue", params: [-255]},
|
{apply: "blue", params: [-255]},
|
||||||
]).getBufferAsync(jimp.MIME_PNG);
|
{apply: "green", params: [-255]}
|
||||||
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
|
])
|
||||||
} catch (err) {
|
.getBufferAsync(jimp.MIME_PNG);
|
||||||
reject(new OperationError(`Could not split green channel: ${err}`));
|
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
|
||||||
}
|
} catch (err) {
|
||||||
});
|
reject(new OperationError(`Could not split red channel: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const blue = new Promise(async (resolve, reject) => {
|
const green = new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const split = parsedImage
|
const split = parsedImage.clone()
|
||||||
.color([
|
.color([
|
||||||
{apply: "red", params: [-255]},
|
{apply: "red", params: [-255]},
|
||||||
{apply: "green", params: [-255]},
|
{apply: "blue", params: [-255]},
|
||||||
]).getBufferAsync(jimp.MIME_PNG);
|
]).getBufferAsync(jimp.MIME_PNG);
|
||||||
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
|
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new OperationError(`Could not split blue channel: ${err}`));
|
reject(new OperationError(`Could not split green channel: ${err}`));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return await Promise.all([red, green, blue]);
|
const blue = new Promise(async (resolve, reject) => {
|
||||||
} else {
|
try {
|
||||||
throw new OperationError("Invalid file type.");
|
const split = parsedImage
|
||||||
}
|
.color([
|
||||||
|
{apply: "red", params: [-255]},
|
||||||
|
{apply: "green", params: [-255]},
|
||||||
|
]).getBufferAsync(jimp.MIME_PNG);
|
||||||
|
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
|
||||||
|
} catch (err) {
|
||||||
|
reject(new OperationError(`Could not split blue channel: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return await Promise.all([red, green, blue]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user