# Jimp #

The "JavaScript Image Manipulation Program" :-)

An image processing library for Node written entirely in JavaScript, with zero external or native dependencies.

Installation: `npm install --save @codelenny/jimp`

Example usage:

```js
var Jimp = require("@codelenny/jimp");

// open a file called "lenna.png"
Jimp.read("lenna.png", function (err, lenna) {
    if (err) throw err;
    lenna.resize(256, 256)            // resize
         .quality(60)                 // set JPEG quality
         .greyscale()                 // set greyscale
         .write("lena-small-bw.jpg"); // save
});
```

Using promises:

```js
Jimp.read("lenna.png").then(function (lenna) {
    lenna.resize(256, 256)            // resize
         .quality(60)                 // set JPEG quality
         .greyscale()                 // set greyscale
         .write("lena-small-bw.jpg"); // save
}).catch(function (err) {
    console.error(err);
});
```

Also available to use in web browsers and Electron applications. See [`browser/README.md`](https://github.com/oliver-moran/jimp/blob/master/browser/README.md).

## Original Work ##
This is a fork of [oliver-moran/jimp](https://github.com/oliver-moran/jimp).

Added:
- `image.print` takes an optional `color`, and fills each character with that color (see CodeLenny/jimp#1, `iss1-add-text-color`)
- `.editorconfig` file prevents editors from accidentally changing files to meet different coding styles.  (See CodeLenny/jimp#6, `iss6-editorconfig`)

Modified:
- Switched to [@codelenny/load-bmfont](https://github.com/CodeLenny/load-bmfont), as the original was out of date, and
  had poor error handling.  (See CodeLenny/jimp#3, `iss3-switch-loadbm`)
- `image.print` can take the optional maxWidth argument, but now that can be replaced with an object of multiple options.
  `maxWidth` and `color` are valid options.  (See CodeLenny/jimp#1, `iss1-add-text-color`)
- `image.print` optionally takes an array of fonts, using subsequent fonts as fallbacks if a character isn't included
  in an earlier font.  (See CodeLenny/jimp#7, `iss7-multiple-fonts`)

## Basic usage ##

The static `Jimp.read` method takes the path to a PNG, JPEG or BMP file and (optionally) a Node-style callback and returns a Promise:

```js
Jimp.read("./path/to/image.jpg", function (err, image) {
    // do stuff with the image (if no exception)
});

Jimp.read("./path/to/image.jpg").then(function (image) {
    // do stuff with the image
}).catch(function (err) {
    // handle an exception
});
```

The method can also read a PNG, JPEG or BMP buffer or from a URL:

```js
Jimp.read(lenna.buffer, function (err, image) {
    // do stuff with the image (if no exception)
});

Jimp.read("http://www.example.com/path/to/lenna.jpg", function (err, image) {
    // do stuff with the image (if no exception)
});
```


### Basic methods ###

Once the callback is filed or the promise fulfilled, the following methods can be called on the image:

```js
/* Resize */
image.contain( w, h[, alignBits || mode, mode] );    // scale the image to the given width and height, some parts of the image may be letter boxed
image.cover( w, h[, alignBits || mode, mode] );      // scale the image to the given width and height, some parts of the image may be clipped
image.resize( w, h[, mode] );     // resize the image. Jimp.AUTO can be passed as one of the values.
image.scale( f[, mode] );         // scale the image by the factor f
image.scaleToFit( w, h[, mode] ); // scale the image to the largest size that fits inside the given width and height

// An optional resize mode can be passed with all resize methods.

/* Crop */
image.autocrop();                 // automatically crop same-color borders from image (if any)
image.crop( x, y, w, h );         // crop to the given region

/* Composing */
image.blit( src, x, y[, srcx, srcy, srcw, srch] );
                                  // blit the image with another Jimp image at x, y, optionally cropped.
image.composite( src, x, y );     // composites another Jimp image over this image at x, y
image.mask( src, x, y );          // masks the image with another Jimp image at x, y using average pixel value

/* Flip and rotate */
image.flip( horz, vert );         // flip the image horizontally or vertically
image.mirror( horz, vert );       // an alias for flip
image.rotate( deg[, mode] );      // rotate the image clockwise by a number of degrees. Optionally, a resize mode can be passed. If `false` is passed as the second parameter, the image width and height will not be resized.

// JPEG images with EXIF orientation data will be automatically re-orientated as appropriate.

/* Colour */
image.brightness( val );          // adjust the brighness by a value -1 to +1
image.contrast( val );            // adjust the contrast by a value -1 to +1
image.dither565();                // ordered dithering of the image and reduce color space to 16-bits (RGB565)
image.greyscale();                // remove colour from the image
image.invert();                   // invert the image colours
image.normalize();                // normalize the channels in an image

/* Alpha channel */
image.fade( f );                  // an alternative to opacity, fades the image by a factor 0 - 1. 0 will haven no effect. 1 will turn the image
image.opacity( f );               // multiply the alpha channel by each pixel by the factor f, 0 - 1
image.opaque();                   // set the alpha channel on every pixel to fully opaque
image.background( hex );          // set the default new pixel colour (e.g. 0xFFFFFFFF or 0x00000000) for by some operations (e.g. image.contain and

/* Blurs */
image.gaussian( r );              // Gaussian blur the image by r pixels (VERY slow)
image.blur( r );                  // fast blur the image by r pixels

/* Effects */
image.posterize( n );             // apply a posterization effect with n level
image.sepia();                    // apply a sepia wash to the image
```

Some of these methods are irreversable, so it can be useful to perform them on a clone of the original image:

```js
image.clone();                    // returns a clone of the image
```

(Contributions of more methods are welcome!)

### Resize modes ###

The default rezing algorithm uses a bilinear method as follows:

```js
image.resize(250, 250);           // resize the image to 250 x 250
image.resize(Jimp.AUTO, 250);     // resize the height to 250 and scale the width accordingly
image.resize(250, Jimp.AUTO);     // resize the width to 250 and scale the height accordingly
```

Optionally, the following constants can be passed to choose a particular resizing algorithm:

```js
Jimp.RESIZE_NEAREST_NEIGHBOR;
Jimp.RESIZE_BILINEAR;
Jimp.RESIZE_BICUBIC;
Jimp.RESIZE_HERMITE;
Jimp.RESIZE_BEZIER;
```

For example:

```js
image.resize(250, 250, Jimp.RESIZE_BEZIER);
```

### Align modes ###

The following constants can be passed to image.cover and image.contain methods:

```js
Jimp.HORIZONTAL_ALIGN_LEFT;
Jimp.HORIZONTAL_ALIGN_CENTER;
Jimp.HORIZONTAL_ALIGN_RIGHT;

Jimp.VERTICAL_ALIGN_TOP;
Jimp.VERTICAL_ALIGN_MIDDLE;
Jimp.VERTICAL_ALIGN_BOTTOM;
```

For example:

```js
image.contain(250, 250, Jimp.HORIZONTAL_ALIGN_LEFT | Jimp.VERTICAL_ALIGN_TOP);
```

Default align modes are :

```js
Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE;
```

### Writing text ###

Jimp supports basic typography using BMFont format (.fnt) [bitmap fonts](https://en.wikipedia.org/wiki/Bitmap_fonts):

```js
Jimp.loadFont( path ).then(function (font) { // load font from .fnt file
    image.print(font, x, y, str);        // print a message on an image
    image.print(font, x, y, str, width); // print a message on an image with text wrapped at width
});

Jimp.loadFont( path, cb ); // using a callback pattern
```

BMFont fonts are raster based and fixed in size and colour. Jimp comes with a set of fonts that can be used on images:

```js
Jimp.FONT_SANS_8_BLACK;   // Open Sans, 8px, black
Jimp.FONT_SANS_16_BLACK;  // Open Sans, 16px, black
Jimp.FONT_SANS_32_BLACK;  // Open Sans, 32px, black
Jimp.FONT_SANS_64_BLACK;  // Open Sans, 64px, black
Jimp.FONT_SANS_128_BLACK; // Open Sans, 128px, black

Jimp.FONT_SANS_8_WHITE;   // Open Sans, 8px, white
Jimp.FONT_SANS_16_WHITE;  // Open Sans, 16px, white
Jimp.FONT_SANS_32_WHITE;  // Open Sans, 32px, white
Jimp.FONT_SANS_64_WHITE;  // Open Sans, 64px, white
Jimp.FONT_SANS_128_WHITE; // Open Sans, 128px, white
```

These can be used as follows:

```js
Jimp.loadFont(Jimp.FONT_SANS_32_BLACK).then(function (font) {
    image.print(font, 10, 10, "Hello world!");
});
```

Online tools are also available to convert TTF fonts to BMFont format (e.g. [Littera](http://kvazars.com/littera/)).

## Writing to files and buffers ##

### Writing to files ###

The image can be written to disk in PNG, JPEG or BMP format (determined by the file extension) using:

```js
image.write( path, cb ); // Node-style callback will be fired when write is successful
```

The original extension for an image (or "png") can accessed as using `image.getExtension()`. The following will save an image using its original format:

```js
var file = "new_name." + image.getExtension();
image.write(file)
```

### Writing to Buffers ###

A PNG, JPEG or BMP binary Buffer of an image (e.g. for storage in a database) can to got using:

```js
image.getBuffer( mime, cb ); // Node-style callback will be fired with result
```

For convenience, supported MIME types are available as static properties:

```js
Jimp.MIME_PNG;  // "image/png"
Jimp.MIME_JPEG; // "image/jpeg"
Jimp.MIME_BMP;  // "image/bmp"
```

If `Jimp.AUTO` is passed as the MIME type then the original MIME type for the image (or "image/png") will be used. Alernatively, `image.getMIME()` will return the original MIME type of the image (or "image/png").

### Data URI ###

A Base64 data URI can be generated in the same way as a Buffer, using:

```js
image.getBase64( mime, cb ); // Node-style callback will be fired with result
```

### PNG and JPEG quality ###

The quality of JPEGs can be set with:

```js
image.quality( n ); // set the quality of saved JPEG, 0 - 100
```

The format of PNGs can be set with:

```js
image.rgba( bool );             // set whether PNGs are saved as RGBA (true, default) or RGB (false)
image.filterType( number );     // set the filter type for the saved PNG
image.deflateLevel( number );   // set the deflate level for the saved PNG
Jimp.deflateStrategy( number ); // set the deflate for the saved PNG (0-3)
```

For convenience, supported filter types are available as static properties:

```js
Jimp.PNG_FILTER_AUTO;    // -1
Jimp.PNG_FILTER_NONE;    //  0
Jimp.PNG_FILTER_SUB;     //  1
Jimp.PNG_FILTER_UP;      //  2
Jimp.PNG_FILTER_AVERAGE; //  3
Jimp.PNG_FILTER_PAETH;   //  4
```

## Advanced usage ##

### Colour manipulation ##

Jimp supports advanced colour manipulation using a single method as follows:

```js
image.color([
    { apply: 'hue', params: [ -90 ] },
    { apply: 'lighten', params: [ 50 ] },
    { apply: 'xor', params: [ '#06D' ] }
]);
```

The method supports the following modifiers:

Modifier                | Description
----------------------- | -----------------------
**lighten** {amount}    | Lighten the color a given amount, from 0 to 100. Providing 100 will always return white (works through [TinyColor](https://github.com/bgrins/TinyColor))
**brighten** {amount}   | Brighten the color a given amount, from 0 to 100 (works through [TinyColor](https://github.com/bgrins/TinyColor))
**darken** {amount}     | Darken the color a given amount, from 0 to 100. Providing 100 will always return black (works through [TinyColor](https://github.com/bgrins/TinyColor))
**desaturate** {amount} | Desaturate the color a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale (works through [TinyColor](https://github.com/bgrins/TinyColor))
**saturate** {amount}   | Saturate the color a given amount, from 0 to 100 (works through [TinyColor](https://github.com/bgrins/TinyColor))
**greyscale** {amount}  | Completely desaturates a color into greyscale (works through [TinyColor](https://github.com/bgrins/TinyColor))
**spin** {degree}       | Spin the hue a given amount, from -360 to 360. Calling with 0, 360, or -360 will do nothing - since it sets the hue back to what it was before. (works through [TinyColor](https://github.com/bgrins/TinyColor))
**hue** {degree}        | Alias for **spin**
**mix** {color, amount} | Mixes colors by their RGB component values. Amount is opacity of overlaying color
**tint** {amount}       | Same as applying **mix** with white color
**shade** {amount}      | Same as applying **mix** with black color
**xor** {color}         | Treats the two colors as bitfields and applies an XOR operation to the red, green, and blue components
**red** {amount}        | Modify Red component by a given amount
**green** {amount}      | Modify Green component by a given amount
**blue** {amount}       | Modify Blue component by a given amount

### Low-level manipulation ###

Jimp enables low-level manipulation of images in memory through the bitmap property of each Jimp object:

```js
image.bitmap.data;  // a Buffer of the raw bitmap data
image.bitmap.width; // the width of the image
image.bitmap.height // the height of the image
```

This data can be manipulated directly but remember: garbage in, garbage out.

A helper method is available to scan a region of the bitmap:

```js
image.scan(x, y, w, h, cb); // scan a given region of the bitmap and call cb on every pixel
```

Example usage:

```js
image.scan(0, 0, image.bitmap.width, image.bitmap.height, function (x, y, idx) {
    // x, y is the position of this pixel on the image
    // idx is the position start position of this rgba tuple in the bitmap Buffer
    // this is the image

    var red   = this.bitmap.data[ idx + 0 ];
    var green = this.bitmap.data[ idx + 1 ];
    var blue  = this.bitmap.data[ idx + 2 ];
    var alpha = this.bitmap.data[ idx + 3 ];

    // rgba values run from 0 - 255
    // e.g. this.bitmap.data[idx] = 0; // removes red from this pixel
});
```

Alternatively, you can manipulate individual pixels using the following these functions:

```js
image.getPixelColor(x, y);      // returns the colour of that pixel e.g. 0xFFFFFFFF
image.setPixelColor(hex, x, y); // sets the colour of that pixel
```

Two static helper functions exist to convert RGBA values into single integer (hex) values:

```js
Jimp.rgbaToInt(r, g, b, a); // e.g. converts 255, 255, 255, 255 to 0xFFFFFFFF
Jimp.intToRGBA(hex);        // e.g. converts 0xFFFFFFFF to {r: 255, g: 255, b: 255, a:255}
```

### Creating new images ###

If you want to begin with an empty Jimp image, you can call the Jimp constructor passing the width and height of the image to create and (optionally) a Node-style callback:

```js
var image = new Jimp(256, 256, function (err, image) {
    // this image is 256 x 256, every pixel is set to 0x00000000
});
```

You can optionally set the pixel colour as follows:

```js
var image = new Jimp(256, 256, 0xFF0000FF, function (err, image) {
    // this image is 256 x 256, every pixel is set to 0xFF0000FF
});
```

## Comparing images ##

To generate a [perceptual hash](https://en.wikipedia.org/wiki/Perceptual_hashing) of a Jimp image, based on the [pHash](http://phash.org/) algorithm, use:

```js
image.hash(); // aHgG4GgoFjA
```

By default the hash is returned as base 64. The hash can be returned at another base by passing a number from 2 to 64 to the method:

```js
image.hash(2); // 1010101011010000101010000100101010010000011001001001010011100100
```

There are 18,446,744,073,709,551,615 unique hashes. The hamming distance between the binary representation of these hashes can be used to find similar-looking images.

To calculate the hamming distance between two Jimp images based on their perceptual hash use:

```js
Jimp.distance(image1, image2); // returns a number 0-1, where 0 means the two images are perceived to be identical
```

Jimp also allows the diffing of two Jimp images using [PixelMatch](https://github.com/mapbox/pixelmatch) as follows:

```js
var diff = Jimp.diff(image1, image2, threshold); // threshold ranges 0-1 (default: 0.1)
diff.image;   // a Jimp image showing differences
diff.percent; // the proportion of different pixels (0-1), where 0 means the images are pixel identical
```

Using a mix of hamming distance and pixel diffing to comare images, the following code has a 99% success rate of detecting the same image from a random sample (with 1% false positives). The test this figure is drawn from attempts to match each image from a sample of 120 PNGs against 120 corresponing JPEGs saved at a quality setting of 60.

```js
var distance = Jimp.distance(png, jpeg); // perceived distance
var diff = Jimp.diff(png, jpeg);         // pixel difference

if (distance < 0.15 || diff.percent < 0.15) {
    // images match
} else {
    // not a match
}
```

## Chaining or callbacks ##

Most instance methods can be chained together, for example as follows:

```js
Jimp.read("lenna.png", function (err, image) {
    this.greyscale().scale(0.5).write("lena-half-bw.png");
});
```

Alternatively, methods can be passed Node-style callbacks:

```js
Jimp.read("lenna.png", function (err, image) {
    image.greyscale(function(err, image) {
        image.scale(0.5, function (err, image) {
            image.write("lena-half-bw.png");
        });
    });
});
```

The Node-style callback pattern allows Jimp to be used with frameworks that expect or build on the Node-style callback pattern.

## License ##

Jimp is licensed under the MIT license. Open Sans is licensed under the Apache license.
