├── .prettierignore
├── _config.yml
├── .gitignore
├── index.js
├── .babelrc
├── images
├── output.png
├── introduction.jpg
└── react-impro.png
├── src
├── index.js
├── utils
│ ├── build.js
│ ├── storage.js
│ ├── errorMsg.js
│ ├── getDimensions.js
│ ├── modes.js
│ ├── propsFactory.js
│ └── options.js
├── worker.js
├── validators
│ └── props.js
└── components
│ └── ProcessImage.js
├── .travis.yml
├── __tests__
├── __snapshots__
│ └── index.test.js.snap
├── options.test.js
└── index.test.js
├── public
├── index.html
└── App.js
├── webpack
├── webpack.config.dev.js
└── webpack.config.js
├── Docs
├── CONTRIBUTING.MD
├── README.md
└── Api.md
├── package.json
└── README.md
/.prettierignore:
--------------------------------------------------------------------------------
1 | /src/jimp.min.js
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | .npmignore
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./build/main.js');
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "react-app"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/images/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nitin42/react-imgpro/HEAD/images/output.png
--------------------------------------------------------------------------------
/images/introduction.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nitin42/react-imgpro/HEAD/images/introduction.jpg
--------------------------------------------------------------------------------
/images/react-impro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nitin42/react-imgpro/HEAD/images/react-impro.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import ProcessImage from './components/ProcessImage';
2 |
3 | export default ProcessImage;
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | notifications:
5 | email: false
6 | script:
7 | - npm run test
--------------------------------------------------------------------------------
/src/utils/build.js:
--------------------------------------------------------------------------------
1 | import root from 'window-or-global';
2 |
3 | let ROOT =
4 | root.Jimp !== undefined && typeof root.Jimp === 'function'
5 | ? root.Jimp
6 | : undefined;
7 |
8 | export default ROOT;
9 |
--------------------------------------------------------------------------------
/src/utils/storage.js:
--------------------------------------------------------------------------------
1 | const setItem = (key, value, store) =>
2 | store !== null ? store.setItem(key, value) : null;
3 |
4 | const getItem = (key, store) => (store !== null ? store.getItem(key) : null);
5 |
6 | const removeItem = (key, store) =>
7 | store !== null ? store.removeItem(key) : null;
8 |
9 | export { getItem, removeItem, setItem };
10 |
--------------------------------------------------------------------------------
/__tests__/__snapshots__/index.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`getDimension should fallback to default 1`] = `300`;
4 |
5 | exports[`getDimension should return the image height when attribute passed is 'height' 1`] = `300`;
6 |
7 | exports[`getDimension should return the image width when attribute passed is 'width' 1`] = `400`;
8 |
--------------------------------------------------------------------------------
/src/utils/errorMsg.js:
--------------------------------------------------------------------------------
1 | const noJimpInstance = `Browser build for Jimp not found. Place this in your index.html file and restart the server -
2 |
3 | `;
4 |
5 | const webWorkerInfo =
6 | 'For better performance, set disableWebWorker to false. This will keep your UI responsive as the image will be processed in a web worker.';
7 |
8 | export { noJimpInstance, webWorkerInfo };
9 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | React App
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/webpack/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: path.resolve(__dirname, '../public/App.js'),
6 | mode: 'development',
7 | output: {
8 | filename: 'bundle.js',
9 | path: path.resolve(__dirname),
10 | publicPath: '/'
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.js$/,
16 | exclude: ['node_modules'],
17 | use: 'babel-loader'
18 | }
19 | ]
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/__tests__/options.test.js:
--------------------------------------------------------------------------------
1 | import renderer from 'react-test-renderer';
2 | import Jimp from 'jimp';
3 | import processImage from '../src/utils/options';
4 |
5 | describe('image options', () => {
6 | const image = 'http://365.unsplash.com/assets/paul-jarvis-9530891001e7f4ccfcef9f3d7a2afecd.jpg';
7 | let output = null;
8 |
9 | test('sanity check', () => {
10 | Jimp.read(image).then(image => {
11 | const output = processImage(image, { resize: { height: 300 } }, Jimp)
12 | expect(output.bitmap.height).toEqual(300);
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/src/utils/getDimensions.js:
--------------------------------------------------------------------------------
1 | let getSize = (props, original, attr) => {
2 | if (props.resize !== undefined) return props.resize[attr];
3 | if (props.crop !== undefined) return props.crop[attr];
4 | if (props.contain !== undefined) return props.contain[attr];
5 | if (props.cover !== undefined) return props.cover[attr];
6 | if (props.scaleToFit !== undefined) return props.scaleToFit[attr];
7 | if (props.style !== undefined) return props.style[attr];
8 | if (props[attr] !== undefined) return parseInt(props[attr], 10);
9 |
10 | return original;
11 | };
12 |
13 | export default getSize;
14 |
--------------------------------------------------------------------------------
/src/utils/modes.js:
--------------------------------------------------------------------------------
1 | const RESIZE_MODES = {
2 | neighbor: 'RESIZE_NEAREST_NEIGHBOR',
3 | bilinear: 'RESIZE_BILINEAR',
4 | bicubic: 'RESIZE_BICUBIC',
5 | hermite: 'RESIZE_HERMITE',
6 | bezier: 'RESIZE_BEZIER'
7 | };
8 |
9 | const ALIGN_MODES = {
10 | horizontal_left: 'HORIZONTAL_ALIGN_LEFT',
11 | horizontal_center: 'HORIZONTAL_ALIGN_CENTER',
12 | horizontal_right: 'HORIZONTAL_ALIGN_RIGHT',
13 | vertical_top: 'VERTICAL_ALIGN_TOP',
14 | vertical_middle: 'VERTICAL_ALIGN_MIDDLE',
15 | vertical_bottom: 'VERTICAL_ALIGN_BOTTOM'
16 | };
17 |
18 | module.exports = {
19 | ALIGN_MODES,
20 | RESIZE_MODES
21 | };
22 |
--------------------------------------------------------------------------------
/src/worker.js:
--------------------------------------------------------------------------------
1 | import processImage from './utils/options';
2 | const defaultCdn = 'https://unpkg.com/jimp@0.6.0/browser/lib/jimp.min.js';
3 |
4 | export function process(data) {
5 | // how to ensure Jimp can work?
6 | return new Promise((resolve, reject) => {
7 | try {
8 | if (!Jimp) {
9 | }
10 | } catch (error) {
11 | const { customCdn } = data;
12 | const cdn = customCdn ? customCdn : defaultCdn;
13 | importScripts(cdn);
14 | }
15 |
16 | Jimp.read(data.image)
17 | .then(image => {
18 | processImage(image, data.props, Jimp).getBase64(
19 | Jimp.AUTO,
20 | (err, src) => {
21 | resolve({ src, err });
22 | }
23 | );
24 | })
25 | .catch(err => {
26 | reject(err);
27 | });
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | import renderer from 'react-test-renderer';
2 | import getSize from '../src/utils/getDimensions';
3 |
4 | describe('getDimension', () => {
5 | const inp = { resize: { height: 300, width: 400 }};
6 | const def = 300;
7 |
8 | test('should return the image height when attribute passed is \'height\' ', () => {
9 | const height = getSize(inp, def, 'height');
10 |
11 | expect(height).toMatchSnapshot();
12 | })
13 |
14 | test('should return the image width when attribute passed is \'width\' ', () => {
15 | const width = getSize(inp, def, 'width');
16 |
17 | expect(width).toMatchSnapshot();
18 | });
19 |
20 | test('should fallback to default', () => {
21 | const height = getSize({}, def, 'height');
22 |
23 | expect(height).toMatchSnapshot();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/Docs/CONTRIBUTING.MD:
--------------------------------------------------------------------------------
1 | # Contributing guide
2 |
3 | I'm excited to have you helping out. Thank you so much for your time 😄
4 |
5 | ### Contributing
6 |
7 | #### Understanding the codebase
8 | `react-imgpro` uses [Jimp](https://github.com/oliver-moran/jimp) for processing the images but will later extends it support for third party OpenGL libs. So before you start working on a PR, take a look at Jimp docs and it's features.
9 |
10 | > [This](https://github.com/nitin42/react-imgpro/tree/with-comments) branch includes comments for every function and module. This may help you in understanding the codebase more easily.
11 |
12 | #### Setting up the environment
13 |
14 | Considering you've forked and cloned the repo on your system, switch to the directory and install the dependencies.
15 |
16 | ```
17 | cd react-imgpro
18 | npm install
19 | ```
20 |
21 | #### Submitting pull requests
22 |
23 | * Create a new branch for the new feature: git checkout -b new-feature
24 | * Make your changes.
25 | * Test everything with `npm run test`.
26 | * Run `npm run lint` to check the syntax errors.
27 | * Commit your changes: git commit -m 'Added some new feature'
28 | * Push to the branch: git push origin new-feature
29 | * Submit a pull request with full remarks documenting your changes.
30 |
31 |
32 | That's it! I am excited to see your pull request.
33 |
--------------------------------------------------------------------------------
/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
4 |
5 | const output = () => ({
6 | filename: '[name].js',
7 | path: path.resolve(__dirname, '../build'),
8 | publicPath: '/',
9 | libraryTarget: 'umd',
10 | globalObject: 'this'
11 | });
12 |
13 | const externals = () => ({
14 | 'browser-image-size': 'browser-image-size',
15 | react: 'react',
16 | 'prop-types': 'prop-types',
17 | 'react-progressive-image': 'react-progressive-image',
18 | 'window-or-global': 'window-or-global'
19 | });
20 |
21 | const jsLoader = () => ({
22 | test: /\.js$/,
23 | include: path.resolve(__dirname, '../src'),
24 | exclude: ['node_modules', 'public'],
25 | use: 'babel-loader'
26 | });
27 |
28 | const plugins = () => [
29 | new webpack.LoaderOptionsPlugin({
30 | minimize: true,
31 | debug: false
32 | }),
33 | new webpack.DefinePlugin({
34 | 'process.env.NODE_ENV': 'production'
35 | }),
36 | new webpack.optimize.ModuleConcatenationPlugin(),
37 | new UglifyJSPlugin()
38 | ];
39 |
40 | module.exports = {
41 | entry: path.resolve(__dirname, '../src/index.js'),
42 | mode: 'production',
43 | output: output(),
44 | target: 'web',
45 | externals: externals(),
46 | devtool: 'inline-source-map',
47 | module: {
48 | rules: [jsLoader()]
49 | },
50 | plugins: plugins()
51 | };
52 |
--------------------------------------------------------------------------------
/src/utils/propsFactory.js:
--------------------------------------------------------------------------------
1 | const filterPropsToListen = props => {
2 | const {
3 | resize,
4 | quality,
5 | greyscale,
6 | contain,
7 | cover,
8 | normalize,
9 | invert,
10 | opaque,
11 | sepia,
12 | dither565,
13 | scale,
14 | crop,
15 | scaleToFit,
16 | flip,
17 | rotate,
18 | brightness,
19 | contrast,
20 | fade,
21 | opacity,
22 | blur,
23 | posterize,
24 | colors,
25 | background
26 | } = props;
27 |
28 | return {
29 | resize,
30 | quality,
31 | greyscale,
32 | contain,
33 | cover,
34 | crop,
35 | normalize,
36 | invert,
37 | opaque,
38 | sepia,
39 | dither565,
40 | scale,
41 | scaleToFit,
42 | flip,
43 | rotate,
44 | brightness,
45 | contrast,
46 | fade,
47 | opacity,
48 | blur,
49 | posterize,
50 | colors,
51 | background
52 | };
53 | };
54 |
55 | const getImageProps = props => {
56 | const {
57 | image,
58 | resize,
59 | quality,
60 | greyscale,
61 | contain,
62 | cover,
63 | normalize,
64 | invert,
65 | opaque,
66 | sepia,
67 | dither565,
68 | scale,
69 | scaleToFit,
70 | flip,
71 | rotate,
72 | crop,
73 | brightness,
74 | contrast,
75 | fade,
76 | opacity,
77 | blur,
78 | posterize,
79 | colors,
80 | placeholder,
81 | processedImage,
82 | storage,
83 | disableWebWorker,
84 | disableRerender,
85 | customCdn,
86 | onProcessFinish,
87 | background,
88 | getImageRef,
89 | ...rest
90 | } = props;
91 |
92 | return rest;
93 | };
94 |
95 | export { filterPropsToListen, getImageProps };
96 |
--------------------------------------------------------------------------------
/public/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { render } from 'react-dom';
3 |
4 | import ProcessImage from '../src';
5 |
6 | const src = 'http://orscxqn8h.bkt.clouddn.com/18-3-3/943334.jpg';
7 |
8 | class App extends Component {
9 | state = {
10 | src: '',
11 | err: '',
12 | sepia: true,
13 | mixAmount: 10,
14 | isProcessing: false
15 | };
16 |
17 | render() {
18 | return (
19 |
20 |
{
26 | this.setState({
27 | isProcessing: false
28 | });
29 | }}
30 | colors={{
31 | mix: {
32 | color: 'mistyrose',
33 | amount: this.state.mixAmount
34 | }
35 | }}
36 | getImageRef={element => (this.image = element)}
37 | />
38 | {
41 | this.setState({
42 | sepia: !this.state.sepia,
43 | isProcessing: true
44 | });
45 | }}
46 | >
47 | test1
48 |
49 |
50 | {
53 | this.setState({
54 | mixAmount: this.state.mixAmount + 10,
55 | isProcessing: true
56 | });
57 | }}
58 | >
59 | test2
60 |
61 | {
63 | console.log(this.image);
64 | }}
65 | >
66 | log ImageRef
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | render( , document.getElementById('root'));
74 |
75 | /**
76 | * processImage prop (validation)
77 | *
78 | *
79 | */
80 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-imgpro",
3 | "version": "1.4.1",
4 | "description": "Image processing component for React",
5 | "main": "index.js",
6 | "files": [
7 | "build",
8 | "index.js"
9 | ],
10 | "keywords": [
11 | "react",
12 | "image processing",
13 | "image",
14 | "jimp",
15 | "sepia",
16 | "colors",
17 | "invert",
18 | "image component"
19 | ],
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/nitin42/react-imgpro"
23 | },
24 | "author": "Nitin Tulswani",
25 | "license": "MIT",
26 | "dependencies": {
27 | "browser-image-size": "^1.1.0",
28 | "lint-staged": "^8.0.4",
29 | "react-progressive-image": "^0.3.0",
30 | "webworkify-webpack": "^2.0.5",
31 | "window-or-global": "^1.0.1"
32 | },
33 | "peerDependencies": {
34 | "react": "^16.0.0"
35 | },
36 | "resolutions": {
37 | "babel-core": "7.0.0-bridge.0"
38 | },
39 | "devDependencies": {
40 | "@babel/core": "7.0.0-beta.46",
41 | "@babel/runtime": "7.0.0-beta.46",
42 | "babel-eslint": "^7.2.3",
43 | "babel-jest": "^23.4.2",
44 | "babel-loader": "^8.0.0",
45 | "babel-plugin-macros": "2.2.1",
46 | "babel-plugin-transform-dynamic-import": "2.0.0",
47 | "babel-plugin-transform-react-remove-prop-types": "0.4.13",
48 | "babel-preset-react-app": "^4.0.0-next.a671462c",
49 | "babili-webpack-plugin": "^0.1.2",
50 | "husky": "^0.14.3",
51 | "jest": "^23.5.0",
52 | "jimp": "^0.5.6",
53 | "prettier": "^1.11.1",
54 | "prop-types": "^15.5.10",
55 | "react": "^16.0.0",
56 | "react-dom": "^16.0.0",
57 | "react-test-renderer": "^16.0.0",
58 | "uglifyjs-webpack-plugin": "^1.3.0",
59 | "webpack": "^4.17.2",
60 | "webpack-cli": "^3.1.0",
61 | "webpack-dev-server": "^3.1.8",
62 | "worker-loader": "^2.0.0",
63 | "workerize-loader": "^1.0.4"
64 | },
65 | "scripts": {
66 | "start": "NODE_ENV=production ./node_modules/.bin/webpack-dev-server --content-base ./public --config ./webpack/webpack.config.dev.js",
67 | "prebuild": "rm -rf ./build",
68 | "build": "NODE_ENV=production ./node_modules/.bin/webpack --config ./webpack/webpack.config.js --progress",
69 | "test": "jest",
70 | "test:watch": "jest --watch",
71 | "format": "prettier --write --single-quote \"src/**/*.js\"",
72 | "precommit": "lint-staged"
73 | },
74 | "lint-staged": {
75 | "*.js": [
76 | "prettier --write --single-quote \"src/**/*.js\"",
77 | "git add"
78 | ]
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Docs/README.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | ## Table of content
4 |
5 | * [Introduction](https://github.com/nitin42/react-imgpro#introduction)
6 | * [Motivation](https://github.com/nitin42/react-imgpro#motivation)
7 | * [Demo](https://github.com/nitin42/react-imgpro#demo)
8 | * [Install](https://github.com/nitin42/react-imgpro#install)
9 | * [Usage](https://github.com/nitin42/react-imgpro#usage)
10 | * [API Reference](./Api.md)
11 | * [ProcessImage component](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#component)
12 | * [props](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#props)
13 | * [resize](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#resize)
14 | * [crop](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#crop)
15 | * [quality](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#quality)
16 | * [greyscale](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#greyscale)
17 | * [normalize](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#normalize)
18 | * [invert](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#invert)
19 | * [opaque](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#opaque)
20 | * [sepia](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#sepia)
21 | * [dither565](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#dither565)
22 | * [scale](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#scale)
23 | * [scaleToFit](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#scaletofitimage)
24 | * [flip](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#flip)
25 | * [rotate](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#rotate)
26 | * [brightness](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#brightness)
27 | * [contrast](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#contrast)
28 | * [fade](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#fade)
29 | * [opacity](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#opacity)
30 | * [blur](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#blur)
31 | * [posterize](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#posterize)
32 | * [cover](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#cover)
33 | * [contain](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#contain)
34 | * [colors](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#colors)
35 | * [storage](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#storage)
36 | * [disableWebWorker](https://github.com/nitin42/react-imgpro/blob/master/Docs/Api.md#disablewebworker)
37 | * [Contributing](./CONTRIBUTING.MD)
38 |
--------------------------------------------------------------------------------
/src/validators/props.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | const resizePropType = PropTypes.shape({
4 | width: PropTypes.number,
5 | height: PropTypes.number,
6 | mode: PropTypes.string
7 | });
8 |
9 | const containPropType = PropTypes.shape({
10 | width: PropTypes.number,
11 | height: PropTypes.number,
12 | mode: PropTypes.string
13 | });
14 |
15 | const coverPropType = PropTypes.shape({
16 | width: PropTypes.number,
17 | height: PropTypes.number,
18 | mode: PropTypes.string
19 | });
20 |
21 | const scaleToFitPropType = PropTypes.shape({
22 | width: PropTypes.number,
23 | height: PropTypes.number
24 | });
25 |
26 | const flipPropType = PropTypes.shape({
27 | horizontal: PropTypes.bool,
28 | vertical: PropTypes.bool
29 | });
30 |
31 | const rotatePropType = PropTypes.shape({
32 | degree: PropTypes.number,
33 | mode: PropTypes.string
34 | });
35 |
36 | const cropPropType = PropTypes.shape({
37 | x: PropTypes.number,
38 | y: PropTypes.number,
39 | w: PropTypes.number,
40 | h: PropTypes.number
41 | });
42 |
43 | const mixPropType = PropTypes.shape({
44 | color: PropTypes.string,
45 | amount: PropTypes.number
46 | });
47 |
48 | const xorPropType = PropTypes.shape({
49 | color: PropTypes.string,
50 | amount: PropTypes.number
51 | });
52 |
53 | const colorsPropType = PropTypes.shape({
54 | lighten: PropTypes.number,
55 | brighten: PropTypes.number,
56 | darken: PropTypes.number,
57 | desaturate: PropTypes.number,
58 | saturate: PropTypes.number,
59 | greyscale: PropTypes.number,
60 | spin: PropTypes.number,
61 | mix: mixPropType,
62 | tint: PropTypes.number,
63 | shade: PropTypes.number,
64 | xor: xorPropType,
65 | red: PropTypes.number,
66 | green: PropTypes.number,
67 | blue: PropTypes.number
68 | });
69 |
70 | const MainPropTypes = {
71 | blur: PropTypes.number,
72 | brightness: PropTypes.number,
73 | contain: containPropType,
74 | cover: coverPropType,
75 | contrast: PropTypes.number,
76 | colors: colorsPropType,
77 | dither565: PropTypes.bool,
78 | flip: flipPropType,
79 | crop: cropPropType,
80 | fade: PropTypes.number,
81 | greyscale: PropTypes.bool,
82 | invert: PropTypes.bool,
83 | image: PropTypes.any.isRequired,
84 | normalize: PropTypes.bool,
85 | opacity: PropTypes.number,
86 | posterize: PropTypes.number,
87 | processedImage: PropTypes.func,
88 | opaque: PropTypes.bool,
89 | quality: PropTypes.number,
90 | rotate: rotatePropType,
91 | resize: resizePropType,
92 | sepia: PropTypes.bool,
93 | scale: PropTypes.number,
94 | scaleToFit: scaleToFitPropType,
95 | disableRerender: PropTypes.bool,
96 | customCdn: PropTypes.string,
97 | onProcessFinish: PropTypes.func,
98 | getImageRef: PropTypes.func
99 | };
100 |
101 | export default MainPropTypes;
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **This project is no longer maintained.**
2 |
3 | # react-imgpro
4 |
5 | [](https://travis-ci.org/nitin42/react-imgpro)
6 | 
7 | 
8 | 
9 | 
10 |
11 | > Image Processing Component for React
12 |
13 |
14 |
15 |
16 |
17 | ## Introduction
18 |
19 | `react-imgpro` is a image processing component for React. This component process an image with filters supplied as props and returns a [base64](https://en.wikipedia.org/wiki/Base64) image.
20 |
21 | **Example**
22 |
23 | ```jsx
24 |
25 | const mix = {
26 | color: 'mistyrose',
27 | amount: 10
28 | }
29 |
30 | class App extends React.Component {
31 | state = { src: '', err: null }
32 | render() {
33 | return (
34 | this.setState({ src, err, })}
41 | />
42 | )
43 | }
44 | }
45 | ```
46 |
47 |
48 |
49 |
50 |
51 | ## Motivation
52 |
53 |
54 |
55 |
56 |
57 | I was working on a project last month which involved a lot of image processing and I'd to rely on third party libraries. But before using them directly, I'd to learn different concepts in gl (shaders) and then try to implement them in React. The difficult part was not learning but it was the verbosity, boilerplate code and redundancy introduced by the libraries in the codebase. It was getting difficult to organise all the things 😞
58 |
59 | So I wanted a layer of abstraction which would make it easy to manipulate the colors of the image, applying filters and gl shaders efficiently with ease. And React's component based model was perfect for hiding all the implementation details in a component 😄
60 |
61 | ## Demo
62 |
63 |
64 |
65 |
66 |
67 | ## Install
68 |
69 | ```
70 | npm install react-imgpro
71 | ```
72 |
73 | This also depends on `react` so make sure you've installed it.
74 |
75 | OR
76 |
77 | The UMD build is also available via [jsDelivr](https://www.jsdelivr.com).
78 |
79 | ```
80 |
81 |
82 | ```
83 |
84 | ## Usage
85 |
86 | ```jsx
87 | import React from 'react';
88 | import ProcessImage from 'react-imgpro';
89 |
90 | class App extends React.Component {
91 | state = {
92 | src: '',
93 | err: null
94 | }
95 |
96 | render() {
97 | return (
98 | this.setState({ src, err})}
108 | />
109 | )
110 | }
111 | }
112 |
113 | ```
114 |
115 | ## Documentation
116 |
117 | See the detailed documentation [here](./Docs).
118 |
119 | ## SSR support ?
120 |
121 | Yes, `react-imgpro` supports SSR.
122 |
123 | ## Contributing
124 |
125 | [Contributing guide](https://github.com/nitin42/react-imgpro/blob/master/Docs/CONTRIBUTING.MD).
126 |
127 | ## Extra resources
128 |
129 | If you want to use blenders, plugins and perform event based calculations, try [CamanJS](http://camanjs.com/).
130 |
131 | ## License
132 |
133 | MIT
134 |
135 |
136 |
--------------------------------------------------------------------------------
/src/components/ProcessImage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ProgressiveImage from 'react-progressive-image';
3 | import size from 'browser-image-size';
4 | import work from 'webworkify-webpack';
5 | import root from 'window-or-global';
6 | import { filterPropsToListen, getImageProps } from '../utils/propsFactory';
7 | import getSize from '../utils/getDimensions';
8 | import { noJimpInstance, webWorkerInfo } from '../utils/errorMsg';
9 | import { setItem, getItem, removeItem } from '../utils/storage';
10 | import ROOT from '../utils/build';
11 | import MainPropTypes from '../validators/props';
12 | import worker from 'workerize-loader?inline!../worker';
13 | import processImage from '../utils/options';
14 |
15 | class ProcessImage extends Component {
16 | static propTypes = MainPropTypes;
17 |
18 | static defaultProps = {
19 | storage: true,
20 | greyscale: false,
21 | normalize: false,
22 | invert: false,
23 | opaque: false,
24 | sepia: false,
25 | dither565: false,
26 | disableWebWorker: false
27 | };
28 |
29 | state = {
30 | src: '',
31 | err: '',
32 | height: null,
33 | width: null
34 | };
35 |
36 | componentWillMount = () => {
37 | this.checkStorageSupport();
38 |
39 | if (typeof Worker !== 'undefined' && !this.props.disableWebWorker) {
40 | this.worker = worker();
41 | }
42 | };
43 |
44 | componentDidMount = () => {
45 | this.getOriginalImageSize(this.props);
46 |
47 | this.processInMainThreadOrInWebWorker(
48 | this.worker,
49 | this.props,
50 | this.myStorage
51 | );
52 | };
53 |
54 | componentDidUpdate = () => {
55 | if (this.props.image && !this.props.disableRerender) {
56 | this.processInMainThreadOrInWebWorker(
57 | this.worker,
58 | this.props,
59 | this.myStorage
60 | );
61 | }
62 | };
63 |
64 | componentWillUnmount = () => {
65 | this.worker !== null ? this.worker.terminate() : null;
66 |
67 | removeItem('placeholder', this.myStorage);
68 | };
69 |
70 | checkStorageSupport = () => {
71 | if (typeof Storage !== 'undefined' && this.props.storage) {
72 | return (this.myStorage = root.localStorage);
73 | } else if (!this.props.storage && typeof Storage !== 'undefined') {
74 | this.clearStorage();
75 | return (this.myStorage = null);
76 | }
77 |
78 | return (this.myStorage = null);
79 | };
80 |
81 | passPropsToParent = (props, src, err) =>
82 | props.processedImage !== undefined ? props.processedImage(src, err) : null;
83 |
84 | processInMainThreadOrInWebWorker = (worker, props, storageReference) => {
85 | if (typeof Worker !== 'undefined' && !props.disableWebWorker) {
86 | return this.processInWebWorker(worker, props, storageReference);
87 | } else {
88 | if (ROOT !== undefined && props.disableWebWorker) {
89 | console.info(webWorkerInfo);
90 | return this.processInMainThread(props);
91 | } else {
92 | return console.error(noJimpInstance);
93 | }
94 | }
95 | };
96 |
97 | clearStorage = () => root.localStorage.removeItem('placeholder');
98 |
99 | getOriginalImageSize = props => {
100 | size(props.image)
101 | .then(size => this.setState({ height: size.height, width: size.width }))
102 | .catch(() => {
103 | if (props.processedImage) {
104 | const err = new Error('Unable to get original size of image');
105 | props.processedImage('', err);
106 | }
107 | });
108 | };
109 |
110 | getDefaultImageSize = props => {
111 | const { height, width } = this.state;
112 |
113 | return {
114 | height: getSize(props, height, 'height'),
115 | width: getSize(props, width, 'width')
116 | };
117 | };
118 |
119 | myStorage = null;
120 |
121 | processInMainThread = props => {
122 | ROOT.read(props.image)
123 | .then(image => {
124 | processImage(image, props, ROOT).getBase64(ROOT.AUTO, (err, src) => {
125 | if (this.state.src !== src || this.state.err !== err) {
126 | this.setState({ src, err });
127 | this.passPropsToParent(props, src, err);
128 | if (typeof props.onProcessFinish === 'function') {
129 | props.onProcessFinish();
130 | }
131 | }
132 | });
133 | })
134 | .catch(err => {
135 | this.passPropsToParent(props, '', result.err);
136 | if (typeof props.onProcessFinish === 'function') {
137 | props.onProcessFinish();
138 | }
139 | return;
140 | });
141 | };
142 |
143 | processInWebWorker = async (worker, props, storageReference) => {
144 | if (worker !== null) {
145 | const result = await worker
146 | .process({
147 | props: filterPropsToListen(props),
148 | image: props.image,
149 | customCdn: props.customCdn
150 | })
151 | .catch(err => ({ err }));
152 |
153 | if (typeof result.src === 'undefined' && result.err) {
154 | this.passPropsToParent(props, '', result.err);
155 | if (typeof props.onProcessFinish === 'function') {
156 | props.onProcessFinish();
157 | }
158 | return;
159 | }
160 |
161 | if (result.src !== this.state.src || result.err !== this.state.err) {
162 | this.setState({ src: result.src, err: result.err });
163 | setItem('placeholder', result.src, storageReference);
164 | this.passPropsToParent(props, result.src, result.err);
165 | if (typeof props.onProcessFinish === 'function') {
166 | props.onProcessFinish();
167 | }
168 | }
169 | }
170 | };
171 |
172 | worker = null;
173 |
174 | processedImage = (image, restProps, style, getImageRef) => (
175 |
176 | );
177 |
178 | placeholderImage = image =>
179 | getItem('placeholder', this.myStorage) === null
180 | ? image
181 | : getItem('placeholder', this.myStorage);
182 |
183 | showImage = (img, props, restProps) => (
184 |
188 | {image =>
189 | this.processedImage(
190 | image,
191 | restProps,
192 | this.getDefaultImageSize(props),
193 | props.getImageRef
194 | )
195 | }
196 |
197 | );
198 |
199 | render() {
200 | const { src } = this.state;
201 | const restProps = getImageProps(this.props);
202 | return this.showImage(src, this.props, restProps);
203 | }
204 | }
205 |
206 | export default ProcessImage;
207 |
--------------------------------------------------------------------------------
/src/utils/options.js:
--------------------------------------------------------------------------------
1 | const { ALIGN_MODES, RESIZE_MODES } = require('./modes');
2 |
3 | function processImage(image, props, ROOT) {
4 | const {
5 | resize,
6 | quality,
7 | greyscale,
8 | contain,
9 | cover,
10 | normalize,
11 | invert,
12 | opaque,
13 | sepia,
14 | dither565,
15 | scale,
16 | scaleToFit,
17 | flip,
18 | rotate,
19 | brightness,
20 | contrast,
21 | fade,
22 | opacity,
23 | blur,
24 | posterize,
25 | crop,
26 | background
27 | } = props;
28 |
29 | function MODE(algorithm) {
30 | return ROOT[algorithm];
31 | }
32 |
33 | function getMode(prop, modes) {
34 | return prop !== undefined ? modes[prop.mode] : null;
35 | }
36 |
37 | function setMode(prop, modes, autoMode) {
38 | return MODE(getMode(prop, modes)) || autoMode;
39 | }
40 |
41 | const AUTOMEASURE = ROOT.AUTO;
42 |
43 | const setter = (value, fallbackTo) =>
44 | value !== undefined ? value : fallbackTo;
45 |
46 | image.__proto__.pass = function(image) {
47 | return image;
48 | };
49 |
50 | function setFilterOrForwardTheImage(filter, img, fn) {
51 | return filter ? img[fn]() : image.pass(img);
52 | }
53 |
54 | function scaleImageWithoutMode(prop, img, scaleMode) {
55 | return prop !== undefined && Object.keys(prop).length > 0
56 | ? img[scaleMode](
57 | prop.width,
58 | prop.height,
59 | setMode(prop, ALIGN_MODES, ROOT.HORIZONTAL_ALIGN_CENTER)
60 | )
61 | : image.pass(image);
62 | }
63 |
64 | function changeImageAppearence(prop, img, filter) {
65 | return prop !== undefined ? img[filter](prop) : image.pass(img);
66 | }
67 |
68 | function colorManipulation(props) {
69 | const setConfig = [];
70 |
71 | if (props.colors !== undefined) {
72 | Object.keys(props.colors).forEach(option => {
73 | const setAmountWithColor = ['mix', 'xor'];
74 |
75 | if (setAmountWithColor.includes(option)) {
76 | const schemaOne = {
77 | apply: option,
78 | params: [props.colors[option].color, props.colors[option].amount]
79 | };
80 |
81 | setConfig.push(schemaOne);
82 | }
83 |
84 | const schemaTwo = {
85 | apply: option,
86 | params: [props.colors[option]]
87 | };
88 |
89 | setConfig.push(schemaTwo);
90 | });
91 | return setConfig;
92 | }
93 |
94 | return [];
95 | }
96 |
97 | image.__proto__.resizeAnImage = function(image, resize) {
98 | return resize !== undefined && Object.keys(resize).length > 0
99 | ? image.resize(
100 | setter(resize.width, AUTOMEASURE),
101 | setter(resize.height, AUTOMEASURE),
102 | setMode(resize, RESIZE_MODES, ROOT.RESIZE_BILINEAR)
103 | )
104 | : image.pass(image);
105 | };
106 |
107 | image.__proto__.cropImage = function(image, crop) {
108 | return crop !== undefined
109 | ? image.crop(
110 | setter(crop.x, AUTOMEASURE),
111 | setter(crop.y, AUTOMEASURE),
112 | setter(crop.width, 0),
113 | setter(crop.height, 0)
114 | )
115 | : image.pass(image);
116 | };
117 |
118 | image.__proto__.changeImageQuality = function(image, quality) {
119 | return changeImageAppearence(quality, image, 'quality');
120 | };
121 |
122 | image.__proto__.applyGreyscale = function(image, greyscale) {
123 | return setFilterOrForwardTheImage(greyscale, image, 'greyscale');
124 | };
125 |
126 | image.__proto__.normalizeImage = function(image, normalize) {
127 | return setFilterOrForwardTheImage(normalize, image, 'normalize');
128 | };
129 |
130 | image.__proto__.invertImage = function(image, invert) {
131 | return setFilterOrForwardTheImage(invert, image, 'invert');
132 | };
133 |
134 | image.__proto__.opaqueImage = function(image, opaque) {
135 | return setFilterOrForwardTheImage(opaque, image, 'opaque');
136 | };
137 |
138 | image.__proto__.sepiaFilter = function(image, sepia) {
139 | return setFilterOrForwardTheImage(sepia, image, 'sepia');
140 | };
141 |
142 | image.__proto__.ditherFilter = function(image, dither565) {
143 | return setFilterOrForwardTheImage(dither565, image, 'dither565');
144 | };
145 |
146 | image.__proto__.scaleImage = function(image, scale) {
147 | return changeImageAppearence(scale, image, 'scale');
148 | };
149 |
150 | image.__proto__.scaleToFitImage = function(image, scaleToFit) {
151 | return scaleToFit !== undefined
152 | ? image.scaleToFit(
153 | setter(scaleToFit.width, AUTOMEASURE),
154 | setter(scaleToFit.height, AUTOMEASURE)
155 | )
156 | : image.pass(image);
157 | };
158 |
159 | image.__proto__.flipImage = function(image, flip) {
160 | return flip !== undefined
161 | ? image.flip(setter(flip.horizontal, false), setter(flip.vertical, false))
162 | : image.pass(image);
163 | };
164 |
165 | image.__proto__.rotateImage = function(image, rotate) {
166 | return rotate !== undefined
167 | ? image.rotate(
168 | setter(rotate.degree, 0),
169 | setMode(rotate, RESIZE_MODES, false)
170 | )
171 | : image.pass(image);
172 | };
173 |
174 | image.__proto__.applyBackground = function(image, background) {
175 | return background !== undefined
176 | ? image.background(background)
177 | : image.pass(image);
178 | };
179 |
180 | image.__proto__.changeBrightness = function(image, brightness) {
181 | return changeImageAppearence(brightness, image, 'brightness');
182 | };
183 |
184 | image.__proto__.changeContrast = function(image, contrast) {
185 | return changeImageAppearence(contrast, image, 'contrast');
186 | };
187 |
188 | image.__proto__.fadeImage = function(image, fade) {
189 | return changeImageAppearence(fade, image, 'fade');
190 | };
191 |
192 | image.__proto__.changeOpacity = function(image, opacity) {
193 | return changeImageAppearence(opacity, image, 'opacity');
194 | };
195 |
196 | image.__proto__.blurImage = function(image, blur) {
197 | return changeImageAppearence(blur, image, 'blur');
198 | };
199 |
200 | image.__proto__.posterizeImage = function(image, posterize) {
201 | return changeImageAppearence(posterize, image, 'posterize');
202 | };
203 |
204 | image.__proto__.containImage = function(image, contain) {
205 | return scaleImageWithoutMode(contain, image, 'contain');
206 | };
207 |
208 | image.__proto__.coverImage = function(image, cover) {
209 | return scaleImageWithoutMode(cover, image, 'cover');
210 | };
211 |
212 | return image
213 | .clone()
214 | .applyBackground(image, background)
215 | .resizeAnImage(image, resize)
216 | .changeImageQuality(image, quality)
217 | .applyGreyscale(image, greyscale)
218 | .normalizeImage(image, normalize)
219 | .invertImage(image, invert)
220 | .opaqueImage(image, opaque)
221 | .sepiaFilter(image, sepia)
222 | .ditherFilter(image, dither565)
223 | .scaleImage(image, scale)
224 | .scaleToFitImage(image, scaleToFit)
225 | .flipImage(image, flip)
226 | .rotateImage(image, rotate)
227 | .cropImage(image, crop)
228 | .changeBrightness(image, brightness)
229 | .changeContrast(image, contrast)
230 | .fadeImage(image, fade)
231 | .changeOpacity(image, opacity)
232 | .blurImage(image, blur)
233 | .posterizeImage(image, posterize)
234 | .coverImage(image, cover)
235 | .color(colorManipulation(props))
236 | .containImage(image, contain);
237 | }
238 |
239 | export default processImage;
240 |
--------------------------------------------------------------------------------
/Docs/Api.md:
--------------------------------------------------------------------------------
1 | # API Reference
2 |
3 | ## Component
4 |
5 | **ProcessImage**
6 |
7 | It takes an image, applies desired filters, resizes the image (if) and returns a base64 image.
8 |
9 | ```jsx
10 | this.setState({ src, err })}
14 | />
15 | ```
16 |
17 | It does not change the original image. It clones the supplied image and passes it to the filter chain to be processed.
18 |
19 | It uses [`react-progressive-image`](https://github.com/FormidableLabs/react-progressive-image) for placeholder image until the image is processed and displayed.
20 |
21 | By default, the image is processed in a web worker instead of main thread for better performance and responsive UI. You can disable this by setting the value of `disableWebWorker` to `true`.
22 |
23 | ## Props
24 |
25 | ### resize
26 |
27 | It takes image width, height and a resize mode.
28 |
29 | **Type** - `object`
30 |
31 | **Default** - `{ width: AUTO, height: AUTO, mode: 'bilinear' }`
32 |
33 | **resize modes**
34 |
35 | You can pass these values to `mode`
36 |
37 | * [neighbor](https://en.wikipedia.org/wiki/Image_scaling)
38 | * [bilinear](https://en.wikipedia.org/wiki/Image_scaling)
39 | * [bicubic](https://en.wikipedia.org/wiki/Image_scaling)
40 | * [hermite](https://en.wikipedia.org/wiki/Hermite_interpolation)
41 | * bezier
42 |
43 | **Example** -
44 |
45 | ```jsx
46 |
47 | ```
48 |
49 | ### crop
50 |
51 | It takes x and y coordinates and a width and height.
52 |
53 | **Type** - `object`
54 |
55 | **Default** - `{ width: AUTO, height: AUTO, x: 0, y: 0 }`
56 |
57 | **Example** -
58 |
59 | ```jsx
60 |
61 | ```
62 |
63 | ### quality
64 |
65 | It takes a number between `1` - `100` for the image quality.
66 |
67 | **Type** - `number`
68 |
69 | **Default** - `AUTO`
70 |
71 | **Example** -
72 |
73 | ```jsx
74 |
75 | ```
76 |
77 | ### greyscale
78 |
79 | Remove colors from the image
80 |
81 | **Type** - `boolean`
82 |
83 | **Default** - `false`
84 |
85 | **Example** -
86 |
87 | ```jsx
88 |
89 | ```
90 |
91 |
92 |
93 | ### normalize
94 |
95 | normalize the channels in an image (contrast stretching). For example the images with poor contrast due to glare.
96 |
97 | **Type** - `boolean`
98 |
99 | **Default** - `false`
100 |
101 | **Example** -
102 |
103 | ```jsx
104 |
105 | ```
106 |
107 |
108 |
109 | ### invert
110 |
111 | invert the image colors
112 |
113 | **Type** - `boolean`
114 |
115 | **Default** - `false`
116 |
117 | **Example** -
118 |
119 | ```jsx
120 |
121 | ```
122 |
123 |
124 |
125 | ### opaque
126 |
127 | This sets the alpha channel to **opaque** for every pixel.
128 |
129 | **Type** - `boolean`
130 |
131 | **Default** - `false`
132 |
133 | **Example** -
134 |
135 | ```jsx
136 |
137 | ```
138 |
139 | ### sepia
140 |
141 | creates a reddish brown tone in an image.
142 |
143 | **Type** - `boolean`
144 |
145 | **Default** - `false`
146 |
147 | **Example** -
148 |
149 | ```jsx
150 |
151 | ```
152 |
153 |
154 |
155 | ### dither565 (similar to ninepatches class in Android)
156 |
157 | mix pixels of two colors
158 |
159 | **Type** - `boolean`
160 |
161 | **Default** - `false`
162 |
163 | **Example** -
164 |
165 | ```jsx
166 |
167 | ```
168 |
169 |
170 |
171 | ### scale
172 |
173 | scale an image by a factor
174 |
175 | **Type** - `boolean`
176 |
177 | **Default** - `AUTO`
178 |
179 | **Example** -
180 |
181 | ```jsx
182 |
183 | ```
184 |
185 | ### scaleToFitImage
186 |
187 | scale an image to the largest size that fits inside the given width and height
188 |
189 | **Type** - `object`
190 |
191 | **Default** - `{}`
192 |
193 | **Example** -
194 |
195 | ```jsx
196 |
197 | ```
198 |
199 | ### flip
200 |
201 | flip the direction of an image
202 |
203 | **Type** - `object`
204 |
205 | **Default** - { horizontal: `false`, vertical: `false` }
206 |
207 | **Example** -
208 |
209 | ```jsx
210 | Optionally, a resize mode can be passed. If `false` is passed as the second parameter, the image width and height will not be resized.
228 |
229 | ### background
230 |
231 | sets the color of any new pixels generated by the image. Will be visible when applying other values such as rotate.
232 |
233 | **Type** - `Hexidecimal rgba`,
234 |
235 | **Default** - `AUTO`
236 |
237 | **Example** -
238 |
239 | ```jsx
240 |
241 | ```
242 |
243 | ### brightness
244 |
245 | change the brightness level of an image. It takes value from `-1` to `1`.
246 |
247 | **Type** - `number`
248 |
249 | **Example** -
250 |
251 | ```jsx
252 |
253 | ```
254 |
255 | ### contrast
256 |
257 | change the contrast level of an image. It also takes value from `-1` to `1`.
258 |
259 | **Type** - `number`
260 |
261 | **Example** -
262 |
263 | ```jsx
264 |
265 | ```
266 |
267 | ### fade
268 |
269 | fades an image by factor `0 - 1`.
270 |
271 | **Type** - `number`
272 |
273 | **Example** -
274 |
275 | ```jsx
276 |
277 | ```
278 |
279 | #### opacity
280 |
281 | multiply the alpha channel by each pixel by the factor f, 0 - 1. Alternative to fade.
282 |
283 | **Type** - `number`
284 |
285 | **Example** -
286 |
287 | ```jsx
288 |
289 | ```
290 |
291 | ### blur
292 |
293 | fast blur the image by r pixels. It takes a value from `1` - `100`.
294 |
295 | **Type** - `number`
296 |
297 | **Example** -
298 |
299 | ```jsx
300 |
301 | ```
302 |
303 | ### posterize
304 |
305 | apply a posterization effect with n level. It takes a value from `1` - `100`.
306 |
307 | **Type** - `number`
308 |
309 | **Example** -
310 |
311 | ```jsx
312 |
313 | ```
314 |
315 |
316 |
317 | ### cover
318 |
319 | scale the image to the given width and height, some parts of the image may be clipped
320 |
321 | **Type** - `object`
322 |
323 | **Default** - `{}`
324 |
325 | **modes**
326 |
327 | * `horizontal_left`
328 | * `horizontal_center`
329 | * `horizontal_right`
330 | * `vertical_top`
331 | * `vertical_bottom`
332 | * `vertical_middle`
333 |
334 | **Example** -
335 |
336 | ```jsx
337 |
338 | ```
339 |
340 | ### contain
341 |
342 | scale the image to the given width and height, some parts of the image may be letter boxed
343 |
344 | **Type** - `object`
345 |
346 | **Default** - `{}`
347 |
348 | **modes**
349 |
350 | * `horizontal_left`
351 | * `horizontal_center`
352 | * `horizontal_right`
353 | * `vertical_top`
354 | * `vertical_bottom`
355 | * `vertical_middle`
356 |
357 | **Example** -
358 |
359 | ```jsx
360 |
361 | ```
362 |
363 | ### colors
364 |
365 | color manipulation
366 |
367 | **Type** - `object`
368 |
369 | **Default** - `{}`
370 |
371 | **color properties**
372 |
373 | ```
374 | colors = {
375 | lighten: number
376 | brighten: number
377 | darken: number,
378 | desaturate: number,
379 | saturate: number,
380 | greyscale: number,
381 | spin: number,
382 | mix: {
383 | color: string,
384 | amount: number
385 | },
386 | tint: number,
387 | xor: number,
388 | shade: number,
389 | red: number,
390 | green: number,
391 | blue: number
392 | }
393 | ```
394 |
395 | > Details given below are taken from [Jimp]() docs.
396 |
397 | * `lighten` - Lighten the color by a given amount, from 0 to 100. Providing 100 will always return white.
398 | * `brighten` - Brighten the color by a given amount, from 0 to 100.
399 | * `darken` - Darken the color by a given amount, from 0 to 100. Providing 100 will always return black.
400 | * `desaturate` - Desaturate the color by a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale.
401 | * `saturate` - Saturate the color by a given amount, from 0 to 100.
402 | * `greyscale` - Completely desaturates a color into greyscale.
403 | * `spin` - spin the color amount from -360 t0 360.
404 | * `mix` - Mixes colors by their RGB component values. Amount is opacity of overlaying color.
405 | * `tint` - Same as applying mix with white color.
406 | * `shade` - Same as applying mix with black color.
407 | * `xor` - Treats the two colors as bitfields and applies an XOR operation to the red, green, and blue components.
408 | * `red` - Modify red component by a given amount.
409 | * `green` - Modify green component by a given amount.
410 | * `blue` - Modify blue component by a given amount.
411 |
412 | ### storage
413 |
414 | localStorage for storing the edited image.
415 |
416 | **Type** - `boolean`
417 |
418 | **Default** - `true`
419 |
420 | **Example** -
421 |
422 | ```jsx
423 |
424 | ```
425 |
426 | ### disableWebWorker
427 |
428 | disable the web worker and process the image in the main thread (not recommended).
429 |
430 | **Type** - `boolean`
431 |
432 | **Default** - `false`
433 |
434 | **Example** -
435 |
436 | ```jsx
437 |
438 | ```
439 |
440 | If you disable the web worker, you will need to add [this](https://github.com/nitin42/react-imgpro/blob/master/src/jimp.min.js) file in your `index.html` in order to access `Jimp` instance.
441 |
442 | ### disableRerender
443 |
444 | disable the process image in re-render by options changed (recommended use with worker)
445 |
446 | **Type** - `boolean`
447 |
448 | **Default** - `false`
449 |
450 | **Example** -
451 |
452 | ```jsx
453 |
454 | ```
455 |
456 | ### customCdn
457 |
458 | support you can add custom cdn for jimp
459 |
460 | **Type** - `string`
461 |
462 | **Example** -
463 |
464 | ```jsx
465 |
466 | ```
467 |
468 | ### onProcessFinish
469 |
470 | **Type** - `function`
471 |
472 | **Example** -
473 |
474 | a callback on process finished
475 |
476 | ```jsx
477 | {
480 | this.setState({
481 | isProcessing: false
482 | });
483 | }}
484 | />
485 | ```
486 |
487 | ### getImageRef
488 |
489 | **Type** - `function`
490 |
491 | **Example** -
492 |
493 | get image ref
494 |
495 | ```jsx
496 | this.image=image}
499 | />
500 | ```
501 |
--------------------------------------------------------------------------------