Comparing version 1.0.2 to 2.0.0
449
curtail.js
'use strict' | ||
import * as extract from './extract.js'; | ||
import * as math from './math.js'; | ||
import * as utils from './utils.js'; | ||
/** | ||
* Curtail is a pure JavaScript in browser canvas-based image manipulation tool. | ||
* Curtail is a pure JavaScript image manipulation tool. | ||
*/ | ||
/** | ||
* Crop an image to a specified size by providing the start location of the crop and | ||
* the dimensions that the product should have. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} path The path to the image to crop. | ||
* @param {number} x The horizontal location in the original image to begin the crop. | ||
* @param {number} y The vertical location in the original image to being the crop. | ||
* @param {number} width The width of the final cropped image. | ||
* @param {number} height The height of of the final cropped image. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promize<HTMLImageElement>} Returns the newly cropped image as an image element. | ||
*/ | ||
export class Curtail { | ||
export function crop(path, x, y, width, height, options = {}) { | ||
/** | ||
* @param {Object} [options] Options used to alter the functionality of Curtail. | ||
* @param {boolean} [autoDownload=false] Indicates whether the new image will be queued to download automatically after it is transformed. | ||
* @param {string} [crossOrigin=null] Set a cross-origin property for images loaded from non-local sources. | ||
*/ | ||
constructor(options = {}) { | ||
const _options = Object.assign({ | ||
/** | ||
* Combine the user options with the defaults for any options not set. | ||
* | ||
* @prop {Object} | ||
* @readonly | ||
*/ | ||
this._options = Object.assign({ | ||
autoDownload: false, | ||
/** | ||
* Indicates whether the image should auto-download after the edit. | ||
* | ||
* @prop {boolean} | ||
*/ | ||
autoDownload: false, | ||
crossOrigin: null | ||
/** | ||
* Sets a cross-origin property for the images used. | ||
* | ||
* @prop {string} | ||
*/ | ||
crossOrigin: null | ||
}, options); | ||
}, options); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
/** | ||
* Used when converting an image to another format, it has to be from the | ||
* following supported formats. | ||
* | ||
* @prop {Object} | ||
*/ | ||
this.FORMAT = { | ||
const fileInfo = utils.extractFileInfo(path); | ||
PNG: { ext: 'png', transparent: true }, | ||
const originalImage = new Image(); | ||
JPG: { ext: 'jpg', transparent: false }, | ||
return new Promise((resolve, reject) => { | ||
GIF: { ext: 'gif', transparent: false }, | ||
originalImage.addEventListener('load', function loadImage() { | ||
BMP: { ext: 'bmp', transparent: false }, | ||
canvas.width = width; | ||
canvas.height = height; | ||
WEBP: { ext: 'webp', transparent: true }, | ||
ctx.drawImage(originalImage, x, y, width, height, 0, 0, width, height); | ||
PDF: { ext: 'pdf', transparent: true }, | ||
const croppedImage = new Image(); | ||
}; | ||
croppedImage.addEventListener('load', function loadCroppedImage() { | ||
} | ||
if (_options.autoDownload) { | ||
/** | ||
* Crop an image down to a specified size by providing the location to being cropping | ||
* the image and the dimensions of the new desired image. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} src The path to the image to crop. | ||
* @param {number} x The x location in the original image to begin the crop. | ||
* @param {number} y The y location in the original image to begin the crop. | ||
* @param {number} width The desired width for the cropped image. | ||
* @param {number} height The desired height for the cropped image. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly cropped image. | ||
*/ | ||
crop(src, x, y, width, height) { | ||
const imageLink = document.createElement('a'); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
imageLink.href = croppedImage.src; | ||
imageLink.download = fileInfo.name + '.' + fileInfo.ext; | ||
const nameIndex = src.lastIndexOf('/') + 1 || 0; | ||
const extIndex = src.lastIndexOf('.'); | ||
imageLink.click(); | ||
const srcName = src.slice(nameIndex, extIndex); | ||
const srcExt = src.slice(extIndex + 1); | ||
} | ||
const originalImage = new Image(); | ||
croppedImage.removeEventListener('load', loadCroppedImage); | ||
return new Promise((resolve, reject) => { | ||
resolve(croppedImage); | ||
originalImage.onload = () => { | ||
}); | ||
canvas.width = width; | ||
canvas.height = height; | ||
croppedImage.addEventListener('error', function loadCroppedImageError(err) { | ||
ctx.drawImage(originalImage, x, y, width, height, 0, 0, width, height); | ||
croppedImage.removeEventListener('error', loadCroppedImage); | ||
const croppedImage = new Image(); | ||
reject(err); | ||
croppedImage.onload = () => { | ||
}); | ||
if (this._options.autoDownload) { | ||
croppedImage.src = canvas.toDataURL(`image/${fileInfo.ext}`).replace(`image/${fileInfo.ext}`, 'image/octet-stream'); | ||
let img = document.createElement('a'); | ||
}); | ||
img.href = croppedImage.src; | ||
img.download = srcName + '.' + srcExt; | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
img.click(); | ||
originalImage.removeEventListener('error', loadImageError); | ||
} | ||
reject(err); | ||
resolve(croppedImage); | ||
}); | ||
originalImage.src = path; | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
}); | ||
} | ||
/** | ||
* Convert an image from one format to another format. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} path The path to the image to convert to another format. | ||
* @param {string} format The new format for the image. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly formatted image as an image element. | ||
*/ | ||
export function convert(path, format, options = {}) { | ||
const _options = Object.assign({ | ||
autoDownload: false, | ||
crossOrigin: null | ||
}, options); | ||
const nonTransparentFormats = ['jpg', 'jpeg', 'gif', 'bmp']; | ||
const fileInfo = utils.extractFileInfo(path); | ||
if (fileInfo.ext === format) return; | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const originalImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
canvas.width = originalImage.width; | ||
canvas.height = originalImage.height; | ||
if (nonTransparentFormats.includes(format)) { | ||
ctx.fillStyle = '#FFF'; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
} | ||
ctx.drawImage(originalImage, 0, 0); | ||
const convertedImage = new Image(); | ||
convertedImage.addEventListener('load', function loadConvertedImage() { | ||
if (_options.autoDownload) { | ||
const imageLink = document.createElement('a'); | ||
imageLink.href = convertedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
croppedImage.onerror = (err) => reject(err); | ||
convertedImage.removeEventListener('load', loadConvertedImage); | ||
croppedImage.src = canvas.toDataURL(`image/${srcExt}`).replace(`image/${srcExt}`, 'image/octet-stream'); | ||
resolve(convertedImage); | ||
}; | ||
}); | ||
originalImage.onerror = (err) => reject(err); | ||
convertedImage.addEventListener('error', function loadConvertedImageError(err) { | ||
originalImage.src = src; | ||
if (this._options.crossOrigin) originalImage.crossOrigin = this._options.crossOrigin; | ||
convertedImage.removeEventListener('load', loadConvertedImageError); | ||
reject(err); | ||
}); | ||
convertedImage.src = canvas.toDataURL(`image/${format}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
/** | ||
* Convert an image from one format to another format, eg png to jpg. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} src The path to the image to convert. | ||
* @param {FORMAT} format The format, from the `curtail.FORMAT` object to convert the image to. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly converted image. | ||
*/ | ||
convert(src, format) { | ||
originalImage.removeEventListener('load', loadImageError); | ||
const fileInfo = extract.getFileInfo(src); | ||
reject(err); | ||
if (fileInfo.ext === format.ext) { | ||
}); | ||
console.warn('Image is already in desired format.'); | ||
return; | ||
originalImage.src = path; | ||
} | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
}); | ||
const originalImage = new Image(); | ||
} | ||
return new Promise((resolve, reject) => { | ||
/** | ||
* Resize an image to a new dimension. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} path The path to the image to resize. | ||
* @param {string} dimension Which dimension to resize, either width or height. Keep in mind that if you're preserving the aspect ratio, the other will resize accordingly. | ||
* @param {number} size The new size to make the specified dimension. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.preserveAspectRatio=true] Indicates whether the width and height will resize together to preserve the aspect ratio of the image. | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly resized image as an image element. | ||
*/ | ||
export function resize(path, dimension, size, options = {}) { | ||
originalImage.onload = () => { | ||
const _options = Object.assign({ | ||
canvas.width = originalImage.width; | ||
canvas.height = originalImage.height; | ||
preserveAspectRatio: true, | ||
if (!format.transparent) { | ||
autoDownload: false, | ||
ctx.fillStyle = '#FFF'; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
crossOrigin: null | ||
} | ||
}, options); | ||
ctx.drawImage(originalImage, 0, 0); | ||
const originalImage = new Image(); | ||
const newImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
newImage.onload = () => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
if (this._options.autoDownload) { | ||
const aspectRatio = utils.simplify(originalImage.width, originalImage.height); | ||
let img = document.createElement('a'); | ||
if (dimension === 'width') { | ||
img.href = newImage.src; | ||
img.download = fileInfo.name + '.' + format.ext; | ||
originalImage.width = size; | ||
img.click(); | ||
if (_options.preserveAspectRatio) originalImage.height = Math.round((aspectRatio.denominator / aspectRatio.numerator) * size); | ||
} | ||
} | ||
else if (dimension === 'height') { | ||
resolve(newImage); | ||
originalImage.height = size; | ||
}; | ||
if (_options.preserveAspectRatio) originalImage.width = Math.round((aspectRatio.numerator / aspectRatio.denominator) * size); | ||
newImage.onerror = (err) => reject(err); | ||
} | ||
newImage.src = canvas.toDataURL(`image/${format.ext}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}; | ||
if (_options.autoDownload) { | ||
originalImage.onerror = (err) => reject(err); | ||
const imageLink = document.createElement('a'); | ||
originalImage.src = src; | ||
if (this._options.crossOrigin) originalImage.crossOrigin = this._options.crossOrigin; | ||
imageLink.href = convertedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
resolve(originalImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
/** | ||
* Resize an image. | ||
* | ||
* The aspect ratio is automatically preserved when resizing an image unless | ||
* the `preserveAspectRatio` parameter is set to false. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} src The path to the image to convert. | ||
* @param {string} dimsension Whether you want to resize the width or height of the image. | ||
* @param {number} size The new size to make the specified dimension in pixels. | ||
* @param {boolean} [preserveAspectRatio=true] Indicates whether the width and height should resize together to preserve the aspect ratio of the image. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly resized image. | ||
*/ | ||
resize(src, dimension, size, preserveAspectRatio = true) { | ||
originalImage.removeEventListener('error', loadImageError); | ||
const image = new Image(); | ||
reject(err); | ||
return new Promise((resolve, reject) => { | ||
}); | ||
image.onload = () => { | ||
originalImage.src = path; | ||
const aspectRatio = math.simplify(image.width, image.height); | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
if (dimension === 'width') { | ||
}); | ||
image.width = size; | ||
} | ||
if (preserveAspectRatio) image.height = Math.round((aspectRatio[1] / aspectRatio[0]) * size); | ||
/** | ||
* Adds the specified amount of padding around an image. | ||
* | ||
* Note that the padding will not be even on images that are not square. | ||
* | ||
* @since 2.0.0 | ||
* | ||
* @param {string} path The path to the image to add padding to. | ||
* @param {number} padding The amount of padding to add to the image. | ||
* @param {Object} [options] | ||
* @param {string} [options.paddingColor='transparent'] The color that the padding will be. This value can be any valid CSS color value such as white or #FFFFFF. | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly padded image as an image element. | ||
*/ | ||
export function pad(path, padding, options = {}) { | ||
} | ||
const _options = Object.assign({ | ||
else if (dimension === 'height') { | ||
paddingColor: 'transparent', | ||
image.height = size; | ||
autoDownload: false, | ||
if (preserveAspectRatio) image.width = Math.round((aspectRatio[0] / aspectRatio[1]) * size); | ||
crossOrigin: null | ||
}, options); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const fileInfo = utils.extractFileInfo(path); | ||
const originalImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
canvas.width = originalImage.width + (padding * 2); | ||
canvas.height = originalImage.height + (padding * 2); | ||
if (_options.paddingColor !== 'transparent') { | ||
ctx.fillStyle = _options.paddingColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
} | ||
ctx.drawImage(originalImage, canvas.width / 2 - originalImage.width / 2, canvas.height / 2 - originalImage.height / 2, originalImage.width, originalImage.height); | ||
const paddedImage = new Image(); | ||
paddedImage.addEventListener('load', function loadPaddedImage() { | ||
if (_options.autoDownload) { | ||
const imageLink = document.createElement('a'); | ||
imageLink.href = paddedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
resolve(image); | ||
paddedImage.removeEventListener('load', loadPaddedImage); | ||
}; | ||
resolve(paddedImage); | ||
image.onerror = (err) => reject(err); | ||
}); | ||
image.src = src; | ||
if (this._options.crossOrigin) image.crossOrigin = this._options.crossOrigin; | ||
paddedImage.addEventListener('error', function loadPaddedImageError(err) { | ||
paddedImage.removeEventListener('load', loadPaddedImageError); | ||
reject(err); | ||
}); | ||
paddedImage.src = canvas.toDataURL(`image/${fileInfo.ext}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
originalImage.removeEventListener('error', loadImageError); | ||
reject(err); | ||
}); | ||
originalImage.src = path; | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
}); | ||
} |
'use strict' | ||
/** | ||
* The functions in extract deal with getting information from the | ||
* src path such as file name or file extension. | ||
* Extract the name of the file and the file's extension from the provided file path. | ||
* | ||
* @since 1.0.0 | ||
*/ | ||
/** | ||
* Extract the file name and extension from the provided src path. | ||
* | ||
* @since 1.0.0 | ||
* @param {string} path The user provided path to the image file. | ||
* | ||
* @param {string} src The path to the image file. | ||
* | ||
* @returns {Object} An object containing the file's name and extension. | ||
* @returns {Object} Returns an object with the file name and extension as properties and the results as the values. | ||
*/ | ||
function getFileInfo(src) { | ||
export function extractFileInfo(path) { | ||
@@ -24,14 +17,15 @@ let nameIndex = 0; | ||
let fileInfo = { | ||
name: null, | ||
ext: null | ||
}; | ||
const fileInfo = { name: null, ext: null }; | ||
if (src.lastIndexOf('/') > -1) nameIndex = src.lastIndexOf('/'); | ||
if (path.lastIndexOf('/') > -1) { | ||
extIndex = src.lastIndexOf('.'); | ||
nameIndex = path.lastIndexOf('/'); | ||
fileInfo.name = src.slice(nameIndex + 1, extIndex); | ||
fileInfo.ext = src.slice(extIndex + 1); | ||
} | ||
extIndex = path.lastIndexOf('.'); | ||
fileInfo.name = path.slice(nameIndex + 1, extIndex); | ||
fileInfo.ext = path.slice(extIndex + 1); | ||
return fileInfo; | ||
@@ -42,23 +36,16 @@ | ||
/** | ||
* The functions in math deal with any mathematical operations not | ||
* supported by native JavaScript. | ||
* Simplify a fraction by using the greatest common divisor method. | ||
* | ||
* @since 0.1.0 | ||
*/ | ||
/** | ||
* Simplify a fraction using the greatest common divisor. | ||
* | ||
* @since 0.1.0 | ||
* @param {number} numerator The top number of the fraction to simplify. | ||
* @param {number} denominator The bottom number of the fraction to simplify. | ||
* | ||
* @param {number} numerator The top number of the original fraction. | ||
* @param {number} denominator The bottom number of the original fraction. | ||
* | ||
* @returns {Array} An array consisting of the two values representing the numerator and denominator of the simplified fraction. | ||
* @returns {Object} Returns an object with the numerator/denominator as properties and the simplified results as the values. | ||
*/ | ||
function simplify(numerator, denominator) { | ||
export function simplify(numerator, denominator) { | ||
const num = gcd(numerator, denominator); | ||
const divisor = gcd(numerator, denominator); | ||
return [numerator / num, denominator / num]; | ||
return { numerator: numerator / divisor, denominator: denominator / divisor }; | ||
@@ -72,20 +59,20 @@ } | ||
* | ||
* @param {number} a The first number. | ||
* @param {number} b The second number. | ||
* @param {number} num1 The first number. | ||
* @param {number} num2 The second number. | ||
* | ||
* @returns {number} The GCD between the two numbers. | ||
* @returns {number} Returns the greatest common divisor between the two numbers. | ||
*/ | ||
function gcd(a, b) { | ||
function gcd(num1, num2) { | ||
while (b !== 0) { | ||
while (num2 !== 0) { | ||
let temp = a; | ||
let temp = num1; | ||
a = b; | ||
num1 = num2; | ||
b = temp % b; | ||
num2 = temp % num2; | ||
} | ||
return a; | ||
return num1; | ||
@@ -95,263 +82,377 @@ } | ||
/** | ||
* Curtail is a pure JavaScript in browser canvas-based image manipulation tool. | ||
* Crop an image to a specified size by providing the start location of the crop and | ||
* the dimensions that the product should have. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} path The path to the image to crop. | ||
* @param {number} x The horizontal location in the original image to begin the crop. | ||
* @param {number} y The vertical location in the original image to being the crop. | ||
* @param {number} width The width of the final cropped image. | ||
* @param {number} height The height of of the final cropped image. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promize<HTMLImageElement>} Returns the newly cropped image as an image element. | ||
*/ | ||
export class Curtail { | ||
export function crop(path, x, y, width, height, options = {}) { | ||
/** | ||
* @param {Object} [options] Options used to alter the functionality of Curtail. | ||
* @param {boolean} [autoDownload=false] Indicates whether the new image will be queued to download automatically after it is transformed. | ||
* @param {string} [crossOrigin=null] Set a cross-origin property for images loaded from non-local sources. | ||
*/ | ||
constructor(options = {}) { | ||
const _options = Object.assign({ | ||
/** | ||
* Combine the user options with the defaults for any options not set. | ||
* | ||
* @prop {Object} | ||
* @readonly | ||
*/ | ||
this._options = Object.assign({ | ||
autoDownload: false, | ||
/** | ||
* Indicates whether the image should auto-download after the edit. | ||
* | ||
* @prop {boolean} | ||
*/ | ||
autoDownload: false, | ||
crossOrigin: null | ||
/** | ||
* Sets a cross-origin property for the images used. | ||
* | ||
* @prop {string} | ||
*/ | ||
crossOrigin: null | ||
}, options); | ||
}, options); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
/** | ||
* Used when converting an image to another format, it has to be from the | ||
* following supported formats. | ||
* | ||
* @prop {Object} | ||
*/ | ||
this.FORMAT = { | ||
const fileInfo = utils.extractFileInfo(path); | ||
PNG: { ext: 'png', transparent: true }, | ||
const originalImage = new Image(); | ||
JPG: { ext: 'jpg', transparent: false }, | ||
return new Promise((resolve, reject) => { | ||
GIF: { ext: 'gif', transparent: false }, | ||
originalImage.addEventListener('load', function loadImage() { | ||
BMP: { ext: 'bmp', transparent: false }, | ||
canvas.width = width; | ||
canvas.height = height; | ||
WEBP: { ext: 'webp', transparent: true }, | ||
ctx.drawImage(originalImage, x, y, width, height, 0, 0, width, height); | ||
PDF: { ext: 'pdf', transparent: true }, | ||
const croppedImage = new Image(); | ||
}; | ||
croppedImage.addEventListener('load', function loadCroppedImage() { | ||
} | ||
if (_options.autoDownload) { | ||
/** | ||
* Crop an image down to a specified size by providing the location to being cropping | ||
* the image and the dimensions of the new desired image. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} src The path to the image to crop. | ||
* @param {number} x The x location in the original image to begin the crop. | ||
* @param {number} y The y location in the original image to begin the crop. | ||
* @param {number} width The desired width for the cropped image. | ||
* @param {number} height The desired height for the cropped image. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly cropped image. | ||
*/ | ||
crop(src, x, y, width, height) { | ||
const imageLink = document.createElement('a'); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
imageLink.href = croppedImage.src; | ||
imageLink.download = fileInfo.name + '.' + fileInfo.ext; | ||
const nameIndex = src.lastIndexOf('/') + 1 || 0; | ||
const extIndex = src.lastIndexOf('.'); | ||
imageLink.click(); | ||
const srcName = src.slice(nameIndex, extIndex); | ||
const srcExt = src.slice(extIndex + 1); | ||
} | ||
const originalImage = new Image(); | ||
croppedImage.removeEventListener('load', loadCroppedImage); | ||
return new Promise((resolve, reject) => { | ||
resolve(croppedImage); | ||
originalImage.onload = () => { | ||
}); | ||
canvas.width = width; | ||
canvas.height = height; | ||
croppedImage.addEventListener('error', function loadCroppedImageError(err) { | ||
ctx.drawImage(originalImage, x, y, width, height, 0, 0, width, height); | ||
croppedImage.removeEventListener('error', loadCroppedImage); | ||
const croppedImage = new Image(); | ||
reject(err); | ||
croppedImage.onload = () => { | ||
}); | ||
if (this._options.autoDownload) { | ||
croppedImage.src = canvas.toDataURL(`image/${fileInfo.ext}`).replace(`image/${fileInfo.ext}`, 'image/octet-stream'); | ||
let img = document.createElement('a'); | ||
}); | ||
img.href = croppedImage.src; | ||
img.download = srcName + '.' + srcExt; | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
img.click(); | ||
originalImage.removeEventListener('error', loadImageError); | ||
} | ||
reject(err); | ||
resolve(croppedImage); | ||
}); | ||
originalImage.src = path; | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
}); | ||
} | ||
/** | ||
* Convert an image from one format to another format. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} path The path to the image to convert to another format. | ||
* @param {string} format The new format for the image. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly formatted image as an image element. | ||
*/ | ||
export function convert(path, format, options = {}) { | ||
const _options = Object.assign({ | ||
autoDownload: false, | ||
crossOrigin: null | ||
}, options); | ||
const nonTransparentFormats = ['jpg', 'jpeg', 'gif', 'bmp']; | ||
const fileInfo = utils.extractFileInfo(path); | ||
if (fileInfo.ext === format) return; | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const originalImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
canvas.width = originalImage.width; | ||
canvas.height = originalImage.height; | ||
if (nonTransparentFormats.includes(format)) { | ||
ctx.fillStyle = '#FFF'; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
} | ||
ctx.drawImage(originalImage, 0, 0); | ||
const convertedImage = new Image(); | ||
convertedImage.addEventListener('load', function loadConvertedImage() { | ||
if (_options.autoDownload) { | ||
const imageLink = document.createElement('a'); | ||
imageLink.href = convertedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
croppedImage.onerror = (err) => reject(err); | ||
convertedImage.removeEventListener('load', loadConvertedImage); | ||
croppedImage.src = canvas.toDataURL(`image/${srcExt}`).replace(`image/${srcExt}`, 'image/octet-stream'); | ||
resolve(convertedImage); | ||
}; | ||
}); | ||
originalImage.onerror = (err) => reject(err); | ||
convertedImage.addEventListener('error', function loadConvertedImageError(err) { | ||
originalImage.src = src; | ||
if (this._options.crossOrigin) originalImage.crossOrigin = this._options.crossOrigin; | ||
convertedImage.removeEventListener('load', loadConvertedImageError); | ||
reject(err); | ||
}); | ||
convertedImage.src = canvas.toDataURL(`image/${format}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
/** | ||
* Convert an image from one format to another format, eg png to jpg. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} src The path to the image to convert. | ||
* @param {FORMAT} format The format, from the `curtail.FORMAT` object to convert the image to. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly converted image. | ||
*/ | ||
convert(src, format) { | ||
originalImage.removeEventListener('load', loadImageError); | ||
const fileInfo = extract.getFileInfo(src); | ||
reject(err); | ||
if (fileInfo.ext === format.ext) { | ||
}); | ||
console.warn('Image is already in desired format.'); | ||
return; | ||
originalImage.src = path; | ||
} | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
}); | ||
const originalImage = new Image(); | ||
} | ||
return new Promise((resolve, reject) => { | ||
/** | ||
* Resize an image to a new dimension. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param {string} path The path to the image to resize. | ||
* @param {string} dimension Which dimension to resize, either width or height. Keep in mind that if you're preserving the aspect ratio, the other will resize accordingly. | ||
* @param {number} size The new size to make the specified dimension. | ||
* @param {Object} [options] | ||
* @param {boolean} [options.preserveAspectRatio=true] Indicates whether the width and height will resize together to preserve the aspect ratio of the image. | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly resized image as an image element. | ||
*/ | ||
export function resize(path, dimension, size, options = {}) { | ||
originalImage.onload = () => { | ||
const _options = Object.assign({ | ||
canvas.width = originalImage.width; | ||
canvas.height = originalImage.height; | ||
preserveAspectRatio: true, | ||
if (!format.transparent) { | ||
autoDownload: false, | ||
ctx.fillStyle = '#FFF'; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
crossOrigin: null | ||
} | ||
}, options); | ||
ctx.drawImage(originalImage, 0, 0); | ||
const originalImage = new Image(); | ||
const newImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
newImage.onload = () => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
if (this._options.autoDownload) { | ||
const aspectRatio = utils.simplify(originalImage.width, originalImage.height); | ||
let img = document.createElement('a'); | ||
if (dimension === 'width') { | ||
img.href = newImage.src; | ||
img.download = fileInfo.name + '.' + format.ext; | ||
originalImage.width = size; | ||
img.click(); | ||
if (_options.preserveAspectRatio) originalImage.height = Math.round((aspectRatio.denominator / aspectRatio.numerator) * size); | ||
} | ||
} | ||
else if (dimension === 'height') { | ||
resolve(newImage); | ||
originalImage.height = size; | ||
}; | ||
if (_options.preserveAspectRatio) originalImage.width = Math.round((aspectRatio.numerator / aspectRatio.denominator) * size); | ||
newImage.onerror = (err) => reject(err); | ||
} | ||
newImage.src = canvas.toDataURL(`image/${format.ext}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}; | ||
if (_options.autoDownload) { | ||
originalImage.onerror = (err) => reject(err); | ||
const imageLink = document.createElement('a'); | ||
originalImage.src = src; | ||
if (this._options.crossOrigin) originalImage.crossOrigin = this._options.crossOrigin; | ||
imageLink.href = convertedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
resolve(originalImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
/** | ||
* Resize an image. | ||
* | ||
* The aspect ratio is automatically preserved when resizing an image unless | ||
* the `preserveAspectRatio` parameter is set to false. | ||
* | ||
* @since 0.1.0 | ||
* | ||
* @param {string} src The path to the image to convert. | ||
* @param {string} dimsension Whether you want to resize the width or height of the image. | ||
* @param {number} size The new size to make the specified dimension in pixels. | ||
* @param {boolean} [preserveAspectRatio=true] Indicates whether the width and height should resize together to preserve the aspect ratio of the image. | ||
* | ||
* @returns {Promise<HTMLImageElement>} The newly resized image. | ||
*/ | ||
resize(src, dimension, size, preserveAspectRatio = true) { | ||
originalImage.removeEventListener('error', loadImageError); | ||
const image = new Image(); | ||
reject(err); | ||
return new Promise((resolve, reject) => { | ||
}); | ||
image.onload = () => { | ||
originalImage.src = path; | ||
const aspectRatio = math.simplify(image.width, image.height); | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
if (dimension === 'width') { | ||
}); | ||
image.width = size; | ||
} | ||
if (preserveAspectRatio) image.height = Math.round((aspectRatio[1] / aspectRatio[0]) * size); | ||
/** | ||
* Adds the specified amount of padding around an image. | ||
* | ||
* Note that the padding will not be even on images that are not square. | ||
* | ||
* @since 2.0.0 | ||
* | ||
* @param {string} path The path to the image to add padding to. | ||
* @param {number} padding The amount of padding to add to the image. | ||
* @param {Object} [options] | ||
* @param {string} [options.paddingColor='transparent'] The color that the padding will be. This value can be any valid CSS color value such as white or #FFFFFF. | ||
* @param {boolean} [options.autoDownload=false] Indicates whether the image should download after the cropping is complete or not. | ||
* @param {string} [options.crossOrigin=null] Sets the cross-origin property of images originating from external sources. | ||
* | ||
* @returns {Promise<HTMLImageElement>} Returns the newly padded image as an image element. | ||
*/ | ||
export function pad(path, padding, options = {}) { | ||
} | ||
const _options = Object.assign({ | ||
else if (dimension === 'height') { | ||
paddingColor: 'transparent', | ||
image.height = size; | ||
autoDownload: false, | ||
if (preserveAspectRatio) image.width = Math.round((aspectRatio[0] / aspectRatio[1]) * size); | ||
crossOrigin: null | ||
}, options); | ||
const canvas = document.createElement('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const fileInfo = utils.extractFileInfo(path); | ||
const originalImage = new Image(); | ||
return new Promise((resolve, reject) => { | ||
originalImage.addEventListener('load', function loadImage() { | ||
canvas.width = originalImage.width + (padding * 2); | ||
canvas.height = originalImage.height + (padding * 2); | ||
if (_options.paddingColor !== 'transparent') { | ||
ctx.fillStyle = _options.paddingColor; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
} | ||
ctx.drawImage(originalImage, canvas.width / 2 - originalImage.width / 2, canvas.height / 2 - originalImage.height / 2, originalImage.width, originalImage.height); | ||
const paddedImage = new Image(); | ||
paddedImage.addEventListener('load', function loadPaddedImage() { | ||
if (_options.autoDownload) { | ||
const imageLink = document.createElement('a'); | ||
imageLink.href = paddedImage.src; | ||
imageLink.download = fileInfo.name + '.' + format; | ||
imageLink.click(); | ||
} | ||
resolve(image); | ||
paddedImage.removeEventListener('load', loadPaddedImage); | ||
}; | ||
resolve(paddedImage); | ||
image.onerror = (err) => reject(err); | ||
}); | ||
image.src = src; | ||
if (this._options.crossOrigin) image.crossOrigin = this._options.crossOrigin; | ||
paddedImage.addEventListener('error', function loadPaddedImageError(err) { | ||
paddedImage.removeEventListener('load', loadPaddedImageError); | ||
reject(err); | ||
}); | ||
paddedImage.src = canvas.toDataURL(`image/${fileInfo.ext}`); | ||
originalImage.removeEventListener('load', loadImage); | ||
}); | ||
} | ||
originalImage.addEventListener('error', function loadImageError(err) { | ||
originalImage.removeEventListener('error', loadImageError); | ||
reject(err); | ||
}); | ||
originalImage.src = path; | ||
if (_options.crossOrigin) originalImage.crossOrigin = _options.crossOrigin; | ||
}); | ||
} |
@@ -1,7 +0,10 @@ | ||
function getFileInfo$$module$Input_0(a){var b=0,d={name:null,ext:null};-1<a.lastIndexOf("/")&&(b=a.lastIndexOf("/"));var e=a.lastIndexOf(".");d.name=a.slice(b+1,e);d.ext=a.slice(e+1);return d}function simplify$$module$Input_0(a,b){var d=gcd$$module$Input_0(a,b);return[a/d,b/d]}function gcd$$module$Input_0(a,b){for(;0!==b;){var d=a;a=b;b=d%b}return a} | ||
var Curtail$$module$Input_0=function(a){a=void 0===a?{}:a;this._options=Object.assign({autoDownload:!1,crossOrigin:null},a);this.FORMAT={PNG:{ext:"png",transparent:!0},JPG:{ext:"jpg",transparent:!1},GIF:{ext:"gif",transparent:!1},BMP:{ext:"bmp",transparent:!1},WEBP:{ext:"webp",transparent:!0},PDF:{ext:"pdf",transparent:!0}}}; | ||
Curtail$$module$Input_0.prototype.crop=function(a,b,d,e,g){var c=this,f=document.createElement("canvas"),k=f.getContext("2d"),h=a.lastIndexOf("/")+1||0,l=a.lastIndexOf("."),p=a.slice(h,l),n=a.slice(l+1),m=new Image;return new Promise(function(h,l){m.onload=function(){f.width=e;f.height=g;k.drawImage(m,b,d,e,g,0,0,e,g);var a=new Image;a.onload=function(){if(c._options.autoDownload){var b=document.createElement("a");b.href=a.src;b.download=p+"."+n;b.click()}h(a)};a.onerror=function(a){return l(a)}; | ||
a.src=f.toDataURL("image/"+n).replace("image/"+n,"image/octet-stream")};m.onerror=function(a){return l(a)};m.src=a;c._options.crossOrigin&&(m.crossOrigin=c._options.crossOrigin)})}; | ||
Curtail$$module$Input_0.prototype.convert=function(a,b){var d=this,e=extract.getFileInfo(a);if(e.ext===b.ext)console.warn("Image is already in desired format.");else{var g=document.createElement("canvas"),c=g.getContext("2d"),f=new Image;return new Promise(function(k,h){f.onload=function(){g.width=f.width;g.height=f.height;b.transparent||(c.fillStyle="#FFF",c.fillRect(0,0,g.width,g.height));c.drawImage(f,0,0);var a=new Image;a.onload=function(){if(d._options.autoDownload){var c=document.createElement("a"); | ||
c.href=a.src;c.download=e.name+"."+b.ext;c.click()}k(a)};a.onerror=function(a){return h(a)};a.src=g.toDataURL("image/"+b.ext)};f.onerror=function(a){return h(a)};f.src=a;d._options.crossOrigin&&(f.crossOrigin=d._options.crossOrigin)})}}; | ||
Curtail$$module$Input_0.prototype.resize=function(a,b,d,e){var g=this;e=void 0===e?!0:e;var c=new Image;return new Promise(function(f,k){c.onload=function(){var a=math.simplify(c.width,c.height);"width"===b?(c.width=d,e&&(c.height=Math.round(a[1]/a[0]*d))):"height"===b&&(c.height=d,e&&(c.width=Math.round(a[0]/a[1]*d)));f(c)};c.onerror=function(a){return k(a)};c.src=a;g._options.crossOrigin&&(c.crossOrigin=g._options.crossOrigin)})};var module$Input_0={};module$Input_0.Curtail=Curtail$$module$Input_0; | ||
function extractFileInfo$$module$Input_0(a){var e=0,b={name:null,ext:null};-1<a.lastIndexOf("/")&&(e=a.lastIndexOf("/"));var f=a.lastIndexOf(".");b.name=a.slice(e+1,f);b.ext=a.slice(f+1);return b}function simplify$$module$Input_0(a,e){var b=gcd$$module$Input_0(a,e);return{numerator:a/b,denominator:e/b}}function gcd$$module$Input_0(a,e){for(;0!==e;){var b=a;a=e;e=b%e}return a} | ||
function crop$$module$Input_0(a,e,b,f,g,d){d=void 0===d?{}:d;var h=Object.assign({autoDownload:!1,crossOrigin:null},d),c=document.createElement("canvas"),k=c.getContext("2d"),l=utils.extractFileInfo(a),m=new Image;return new Promise(function(d,p){m.addEventListener("load",function(){c.width=f;c.height=g;k.drawImage(m,e,b,f,g,0,0,f,g);var a=new Image;a.addEventListener("load",function n(){if(h.autoDownload){var b=document.createElement("a");b.href=a.src;b.download=l.name+"."+l.ext;b.click()}a.removeEventListener("load", | ||
n);d(a)});a.addEventListener("error",function(b){a.removeEventListener("error",loadCroppedImage);p(b)});a.src=c.toDataURL("image/"+l.ext).replace("image/"+l.ext,"image/octet-stream")});m.addEventListener("error",function n(a){m.removeEventListener("error",n);p(a)});m.src=a;h.crossOrigin&&(m.crossOrigin=h.crossOrigin)})} | ||
function convert$$module$Input_0(a,e,b){b=void 0===b?{}:b;var f=Object.assign({autoDownload:!1,crossOrigin:null},b),g=["jpg","jpeg","gif","bmp"],d=utils.extractFileInfo(a);if(d.ext!==e){var h=document.createElement("canvas"),c=h.getContext("2d"),k=new Image;return new Promise(function(b,m){k.addEventListener("load",function p(){h.width=k.width;h.height=k.height;g.includes(e)&&(c.fillStyle="#FFF",c.fillRect(0,0,h.width,h.height));c.drawImage(k,0,0);var a=new Image;a.addEventListener("load",function n(){if(f.autoDownload){var c= | ||
document.createElement("a");c.href=a.src;c.download=d.name+"."+e;c.click()}a.removeEventListener("load",n);b(a)});a.addEventListener("error",function v(b){a.removeEventListener("load",v);m(b)});a.src=h.toDataURL("image/"+e);k.removeEventListener("load",p)});k.addEventListener("error",function r(a){k.removeEventListener("load",r);m(a)});k.src=a;f.crossOrigin&&(k.crossOrigin=f.crossOrigin)})}} | ||
function resize$$module$Input_0(a,e,b,f){f=void 0===f?{}:f;var g=Object.assign({preserveAspectRatio:!0,autoDownload:!1,crossOrigin:null},f),d=new Image;return new Promise(function(f,c){d.addEventListener("load",function l(){var a=utils.simplify(d.width,d.height);"width"===e?(d.width=b,g.preserveAspectRatio&&(d.height=Math.round(a.denominator/a.numerator*b))):"height"===e&&(d.height=b,g.preserveAspectRatio&&(d.width=Math.round(a.numerator/a.denominator*b)));d.removeEventListener("load",l);g.autoDownload&& | ||
(a=document.createElement("a"),a.href=convertedImage.src,a.download=fileInfo.name+"."+format,a.click());f(d)});d.addEventListener("error",function q(a){d.removeEventListener("error",q);c(a)});d.src=a;g.crossOrigin&&(d.crossOrigin=g.crossOrigin)})} | ||
function pad$$module$Input_0(a,e,b){b=void 0===b?{}:b;var f=Object.assign({paddingColor:"transparent",autoDownload:!1,crossOrigin:null},b),g=document.createElement("canvas"),d=g.getContext("2d"),h=utils.extractFileInfo(a),c=new Image;return new Promise(function(b,l){c.addEventListener("load",function q(){g.width=c.width+2*e;g.height=c.height+2*e;"transparent"!==f.paddingColor&&(d.fillStyle=f.paddingColor,d.fillRect(0,0,g.width,g.height));d.drawImage(c,g.width/2-c.width/2,g.height/2-c.height/2,c.width, | ||
c.height);var a=new Image;a.addEventListener("load",function r(){if(f.autoDownload){var c=document.createElement("a");c.href=a.src;c.download=h.name+"."+format;c.click()}a.removeEventListener("load",r);b(a)});a.addEventListener("error",function u(b){a.removeEventListener("load",u);l(b)});a.src=g.toDataURL("image/"+h.ext);c.removeEventListener("load",q)});c.addEventListener("error",function t(a){c.removeEventListener("error",t);l(a)});c.src=a;f.crossOrigin&&(c.crossOrigin=f.crossOrigin)})} | ||
var module$Input_0={};module$Input_0.extractFileInfo=extractFileInfo$$module$Input_0;module$Input_0.simplify=simplify$$module$Input_0;module$Input_0.crop=crop$$module$Input_0;module$Input_0.convert=convert$$module$Input_0;module$Input_0.resize=resize$$module$Input_0;module$Input_0.pad=pad$$module$Input_0; |
{ | ||
"name": "curtail", | ||
"version": "1.0.2", | ||
"description": "Curtail is a pure JavaScript in browser canvas-based image manipulation tool.", | ||
"version": "2.0.0", | ||
"description": "Curtail is a pure JavaScript image manipulation tool.", | ||
"main": "curtail.js", | ||
@@ -14,3 +14,5 @@ "scripts": { | ||
"keywords": [ | ||
"image", "crop", "format" | ||
"image", | ||
"crop", | ||
"format" | ||
], | ||
@@ -17,0 +19,0 @@ "author": "Robert Corponoi", |
134
readme.md
<p align="center"> | ||
<img width="250" height="250" src="./Curtail.png"> | ||
<img width="250" height="250" src="./curtail.png"> | ||
</p> | ||
@@ -7,3 +7,3 @@ | ||
<p align="center">Curtail is a pure JavaScript in browser canvas-based image manipulation tool.<p> | ||
<p align="center">Curtail is a pure JavaScript image manipulation tool.<p> | ||
@@ -28,9 +28,9 @@ <div align="center"> | ||
and to use it, you can import it as an ES6 module: | ||
Curtail doesn't have a named export so to use it as an ES6 module use the following import: | ||
```js | ||
import { Curtail } from './node_modules/curtail/curtail.js'; | ||
import * as curtail from './node_modules/curtail/curtail.js'; | ||
``` | ||
or reference the script: | ||
or reference the script from the dist folder: | ||
@@ -41,27 +41,2 @@ ```html | ||
## **Initialization** | ||
After referencing Curtail, a new instance can be created like below: | ||
```js | ||
const curtail = new Curtail(); | ||
``` | ||
Curtail does accept some optional parameters on initialization as highlighted below: | ||
| param | type | description | default | | ||
|--------------|---------|---------------------------------------------------------------------------------|---------| | ||
| autoDownload | boolean | If set to true, the newly edited file will automatically be queued to download. | false | | ||
| crossOrigin | string | Cross-origin property to set if the images are from a non-local source. | null | | ||
So let's say you would like your images to be downloaded after edits, you would initialize Curtail like: | ||
```js | ||
const options = { | ||
autoDownload: true | ||
}; | ||
const curtail = new Curtail(options); | ||
``` | ||
## **API** | ||
@@ -73,12 +48,14 @@ | ||
Curtail's crop method lets you input an image, crop location, and crop dimensions and returns a newly cropped version | ||
of the original image. | ||
The crop method takes the path to an image, a crop start location, and the final dimensons of the image and returns the newly cropped version of the original image. | ||
| param | type | description | default | | ||
|--------|--------|-------------------------------------------------|---------| | ||
| src | string | The path to the image. | | | ||
| x | number | Where to begin cropping the image horizontally. | | | ||
| y | number | Where to begin cropping the image vertically. | | | ||
| width | number | The width of the new image. | | | ||
| height | number | The height of the new image. | | | ||
| param | type | description | default | | ||
|----------------------|---------|------------------------------------------------------------------------------------|---------| | ||
| path | string | The path to the image to crop | | | ||
| x | number | The horizontal starting location of the crop | | | ||
| y | number | The vertical starting location of the crop | | | ||
| width | number | The width of the cropped image | | | ||
| height | number | The height of the cropped image | | | ||
| options | Object | | {} | | ||
| options.autoDownload | boolean | Indicates whether the image should download after the cropping is complete or not. | false | | ||
| options.crossOrigin | string | Sets the cross-origin property of images originating from external sources. | null | | ||
@@ -119,12 +96,13 @@ Using `Promise.then`: | ||
Curtail's convert method takes an image and converts it from one image format to another. | ||
The convert method takes an image and converts it from one image format to another. | ||
Note that in order to normalize format input, the `format` parameter will have to be selected from the `curtail.FORMAT` object. | ||
If you have a transparent image and convert it to a format that doesn't support transparency, the image will be placed on a white background. | ||
| param | type | description | default | | ||
|--------|----------------|-------------------------------------------------|---------| | ||
| src | string | The path to the image. | | | ||
| format | Curtail.FORMAT | Where to begin cropping the image horizontally. | | | ||
| param | type | description | default | | ||
|----------------------|---------|------------------------------------------------------------------------------------|---------| | ||
| path | string | The path to the image to crop | | | ||
| format | string | The new format for the image | | | ||
| options | Object | | {} | | ||
| options.autoDownload | boolean | Indicates whether the image should download after the cropping is complete or not. | false | | ||
| options.crossOrigin | string | Sets the cross-origin property of images originating from external sources. | null | | ||
@@ -136,3 +114,3 @@ Using `Promise.then`: | ||
// with a width of 720x480. | ||
curtail.convert('./path/to/image.png', curtail.FORMAT.JPG).then((newImage) => { | ||
curtail.convert('./path/to/image.png', 'jpg').then((newImage) => { | ||
@@ -154,3 +132,3 @@ // newImage will be your newly converted image and if autoDownload is set to true | ||
// You should probably use `try, catch` | ||
const newImage = curtail.convert('./path/to/image.png', curtail.FORMAT.JPG).catch((err) => console.log(err)); | ||
const newImage = curtail.convert('./path/to/image.png', 'jpg').catch((err) => console.log(err)); | ||
@@ -167,10 +145,13 @@ // newImage will be your newly converted image and if autoDownload is set to true | ||
Curtail's resize method takes an image and resizes it, maintaining its aspect ratio by default. | ||
The resize method takes an image and resizes it, maintaining its aspect ratio by default. | ||
| param | type | description | default | | ||
|---------------------|---------|----------------------------------------------------------------------------------------------------------|---------| | ||
| src | string | The path to the image | | | ||
| dimension | string | The side you want to resize, width or height. | | | ||
| size | number | The new size of the side to resize, in pixels. | | | ||
| preserveAspectRatio | boolean | Indicates whether the width and height should resize together to preserve the aspect ratio of the image. | true | | ||
| param | type | description | default | | ||
|-----------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------|---------| | ||
| path | string | The path to the image to crop | | | ||
| format | string | Which dimension to resize, either width or height. Keep in mind that if you're preserving the aspect ratio, the other will resize accordingly | | | ||
| size | number | The new size to make the specified dimension | | | ||
| options | Object | | {} | | ||
| options.preserveAspectRatio | boolean | Indicates whether the width and height will resize together to preserve the aspect ratio of the image | true | | ||
| options.autoDownload | boolean | Indicates whether the image should download after the cropping is complete or not. | false | | ||
| options.crossOrigin | string | Sets the cross-origin property of images originating from external sources. | null | | ||
@@ -209,4 +190,47 @@ Using `Promise.then`: | ||
### **pad** | ||
The pad method takes an image and adds the specified amount of padding to it. | ||
| param | type | description | default | | ||
|----------------------|---------|----------------------------------------------------------------------------------------------------------|---------------| | ||
| path | string | The path to the image to crop | | | ||
| padding | number | The amount of padding to add to the image | | | ||
| options | Object | | {} | | ||
| options.paddingColor | string | The color that the padding will be. This value can be any valid CSS color value such as white or #FFFFFF | 'transparent' | | ||
| options.autoDownload | boolean | Indicates whether the image should download after the cropping is complete or not. | false | | ||
| options.crossOrigin | string | Sets the cross-origin property of images originating from external sources. | null | | ||
Using `Promise.then`: | ||
```js | ||
// This will take an image and add 20px of blue padding to all sides. | ||
curtail.pad('./path/to/image.png', 20, { paddingColor: 'blue' }).then((newImage) => { | ||
// newImage will be your newly padded image and if autoDownload is set to true | ||
// then you will have a local copy downloaded at this time. | ||
}); | ||
``` | ||
Using `async/await`: | ||
```js | ||
async function main() { | ||
// This will take an image and add 20px of blue padding to all sides. | ||
// You should probably use `try, catch` | ||
const newImage = curtail.pad('./path/to/image.png', 20, { paddingColor: 'blue' }).catch((err) => console.log(err)); | ||
// newImage will be your newly padded image and if autoDownload is set to true | ||
// then you will have a local copy downloaded at this time. | ||
} | ||
main(); | ||
``` | ||
## **License** | ||
MIT |
'use strict' | ||
import { Curtail } from '../curtail.js'; | ||
import * as extract from '../extract.js'; | ||
import * as curtail from '../curtail.js'; | ||
// Test the fucionality of Curtail's image manipulation features. | ||
describe('Curtail', () => { | ||
describe('Cropping an image', () => { | ||
// Test the crop function which resizes images. | ||
describe('#crop()', () => { | ||
it('should crop an image starting at (200, 300) and end up with a new dimension of 450x540', async () => { | ||
// The specified image should be cropped at the origin but with a new dimension of 300x400. | ||
it('should crop an image at (0, 0) and result in a new dimension of 300x400', async () => { | ||
try { | ||
const curtail = new Curtail(); | ||
const crop = await curtail.crop('../test/wallpaper.png', 200, 300, 450, 540); | ||
const crop = await curtail.crop('../test/wallpaper.png', 0, 0, 300, 400).catch((err) => console.log(err)); | ||
chai.expect({ width: crop.width, height: crop.height }).to.deep.equal({ width: 450, height: 540 }); | ||
const cropDimensions = { width: crop.width, height: crop.height }; | ||
} | ||
catch (err) { | ||
chai.expect(cropDimensions).to.deep.equal({ width: 300, height: 400 }); | ||
throw new Error(err); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('Changing the format of an image', () => { | ||
it('should convert an image from png to jpg', async () => { | ||
try { | ||
const convert = await curtail.convert('../test/skeleton.png', 'jpg'); | ||
} | ||
catch (err) { | ||
throw new Error(err); | ||
} | ||
}); | ||
// Test the convert function which converts images between file types. | ||
describe('#convert()', () => { | ||
}); | ||
// The specified image should be changed from wallpaper.png to wallpaper.jpg. | ||
it('should convert the image from .png to .jpg', async () => { | ||
describe('Resizing an image', () => { | ||
const curtail = new Curtail(); | ||
it('should resize the width of an image keeping the aspect ratio', async () => { | ||
const convert = await curtail.convert('../test/wallpaper.png', curtail.FORMAT.JPG); | ||
try { | ||
}); | ||
const resize = await curtail.resize('../test/1920x1080.png', 'width', 400); | ||
chai.expect({ width: resize.width, height: resize.height }).to.deep.equal({ width: 400, height: 225 }); | ||
} | ||
catch (err) { | ||
throw new Error(err); | ||
} | ||
}); | ||
// Test the resize function which resizes images. | ||
describe('#resize()', () => { | ||
it('should resize the height of an image keeping the aspect ratio', async () => { | ||
// It sould resize the image's width and maintain the aspect ratio | ||
it('it should resize the image\'s width maintaining the aspect ratio resulting in the image being 400x225', async () => { | ||
try { | ||
const curtail = new Curtail(); | ||
const resize = await curtail.resize('../test/1920x1080.png', 'height', 225); | ||
const resize = await curtail.resize('../test/1920x1080.png', 'width', 400).catch((err) => console.log(err)); | ||
chai.expect({ width: resize.width, height: resize.height }).to.deep.equal({ width: 400, height: 225 }); | ||
const expectedSize = { width: 400, height: 225 }; | ||
} | ||
catch (err) { | ||
const actualSize = { width: resize.width, height: resize.height }; | ||
throw new Error(err); | ||
} | ||
chai.expect(actualSize).to.deep.equal(expectedSize); | ||
}); | ||
}); | ||
it('should resize the width of an image not keeping the aspect ratio', async () => { | ||
// It sould resize the image's height and maintain the aspect ratio | ||
it('it should resize the image\'s height maintaining the aspect ratio resulting in the image being 400x225', async () => { | ||
try { | ||
const curtail = new Curtail(); | ||
const resize = await curtail.resize('../test/1920x1080.png', 'width', 400, { preserveAspectRatio: false }); | ||
const resize = await curtail.resize('../test/1920x1080.png', 'height', 225).catch((err) => console.log(err)); | ||
chai.expect({ width: resize.width, height: resize.height }).to.deep.equal({ width: 400, height: 1080 }); | ||
const expectedSize = { width: 400, height: 225 }; | ||
} | ||
catch (err) { | ||
const actualSize = { width: resize.width, height: resize.height }; | ||
throw new Error(err); | ||
} | ||
chai.expect(actualSize).to.deep.equal(expectedSize); | ||
}); | ||
}); | ||
it('should resize the height of an image not keeping the aspect ratio', async () => { | ||
try { | ||
const resize = await curtail.resize('../test/1920x1080.png', 'height', 400, { preserveAspectRatio: false }); | ||
chai.expect({ width: resize.width, height: resize.height }).to.deep.equal({ width: 1920, height: 400 }); | ||
} | ||
catch (err) { | ||
throw new Error(err); | ||
} | ||
}); | ||
}); | ||
describe('Padding an image', () => { | ||
it('should add 20px padding around the image', async () => { | ||
try { | ||
const resize = await curtail.pad('../test/1920x1080.png', 20, { paddingColor: 'white ' }); | ||
chai.expect({ width: resize.width, height: resize.height }).to.deep.equal({ width: 1960, height: 1120 }); | ||
} | ||
catch (err) { | ||
throw new Error(err); | ||
} | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1090746
15
745
227
2