Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
npm install --save img-mage
const { Image } = require('img-mage');
const { GAUSSIAN_1D, LAPLACIAN_90 } = Image.CONSTANT;
const Gaussian1D = Image.filter(GAUSSIAN_1D, 2); // sigma=2
const Laplacian90 = Image.filter(LAPLACIAN_90);
const img = new Image().load('example.jpg');
img
.convolve1D(Gaussian1D, 'x') // apply 1D Gaussian filter along x-direction
.convolve1D(Gaussian1D, 'y') // apply 1D Gaussian filter along y-direction
.convolve2D(Laplacian90) // apply Laplacian filter
.add(img) // add back the original image
.clip() // clip overflow pixels
.save('sharpen.jpg');
const corners = img.detectCorners(2, 1000000); // sigma=2, threshold=1000000
img
.plot(corners)
.save('corners.jpg');
We introduce a robust method called map
, which enables pixel-wise manipulation. This method is designed for channel-wise processing, i.e. you can specify the index of the channels that you want to process to reduce execution time.
const height = img.getDimensions()[1];
/**
* Channel is an 2D array,
* The callback maps each pixel to a new pixel.
*/
const cb = (pixel, i, j, k, channel) => channel[height - 1 - i][j];
img.map(cb); // reflect the image along x-direction
img.map(cb, 0); // only reflect the red channel
img.map(cb, 0, 2); // only reflect the red and blue channels
// Equivalent operations
img.reflectX();
img.reflectX(0);
img.reflectX(0, 2);
const GLPF = Image.filter(Image.CONSTANT.GLPF);
img
.fourier() // fast fourier transform
.fourierMap(GLPF) // apply Gaussian low-pass filter
.inverseFourier() // fast inverse fourier transform
.clip() // clip overflow pixels
.save('blur.jpg');
It is extremely easy to implement a custom filter. If the filter is linear, you can implement it as an 2D array. If the filter is non-linear, e.g. Median filter, you can implement it as a map callback. If the filter is for frequency domain, implement it as a fourierMap callback Example.
const derivativeFilter2D = [
[1, 0, -1],
[2, 0, -2],
[1, 0, -1],
];
img.convolve2D(derivativeFilter);
const derivativeFilter1D = [1, 0, -1];
img.convolve1D(derivativeFilter1D, 'x');
// 3x3 max filter
const maxFilter = (pixel, i, j, k, channel) => {
const h = channel.length;
const w = channel[0].length;
let max = Number.NEGATIVE_INFINITY;
for (let x = -1; x <= 1; x++) {
for (let y = -1; y <= 1; y++) {
const posX = i - x;
const posY = j - y;
if (posX < 0 || posX >= h || posY < 0 || posY >= w) {
continue;
}
max = Math.max(max, channel[posX][posY]);
}
}
return max;
}
img.map(maxFilter);
//
const { Image } = require('img-mage');
const img = new Image().load('rgb.jpg');
const [width, height, depth] = img.getDimensions();
const bitDepth = img.getBitDepth();
const R = img.getChannel(0);
const [r, g, b] = img.getPixel(10, 10);
img.save('rgb2.jpg');
Map is a robust method, it provides you a flexible way to implement most of the spatial transformations. Map applies the callback to each pixel and produce a new pixel. You can specify the channels you want to apply the map function to reduce execution time. The callback takes current pixel, pixel coordinates (i, j, k), and current channel as input.
const maxIntensity = 2 ** img.getBitDepth() - 1;
const cb = (pixel) => maxIntensity - pixel;
img.map(cb); // invert whole image
img.map(cb, 0); // only invert the R channel
img.map(cb, 1, 2); // only invert the G and B channels
const img2 = new Image().load('img2.jpg'); // assume same size
const cb = (pixel, i, j, k) => pixel + img2.getChannel(k)[i][j];
img.map(cb); // add img2 to img
img.map(cb, 0); // add R channel of img2 to R channel of img
img.map(cb, 1, 2); // add G and B channels of img2 to G and B channels of img
const height = img.getDimensions()[1];
const cb = (pixel, i, j, k, channel) => channel[height - 1 - i][j];
img.map(cb); // reflect the image along x-direction
img.map(cb, 0); // only reflect the red channel
img.map(cb, 0, 2); // only reflect the red and blue channels
Apply fast fourier transform to the channels of an image and convert it to frequency domain. Apply fast inverse fourier transform to all the fourier channels of an image and convert back to the spatial domain. Note that the fourier transformation is centered.
img
.fourier()
.inverseFourier()
.clip() // Suggest to clip the pixels to ignore the floating point errors
Similar to map in spatial domain, fourierMap is the map in frequency domain. The only different is that the callback takes centerX and centerY as additional arguments, which are the center coordinate of the transformation. Note that all pixels in frequency domain are complex number. We provide a library Complex.js for you to manipulate complex numbers
const { Complex } = require('img-mage');
const cb = (pixel, i, j, k, centerX, centerY, channel) => {
const distance = Math.sqrt((i - centerX) ** 2 + (j - centerY) ** 2);
if (distance <= 100) { // cut-off frequency
return pixel;
}
return new Complex(0); // 0 in complex number
}
// apply ILPF to all channels
img
.fourier()
.fourierMap(cb)
.inverseFourier()
.clip()
.save('blur.jpg');
Get the fourier spectrum (or fourier phase) of an image.
img
.fourier()
.fourierSpectrum()
.rescale()
.logTransform()
.save('fourier-spectrum.jpg');
We provide some common linear, non-linear, and frequency domain filters. Linear filters are in the form of 1D and 2D arrays, non-linear filters are in the form of map callback, frequency domain filters are in the form of fourierMap callback. List of the filters:
Name | Argument(s) | Type | Remark |
---|---|---|---|
BOX_FILTER | size | Linear | |
LAPLACIAN_45 | No | Linear | |
LAPLACIAN_90 | No | Linear | |
GAUSSIAN_1D | sigma | Linear | |
GAUSSIAN_2D | sigma | Linear | |
MAX_FILTER | size | Non-linear | |
MIN_FILTER | size | Non-linear | |
MEDIAN_FILTER | size | Non-linear | |
ILPF | Cut-off | Frequency domain | Ideal low-pass |
GLPF | Cut-off | Frequency domain | Gaussian low-pass |
BLPF | Cut-off, order | Frequency domain | Butterworth low-pass |
IHPF | Cut-off | Frequency domain | Ideal high-pass |
GHPF | Cut-off | Frequency domain | Gaussian high-pass filter |
ILPF | Cut-off | Frequency domain | Ideal low-pass filter |
BHPF | Cut-off, order | Frequency domain | Butterworth high-pass filter |
const { BOX_FILTER, MEDIAN_FILTER, GHPF } = Image.CONSTANT;
const boxFilter = Image.filter(BOX_FILTER);
const medianFilter = Image.filter(MEDIAN_FILTER, 3); // size
const gaussianHighPass = Image.filter(GHPF, 100); // cut-off frequency
img.convolve2D(BOX_FILTER); // linear filter, thus an 2D array
img.map(MEDIAN_FILTER); // non-linear, use map
img.fourier().fourierMap(gaussianHighPass); // frequency domain, use fourierMap
Apply 1D and 2D convolution to the channels of an image. For 1D convolution, you should specify the direction of the convolution. It allows you to utilize the advantages of separating 2D filters.
const gaussian1D = Image.filter(Image.CONSTANT.GAUSSIAN_1D, 2);
const gaussian2D = Image.filter(Image.CONSTANT.GAUSSIAN_2D, 2);
const custom1D = [-1, 0, 1];
const custom2D = [
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1],
];
img
.convolve1D(gaussian1D, 'x') // x-direction
.convolve1D(gaussian1D, 'y'); // y-direction
img.convolve2D(gaussian2D); // equivalent but slower
img
.convolve1D(custom1D, 'x')
.convolve1D(custom1D, 'y'); // image derivative
img.convolve2D(custom2D);
Apply Harris corner detection algorithm to your image.
const checkerboard = new Image().load('checkboard.jpg');
const corners = checkerboard.detectCorners(2, 1000000);
checkerboard.plot(corners);
Crop an image with width w and height h at (x, y)
img.crop(0, 0, 200, 200);
img.crop(0, 0, 10000, 10000); // handle overflow for you
Rotate an image by specifying the rotation. 1 and -3 refer to clockwise 90 degrees, 2 and -2 refer to clockwise 180 degrees, 3 and -1 refer to clockwise 270 degrees.
img.rotate(1); // clockwise 90 degrees
img.rotate(-3); // equivalent
Add zero-padding to an image. The height and width of the resulting image are h + 2x and w + 2y respectively.
img.pad(10); // 10px to 4 sides
img.pad(10, 20); // 10px to top and bottom, 20px to left and right
Reflect the channels of an image vertically (x-direction) and horizontally (y-direction).
img.reflectX(); // reflect whole image
img.reflectX(0); // only reflect the R channel
img.reflectX(1, 2); // only reflect the G and B channels
Invert the channels of an image.
img.negative(); // invert whole image
img.negative(2); // only inver the B channel
img.negavie(0, 1); // Only inver the R and G channels
Apply log transform to the channels of an image. It enlarges pixel intensity.
img.logTransform(); // brighter
img.logTransform(0, 1); // more green
Apply power law transform to the channels of an image. gamma > 1 compresses the intensity while gamma < 1 enlarge the intensity.
img.powerLawTransform(0.5); // brighter
img.powerLawTransform(2); // darker
img.powerLawTransform(2, 0); // less red
Clip the overflow and underflow pixels to max intensity and 0 respectively.
img.clip(); // clip all channels
img.clip(0); // only clip the R channel
Rescale the pixels to the range [0, maxIntensity].
img.rescale();
img.rescale(1); // only rescale the G channel
Blur the channels of an image using Gaussian filter. Sigma controls the standard deviation of the distribution, larger sigma produces blurrier image.
img.blur(2); // blur the whole image
img.blur(2, 1, 2); // blur the G and B channels
Sharpen the channels of an image using Laplacian filter. Sigma controls the sharp level, smaller sharper.
img.sharpen(0.5); // more sharp
img.sharpen(2); // less sharp
Calculate the absolute value of each pixel in the channels of an image.
Apply pixel-wise addition to the channels of an image.
const Laplacian2D = Image.filter(Image.CONSTANT.LAPLACIAN_90);
img
.convolve2D(Laplacian2D) // get the edges of an image
.add(img) // add back the original image to make it sharper
Apply pixel-wise subtraction to the channels of an image.
const sharpen = new Image().load('sharpen.jpg'); // assume in same dimensions
img
.subtract(sharpen)
.abs() // get the absolute values
.rescale()
.logTransform() // make the difference more obvious
.save('difference.jpg');
Apply pixel-wise multiplication to the channels of an image.
Convert RGB to YIQ and YIQ back to RGB.
const YIQ = img.RGBtoYIQ();
YIQ.getChannel(0); // Y channel
YIQ.getChannel(1); // I channel
YIQ.getChannel(2); // Q channel
const RGB = YIQ.YIQtoRGB(); // back to RGB
MIT
FAQs
A node.js image processing library
We found that img-mage demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.