diff --git a/CHANGELOG.md b/CHANGELOG.md index 25ee318..b53ba40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,27 @@ -## [1.0.2](https://github.com/duniul/trim-image-data/compare/v1.0.1...v1.0.2) (2020-09-04) +## 2.0.0 +### Major Changes + +- BREAKING CHANGE: `trimColor` now accepts an RGBA array instead of an object. + + - Before: `trimColor: ({ red, blue, green, alpha }) => { ... }` + - Now: `trimColor: ([red, blue, green, alpha]) => { ... }` + +- BREAKING CHANGE: the response of `trimColor` should now return return true if you _want_ the color + to be trimmed, so essentially the opposite of the previous behavior. + +### Minor Changes + +- `trimColor` now also accepts a single RGBA-array as a shorthand for a callback that returns `true` + if all channels are equal to the corresponding value in the array. + - Example: `trimColor: [255, 255, 255, 255]` (would trim white pixels) + +### Patch Changes + +- Fix default behavior of `trimImageData()`. + +## 1.0.2 ### Bug Fixes -* only include built files in the package ([ca9d7cc](https://github.com/duniul/trim-image-data/commit/ca9d7cca67c1d614983fe0b495f9945baa706ca0)) +- Only include built files in the package. diff --git a/README.md b/README.md index 90dc06b..e77d0d1 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,46 @@ specifying custom colors to trim. https://trim-image-data.netlify.app +## Usage + +```js +import trimImageData from 'trim-image-data'; + +// trim surrounding fully transparent pixels +const trimmedTransparent = trimImageData(imageData); + +// trim surrounding white pixels +const trimmedWhite = trimImageData(imageData, { + trimColor: ([red, green, blue, alpha]) => { + return red === 255 && green === 255 && blue === 255 && alpha === 255; + }; +}); + +// supports passing a RGBA array instead of a callback too +const trimmedWhite = trimImageData(imageData, { + trimColor: [255, 255, 255, 255] +}); + +// trim any pixel with max alpha +const trimmedDim = trimImageData(imageData, { + trimColor: ([alpha]) => alpha === 255 +}); +``` + ## Installation -| npm | yarn | -| ----------------------------- | --------------------------- | -| `npm install trim-image-data` | `yarn add trim-image-data`  | +```sh +# npm +npm install trim-image-data -## Usage +# yarn +yarn add trim-image-data + +# pnpm +pnpm add trim-image-data +``` + +## API ### `trimImageData(imageData, trimOptions)` @@ -29,35 +62,18 @@ not mutate the recieved instance. - `imageData` - the ImageData-instance instance to crop - `cropOptions` - optional, an object specifying the amount of pixels to crop from each side - - `trimColor({ red, green, blue, alpha }) => boolean` + + - `trimColor([red, green, blue, alpha]) => boolean` | `trimColor: [r, g, b, a]` Callback function used to determine if a value should be trimmed or not. Receives an object of RGBA channels and should return a boolean. + Also accepts a single RGBA-array as a shorthand for a callback that returns `true` if all + channels are equal to the corresponding channel in the array. + **Return value:** A new, trimmed ImageData-instance. -**Examples:** - -```js -import trimImageData from 'trim-image-data'; - -// trim surrounding fully transparent pixels -const trimmedTransparent = trimImageData(imageData); - -// trim surrounding white pixels -const trimmedWhite = trimImageData(imageData, { - trimColor: ({ red, green, blue, alpha }) => { - return red === 255 && green === 255 && blue === 255 && alpha === 255; - }; -}); - -// trim any pixel without max alpha -const trimmedDim = trimImageData(imageData, { - trimColor: ({ alpha }) => alpha === 255 -}); -``` - ## Related packages - [crop-image-data] - crops ImageData by specified number of pixels. Used as a dependency in diff --git a/package.json b/package.json index f0cf583..d5a8a80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "trim-image-data", - "version": "1.0.2", + "version": "2.0.0", "description": "Function for trimming surrounding pixels of an ImageData-instance.", "author": "Daniel Grefberg ", "license": "ISC", diff --git a/src/index.test.ts b/src/index.test.ts index 64c1481..382049c 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,5 +1,5 @@ import ImageData from '@canvas/image-data'; -import trimImageData from '.'; +import trimImageData, { RGBA } from '.'; import { getTestImageData } from '../test/testImageData'; global.ImageData = ImageData; @@ -48,7 +48,14 @@ describe('test data arrays', () => { expect(isSameData(result.data, expectedDataOut)).toBe(true); }); - it('trims custom pixels through trimColor function', () => { + it.each([ + { + label: 'callback', + trimColor: ([red, green, blue, alpha]: RGBA) => + red === 255 && green === 255 && blue === 255 && alpha === 255, + }, + { label: 'shorthand', trimColor: [255, 255, 255, 255] as [number, number, number, number] }, + ])('trims custom pixels through trimColor function ($label)', ({ trimColor }) => { // prettier-ignore const dataIn = flat([ b, b, b, b, b, b, @@ -68,10 +75,7 @@ describe('test data arrays', () => { ]); const imageData = new ImageData(Uint8ClampedArray.from(dataIn), 6, 6); - const result = trimImageData(imageData, { - trimColor: ({ red, green, blue, alpha }) => - red === 0 && green === 0 && blue === 0 && alpha === 255, - }); + const result = trimImageData(imageData, { trimColor }); expect(result.width).toEqual(4); expect(result.height).toEqual(4); diff --git a/src/index.ts b/src/index.ts index 1129e7e..a06a3b6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,27 +2,35 @@ import cropImageData, { CropOptions, ImageDataLike } from 'crop-image-data'; type ImageDataLikeData = Uint8ClampedArray | number[]; -export interface RGBA { - red: number; - green: number; - blue: number; - alpha: number; -} +export type RGBA = [number, number, number, number]; export type TrimColorFunc = (rgba: RGBA) => boolean; type Side = 'top' | 'right' | 'bottom' | 'left'; export interface TrimOptions { - trimColor: TrimColorFunc; + trimColor: TrimColorFunc | RGBA; } function getEmptyImageData() { return new ImageData(1, 1); } -function getRGBA(data: ImageDataLikeData, i: number): RGBA { - return { red: data[i], green: data[i + 1], blue: data[i + 2], alpha: data[i + 3] }; +function getRgba(data: ImageDataLikeData, i: number): RGBA { + return [data[i], data[i + 1], data[i + 2], data[i + 3]]; +} + +function getTrimColorFunc(option: TrimOptions['trimColor'] | undefined): TrimColorFunc { + if (typeof option === 'function') { + return option; + } else if (Array.isArray(option)) { + return ([r, g, b, a]) => { + return r === option[0] && g === option[1] && b === option[2] && a === option[3]; + }; + } + + // trim transparent pixels by default + return rgba => rgba[3] === 0; } function scanSide(imageData: ImageDataLike, side: Side, trimColor: TrimColorFunc) { @@ -39,8 +47,8 @@ function scanSide(imageData: ImageDataLike, side: Side, trimColor: TrimColorFunc // loop through each row for (let s = 0; s < secondaryAxis; s++) { const index = (horizontal ? width * s + p : width * p + s) * 4; - const rgba = getRGBA(data, index); - if (trimColor(rgba)) { + const rgba = getRgba(data, index); + if (!trimColor(rgba)) { // return number of columns from edge return reverse ? start - p : p; } @@ -55,7 +63,7 @@ export default function trimImageData( imageData: ImageDataLike, trimOptions?: TrimOptions ): ImageData { - const trimColor: TrimColorFunc = trimOptions?.trimColor || (({ alpha }) => !!alpha); + const trimColor: TrimColorFunc = getTrimColorFunc(trimOptions?.trimColor); const cropOptions: CropOptions = {}; const sides: Side[] = ['top', 'bottom', 'left', 'right'];