├── test ├── coverage │ ├── lcov.info │ └── coverage-final.json ├── fixtures │ └── test-base64.png ├── specs │ └── index.test.js └── karma.conf.js ├── .npmignore ├── examples ├── images │ ├── city.jpg │ ├── daycaca.png │ ├── test-crop.jpg │ ├── test-base64.png │ ├── daycaca.logo.png │ └── test-compress.jpg ├── style.css └── index.html ├── .travis.yml ├── .eslintrc.json ├── .gitignore ├── .circleci └── config.yml ├── package.json ├── README.jp.md ├── README.zh.md ├── README.md ├── dist ├── daycaca.min.js └── index.js └── src └── index.js /test/coverage/lcov.info: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | build 3 | examples 4 | -------------------------------------------------------------------------------- /test/coverage/coverage-final.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /examples/images/city.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/city.jpg -------------------------------------------------------------------------------- /examples/images/daycaca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/daycaca.png -------------------------------------------------------------------------------- /examples/images/test-crop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/test-crop.jpg -------------------------------------------------------------------------------- /test/fixtures/test-base64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/test/fixtures/test-base64.png -------------------------------------------------------------------------------- /examples/images/test-base64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/test-base64.png -------------------------------------------------------------------------------- /examples/images/daycaca.logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/daycaca.logo.png -------------------------------------------------------------------------------- /examples/images/test-compress.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackPu/daycaca/HEAD/examples/images/test-compress.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | script: npm run test 5 | before_install: 6 | - export CHROME_BIN=chromium-browser 7 | - export DISPLAY=:99.0 8 | - sh -e /etc/init.d/xvfb start 9 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true 5 | }, 6 | "plugins": [ 7 | "import" 8 | ], 9 | "rules": { 10 | "no-underscore-dangle": 0, 11 | "no-param-reassign": 0, 12 | "consistent-return": 0 13 | } 14 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata 16 | *.xccheckout 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | *.xcuserstate 22 | project.xcworkspace 23 | 24 | # node.js 25 | # 26 | node_modules/ 27 | npm-debug.log 28 | .idea 29 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | version: 2 3 | jobs: 4 | build: 5 | docker: 6 | # specify the version you desire here 7 | # - image: circleci/node:7.10 8 | - image: circleci/node:8-browsers 9 | 10 | working_directory: ~/repo 11 | 12 | steps: 13 | - checkout 14 | 15 | # Download and cache dependencies 16 | - restore_cache: 17 | keys: 18 | - v1-dependencies-{{ checksum "package.json" }} 19 | # fallback to using the latest cache if no exact match is found 20 | - v1-dependencies- 21 | 22 | - run: npm install 23 | 24 | - save_cache: 25 | paths: 26 | - node_modules 27 | key: v1-dependencies-{{ checksum "package.json" }} 28 | # run tests! 29 | - run: npm run test -------------------------------------------------------------------------------- /test/specs/index.test.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | import { expect } from 'chai'; 3 | import daycaca from '../../src/index'; 4 | 5 | describe('daycaca tests', () => { 6 | 7 | it('#_getCanvas()', () => { 8 | const canvas = daycaca._getCanvas(100, 100); 9 | expect(canvas.tagName).to.equal('CANVAS'); 10 | expect(canvas.width).to.equal(100); 11 | }); 12 | 13 | it('#_createImage()', () => { 14 | const i = daycaca._createImage('http://img1.vued.vanthink.cn/vuede7738ce4bcff0e00874b3566ef518783.png'); 15 | expect(i.tagName).to.equal('IMG'); 16 | }); 17 | 18 | it('#base64()', (done) => { 19 | const src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQYV2P8+bbpPwMDAwMjjAEAS2AG0Z9vsksAAAAASUVORK5CYII='; 20 | daycaca.base64(src, (data) => { 21 | expect(/data:image\/png;base64/.test(data)).to.equal(true) 22 | done(); 23 | }); 24 | }); 25 | 26 | it('#resize()', () => { 27 | const src = 'http://img1.vued.vanthink.cn/vuede7738ce4bcff0e00874b3566ef518783.png'; 28 | daycaca.base64(src, 2, (data) => { 29 | expect(/data:image\/png;base64/.test(data)).to.equal(true) 30 | done(); 31 | }); 32 | }); 33 | 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daycaca", 3 | "version": "1.0.8", 4 | "description": "a pure JavaScript lib to handle image via canvas", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "npm run build-browser && npm run build-umd", 8 | "build-browser": "webpack --config ./build/webpack.browser.config.js", 9 | "build-umd": "webpack --config ./build/webpack.build.config.js", 10 | "dev": "webpack-dev-server --config ./build/webpack.dev.config.js", 11 | "test": "karma start ./test/karma.conf.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/JackPu/daycaca.git" 16 | }, 17 | "keywords": [ 18 | "image", 19 | "canvas", 20 | "rotate", 21 | "compress" 22 | ], 23 | "author": "Jack Pu", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/JackPu/daycaca/issues" 27 | }, 28 | "homepage": "https://github.com/JackPu/daycaca#readme", 29 | "devDependencies": { 30 | "@babel/preset-env": "^7.0.0-beta.47", 31 | "babel-core": "^6.26.0", 32 | "babel-loader": "^7.1.2", 33 | "babel-plugin-transform-function-bind": "^6.22.0", 34 | "babel-plugin-transform-object-assign": "^6.22.0", 35 | "babel-preset-env": "^1.7.0", 36 | "chai": "^4.1.2", 37 | "eslint": "^4.15.0", 38 | "eslint-config-airbnb-base": "^12.1.0", 39 | "eslint-plugin-import": "^2.8.0", 40 | "jasmine-core": "^2.8.0", 41 | "karma": "^2.0.0", 42 | "karma-chai": "^0.1.0", 43 | "karma-chrome-launcher": "^2.2.0", 44 | "karma-coverage": "^1.1.1", 45 | "karma-jasmine": "^1.1.1", 46 | "karma-sourcemap-loader": "^0.3.7", 47 | "karma-webpack": "^2.0.9", 48 | "webpack": "^3.10.0", 49 | "webpack-dev-server": "^2.11.1" 50 | } 51 | } -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | // Karma configuration 3 | // Generated on Tue Sep 27 2016 22:14:28 GMT+0800 (CST) 4 | 5 | module.exports = function(config) { 6 | config.set({ 7 | 8 | // base path that will be used to resolve all patterns (eg. files, exclude) 9 | basePath: '', 10 | 11 | 12 | // frameworks to use 13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 14 | frameworks: ['jasmine'], 15 | 16 | 17 | // list of files / patterns to load in the browser 18 | files: [ 19 | //'src/*.js', 20 | 'specs/*.test.js' 21 | ], 22 | webpack: { 23 | module: { 24 | 25 | loaders: [ 26 | { 27 | test: /\.js$/, 28 | loader: 'babel-loader', 29 | exclude: /(node_modules)/, 30 | }, 31 | ] 32 | }, 33 | devtool: 'inline-source-map', 34 | }, 35 | 36 | // list of files to exclude 37 | exclude: [ 38 | 39 | ], 40 | preprocessors: { 41 | './specs/*.test.js': ['webpack'], 42 | '../src/*.js': ['coverage'], 43 | }, 44 | 45 | reporters: ['progress', 'coverage'], 46 | port: 9876, 47 | colors: true, 48 | logLevel: config.LOG_INFO, 49 | autoWatch: true, 50 | browsers: ['Chrome'], 51 | singleRun: true, 52 | concurrency: Infinity, 53 | // Configure code coverage reporter 54 | coverageReporter: { 55 | reporters: [ 56 | // generates ./coverage/lcov.info 57 | {type:'lcovonly', subdir: '.'}, 58 | // generates ./coverage/coverage-final.json 59 | {type:'json', subdir: '.'}, 60 | ] 61 | }, 62 | plugins: [ 63 | 'karma-webpack', 64 | 'karma-jasmine', 65 | 'karma-chai', 66 | 'karma-chrome-launcher', 67 | 'karma-sourcemap-loader', 68 | 'karma-coverage', 69 | ], 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /README.jp.md: -------------------------------------------------------------------------------- 1 | # daycaca 2 | 3 | [![CircleCI](https://circleci.com/gh/JackPu/daycaca.svg?style=shield)](https://circleci.com/gh/JackPu/daycaca) 4 | [![npm](https://img.shields.io/npm/v/daycaca.svg?maxAge=2592000)]() 5 | 6 | 7 | 8 | 9 | 10 | キャンバスを介して Canvas ソースを処理するための純粋な JavaScript ライブラリ。 11 | 12 | 13 | [中文文档](./README.zh.md) | [English](./README.md) | [日本語](./README.jp.md) 14 | 15 | [examples](http://events.jackpu.com/daycaca/) 16 | 17 | 18 | ## 使い方 19 | 20 | ### Npm 21 | 22 | ``` bash 23 | $ npm install daycaca --save 24 | ``` 25 | 26 | ``` js 27 | // es6import daycaca from 'daycaca';// src specify an image src (url or base64) 28 | daycaca.rotate(src, degress, (data, w, h) => { 29 | // your code here 30 | }); 31 | ``` 32 | 33 | ### CDN (ブラウザーで直接使う) 34 | 35 | ``` html 36 | 37 | 42 | ``` 43 | 44 | ## API 45 | 46 | すべてのAPI source は以下の1つのタイプでなければなりません: 47 | + 画像url (URLを使う場合、クロスドメインの設置にお気を付けください。) 48 | + 画像のDOM節点 49 | + [type="file"]を使用する画像ファイルの対象值 50 | 51 | ### base64(source, callback) 52 | 53 | 画像をbase64 code値に転換する。参考数elは画像のDOM節点やDOMのURLである。 54 | 55 | ``` js 56 | const img = document.querySelector('img') 57 | daycaca.base64(img, (data) => { 58 | //... handle base64 59 | }) 60 | ``` 61 | 62 | ### compress(source, quailty, callback) 63 | 64 | 画像を圧縮する場合、画質を圧縮し、画像のサイズを小さくする。 65 | 66 | + PNGは無損失圧縮されるので、quality無効。 67 | + JPG/JPEG/BMP は損失圧縮される。 68 | 69 | `quality` は圧縮後の画質を表す。Qualityの数値が大きいほど、画質が高いのである。 70 | 71 | ``` js 72 | const img = document.querySelector('img')daycaca.compress(img, 0.5,(data) => { 73 | //... handle base64 74 | }) 75 | ``` 76 | 77 | ### crop(source, option, callback) 78 | 79 | 画像をカットする。 80 | 81 | `option` {} では、指定する必要がある参考数値である: 82 | 83 | + `x`;はカットされたエリアが画像の左までの距離 84 | + `y`;はカットされたエリアが画像の上までの距離 85 | + `w`;はカットされたエリアの横幅 86 | + `h`;はカットされたエリアの高度 87 | + `ratio`: スケール比率; 88 | 89 | ``` js 90 | const img = document.querySelector('img') 91 | daycaca.reszie(img, { 92 | x: 10, 93 | y: 20, 94 | w: 100, 95 | h: 70 96 | },(data) => { 97 | //... handle base64 98 | }) 99 | ``` 100 | 101 | ### rotate(source, degree, callback) 102 | 103 | 画像を回転させる。 104 | 105 | ``` js 106 | const img = document.querySelector('img') 107 | daycaca.rotate(img, 90,(data) => { 108 | //... handle base64 109 | }) 110 | ``` 111 | 112 | ### reszie(source, ratio, callback) 113 | 114 | 画像を拡大、縮小させる; 115 | 116 | + `ratio` (0~1)は画像のスケール比率である。1と設定する場合は、画像の大きさが変わらない。0以下の数値は設定できない。 117 | 118 | ``` js 119 | const img = document.querySelector('img') 120 | daycaca.reszie(img, 0.5,(data) => { 121 | //... handle base64 122 | }) 123 | ``` 124 | 125 | ### コメント 126 | 127 | ご意見やご質問大歓迎です! 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # daycaca 2 | 3 | [![CircleCI](https://circleci.com/gh/JackPu/daycaca.svg?style=shield)](https://circleci.com/gh/JackPu/daycaca) 4 | [![npm](https://img.shields.io/npm/v/daycaca.svg?maxAge=2592000)](https://www.npmjs.com/package/daycaca) 5 | 6 | 7 | 8 | 9 | 一款基于 canvas 图片处理类库,它可以帮助你处理图片的压缩,裁剪等; 10 | 11 | [中文文档](./README.zh.md) | [English](./README.md) | [日本語](./README.jp.md) 12 | 13 | [examples](http://events.jackpu.com/daycaca/) 14 | 15 | 16 | ## 快速开始 17 | 18 | ### npm 19 | 20 | ``` bash 21 | $ npm install daycaca -save 22 | ``` 23 | 24 | 25 | ``` es6 26 | // es6 27 | import daycaca from 'daycaca'; 28 | // src specify an image src (url or base64) 29 | daycaca.rotate(src, degress, (data, w, h) => { 30 | // your code here 31 | }); 32 | 33 | ``` 34 | 35 | ### 直接在浏览器使用 36 | 37 | ``` js 38 | 39 | 40 | 46 | ``` 47 | 48 | 49 | 50 | ## API 51 | 52 | 所有 api 中的 `source` 它可以是; 53 | 54 | + 图片 url 地址 (如果使用 url 注意对于 [跨域](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image) 的设置) 55 | + 图片的 DOM 节点 56 | + 一个图片的 [文件对象](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) 使用 `input[type="file"]` 读取的对象值 57 | 58 | ### base64(source, callback) 59 | 60 | 将图片转换成 base64 code 值;参数 `el` 可以为一个图片的 Dom 节点也可以是一个图片地址; 61 | 62 | ``` js 63 | const img = document.querySelector('img') 64 | daycaca.base64(img, (data) => { 65 | //... handle base64 66 | }) 67 | ``` 68 | 69 | ### compress(source, quailty, callback) 70 | 71 | 压缩图片,会将图片进行质量上的压缩, 从而降低图片的大小。 72 | 73 | + PNG 走的无损压缩,类库参考 .因此 `quailty` 无效 74 | 75 | + JPG/JPEG/BMP 等位图走的有损压缩 76 | 77 | `quality` 表示图片压缩的质量,值越大,图片会清晰 78 | 79 | 80 | ``` js 81 | const img = document.querySelector('img') 82 | daycaca.compress(img, 0.5,(data) => { 83 | //... handle base64 84 | }) 85 | ``` 86 | 87 | ### crop(source, option, callback) 88 | 89 | 裁剪图片,将图片裁剪至指定大小。 90 | 91 | option {} 里面需要指定的参数: 92 | 93 | + x: 裁剪的区域距离图片的左边缘的距离 94 | + y: 裁剪的区域距离图片的上边缘的距离 95 | + w: 裁剪的区域的宽度 96 | + h: 裁剪的区域的高度 97 | + ratio 缩放比例 98 | 99 | 100 | 101 | 102 | ``` js 103 | const img = document.querySelector('img') 104 | daycaca.reszie(img, { 105 | x: 10, 106 | y: 20, 107 | w: 100, 108 | h: 70 109 | },(data) => { 110 | //... handle base64 111 | }) 112 | ``` 113 | 114 | 115 | ### rotate(source, degree, callback) 116 | 117 | 旋转图片至某个角度。 118 | 119 | ``` js 120 | const img = document.querySelector('img') 121 | daycaca.rotate(img, 90,(data) => { 122 | //... handle base64 123 | }) 124 | ``` 125 | 126 | 127 | ### reszie(source, ratio, callback) 128 | 129 | 图片缩放,将图片进行放大缩小 130 | 131 | + ratio 表示图片缩放的比例,其中 1 表示图片不进行缩放,最小值必须 **大于0** 132 | 133 | ``` js 134 | const img = document.querySelector('img') 135 | daycaca.reszie(img, 0.5,(data) => { 136 | //... handle base64 137 | }) 138 | ``` 139 | 140 | ## 贡献 141 | 142 | 欢迎您提出自己的代码 PR 以及任何建议 😄😄🌺🌺🎆🎆 143 | 144 | 145 | ## MIT License 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # daycaca 2 | 3 | [![CircleCI](https://circleci.com/gh/JackPu/daycaca.svg?style=shield)](https://circleci.com/gh/JackPu/daycaca) 4 | [![prs wlecome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)]() 5 | [![npm](https://img.shields.io/npm/v/daycaca.svg?maxAge=2592000)]() 6 | 7 | 8 | 9 | 10 | A pure JavaScript library to handle image source via canvas. 11 | 12 | [中文文档](./README.zh.md) | [English](./README.md) | [日本語](./README.jp.md) 13 | 14 | [examples](http://events.jackpu.com/daycaca/) 15 | 16 | 17 | ## How to use 18 | 19 | ### Npm 20 | 21 | ``` bash 22 | $ npm install daycaca -save 23 | ``` 24 | 25 | 26 | ``` es6 27 | // es6 28 | import daycaca from 'daycaca'; 29 | // src specify an image src (url or base64) 30 | daycaca.rotate(src, degress, (data, w, h) => { 31 | // your code here 32 | }); 33 | 34 | ``` 35 | 36 | ### CDN 37 | 38 | ``` js 39 | 40 | 41 | 47 | ``` 48 | 49 | 50 | 51 | ## API 52 | 53 | All API methods's argument `source` should be one type below: 54 | 55 | + an image url (Pay attention to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image) settings) 56 | + an IMG element 57 | + [a file object](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) Which use `input[type="file"]` value as source 58 | 59 | ### base64(source, callback) 60 | 61 | Convert your image to base64. 62 | 63 | ``` js 64 | const img = document.querySelector('img') 65 | daycaca.base64(img, (data) => { 66 | //... handle base64 67 | }) 68 | ``` 69 | 70 | ### compress(source, quailty, callback) 71 | 72 | Compress your image and minify the size of your image. 73 | 74 | + PNG need lossless compression; So the param `quality` may not work. 75 | 76 | + JPG/JPEG/BMP need lossy compression; 77 | 78 | `quality` (1~100). 100 means that the image keeps the same quality. 79 | 80 | 81 | ``` js 82 | const img = document.querySelector('img') 83 | daycaca.compress(img, 0.5,(data) => { 84 | //... handle base64 85 | }) 86 | ``` 87 | 88 | ### crop(source, option, callback) 89 | 90 | Crop your image to the size which you specify. 91 | 92 | option {} : 93 | 94 | + x: The x-axis distance between the crop area and the image; 95 | + y: The y-axis distance between the crop area and the image; 96 | + w: The width of crop area; 97 | + h: The height of crop area 98 | + ratio: the scale ration of the image 99 | + fixedWidth: get the image with fixed width 100 | + fixedHieght: get the image with fixed height 101 | 102 | 103 | 104 | 105 | ``` js 106 | const img = document.querySelector('img') 107 | daycaca.reszie(img, { 108 | x: 10, 109 | y: 20, 110 | w: 100, 111 | h: 70 112 | },(data) => { 113 | //... handle base64 114 | }) 115 | ``` 116 | 117 | ### rotate(source, degree, callback) 118 | 119 | Rotate your image to any degree. 120 | 121 | ``` js 122 | const img = document.querySelector('img') 123 | daycaca.rotate(img, 90,(data) => { 124 | //... handle base64 125 | }) 126 | ``` 127 | 128 | 129 | ### reszie(source, ratio, callback) 130 | 131 | Scale the image; 132 | + ratio (0~1): the scale ratio of the image. 1 means the image keep the same size; 133 | 134 | ``` js 135 | const img = document.querySelector('img') 136 | daycaca.reszie(img, 0.5,(data) => { 137 | //... handle base64 138 | }) 139 | ``` 140 | 141 | ## Contributions 142 | 143 | Your contributions and suggestions are welcome 😄😄🌺🌺🎆🎆 144 | 145 | ## Contributors 146 | 147 | + @Annie Tanslations of Japanese documents; 148 | 149 | ## MIT License 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /examples/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin:0; 3 | padding: 0; 4 | } 5 | 6 | body{ 7 | font-size: 16px; 8 | font-family: Helvetica, 'Microsoft Yahei', SimHei, arial, sans-serif; 9 | background:#e3e3e3; 10 | } 11 | html,body{ 12 | height: 100%; 13 | } 14 | .page{ 15 | position: relative; 16 | width: 100%; 17 | } 18 | img{ 19 | max-width: 100%; 20 | margin-bottom: 20px; 21 | } 22 | img + p{ 23 | font-size: 13px; 24 | color: #ddd; 25 | text-align: center; 26 | } 27 | a{ 28 | color: #f6e342; 29 | text-decoration: none; 30 | transition: all .2s ease; 31 | } 32 | a:hover{ 33 | color: #f9ec82; 34 | } 35 | h1{ 36 | text-align: center; 37 | margin-top: 0; 38 | padding-top: 120px; 39 | padding-bottom: 40px; 40 | font-family: 'Monoton', cursive; 41 | font-size: 60px; 42 | letter-spacing: 2px; 43 | text-shadow: 0 6px 1px rgba(0,0,0,0.2); 44 | } 45 | 46 | h1 img{ 47 | width: 480px; 48 | 49 | } 50 | h2{ 51 | color: #333; 52 | padding-top: 60px; 53 | padding-bottom: 30px; 54 | text-align: center; 55 | } 56 | ul{ 57 | padding-left: 40px; 58 | } 59 | code{ 60 | word-break: break-all; 61 | } 62 | .js-navbar{ 63 | display: none; 64 | } 65 | .js-navbar.active{ 66 | display: block; 67 | background-color: rgba(255, 255, 255, .95); 68 | } 69 | .doc-hd{ 70 | min-height: 75vh; 71 | background: #2d323c url(http://img1.vued.vanthink.cn/vued16831dfcbc402a474725d39217612578.jpeg) center bottom; 72 | background-size: cover; 73 | color:#f6e342; 74 | text-align: center; 75 | } 76 | .doc-hd p { 77 | font-size: 20px; 78 | color: #888; 79 | padding: 20px 0; 80 | } 81 | .btn-install{ 82 | padding: 12px 36px; 83 | border-radius: 50px; 84 | font-size: 18px; 85 | color: #f6e342; 86 | background: #2d323c; 87 | border:2px solid #f6e342; 88 | } 89 | .btn-install:hover{ 90 | color:#fff; 91 | border-color:#fff;; 92 | } 93 | .doc .btn{ 94 | background-color: #f6e342; 95 | color: #333; 96 | border-color: #f6e342; 97 | border-radius: 20px; 98 | } 99 | .doc .btn:hover{ 100 | box-shadow: 0 2px 4px rgba(0,0,0, .25); 101 | } 102 | .contents{ 103 | padding: 20px; 104 | background: #fff; 105 | box-shadow: 0 6px 10px rgba(0,0,0,.15); 106 | max-width: 720px; 107 | margin: 0 auto 40px auto; 108 | } 109 | 110 | .doc-ft{ 111 | padding-top: 40px; 112 | padding-bottom: 30px; 113 | background: #2d323c; 114 | color:#555; 115 | font-size: 13px; 116 | text-align: center; 117 | } 118 | pre{ 119 | border-width: 0px; 120 | } 121 | @media all and (max-width:960px) { 122 | h2,.doc,.img-wrap{ 123 | flex-wrap: wrap; 124 | } 125 | .img-wrap .item{ 126 | width: 100%' 127 | } 128 | .js-navbar.active{ 129 | display: none; 130 | } 131 | } 132 | /** view doc https://highlightjs.org **/ 133 | .hljs { 134 | display: block; 135 | overflow-x: auto; 136 | padding: 0.5em; 137 | background: #f7f7f7; 138 | } 139 | .hljs, 140 | .hljs-subst { 141 | color: #2c3e50; 142 | } 143 | .hljs-comment { 144 | color: #999; 145 | } 146 | .hljs-keyword, 147 | .hljs-attribute, 148 | .hljs-selector-tag, 149 | .hljs-meta-keyword, 150 | .hljs-doctag, 151 | .hljs-name { 152 | font-weight: bold; 153 | } 154 | .hljs-type, 155 | .hljs-string, 156 | .hljs-number, 157 | .hljs-selector-id, 158 | .hljs-selector-class, 159 | .hljs-quote, 160 | .hljs-template-tag, 161 | .hljs-deletion { 162 | color: #e74c3c; 163 | } 164 | .hljs-title, 165 | .hljs-section { 166 | color: #e74c3c; 167 | font-weight: bold; 168 | } 169 | .hljs-regexp, 170 | .hljs-symbol, 171 | .hljs-variable, 172 | .hljs-template-variable, 173 | .hljs-link, 174 | .hljs-selector-attr, 175 | .hljs-selector-pseudo { 176 | color: #bc6060; 177 | } 178 | .hljs-literal { 179 | color: #78a960; 180 | } 181 | .hljs-built_in, 182 | .hljs-bullet, 183 | .hljs-code, 184 | .hljs-addition { 185 | color: #16a085; 186 | } 187 | .hljs-meta { 188 | color: #2980b9; 189 | } 190 | .hljs-meta-string { 191 | color: #2980b9; 192 | } 193 | .hljs-emphasis { 194 | font-style: italic; 195 | } 196 | .hljs-strong { 197 | font-weight: bold; 198 | } 199 | 200 | .navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover{ 201 | background: transparent; 202 | color: #f6e342; 203 | } 204 | .btn{ 205 | border-radius: 0; 206 | transition: all .2s ease-in; 207 | padding: 8px 30px; 208 | } 209 | -------------------------------------------------------------------------------- /dist/daycaca.min.js: -------------------------------------------------------------------------------- 1 | var daycaca=function(t){function e(a){if(r[a])return r[a].exports;var i=r[a]={i:a,l:!1,exports:{}};return t[a].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var r={};return e.m=t,e.c=r,e.d=function(t,r,a){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:a})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,r){"use strict";var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=Object.assign||function(t){for(var e=1;e1&&(i=a[0].replace("data:","")),n.onload=function(){var t=r._getCanvas(n.naturalWidth,n.naturalHeight);t.getContext("2d").drawImage(n,0,0);var a=t.toDataURL(i);e(a)}},base64:function(t,e){var r=this._getSrc(t),a=r.src,i=r.type;if("file"===i)return this._readFile(a,e);if("video"===i){var n=t,o=this._getCanvas(n.videoWidth,n.videoHeight);o.getContext("2d").drawImage(n,0,0);e(o.toDataURL(),o)}return this.init(a,e)},compress:function(t,e,r){var a=this,i=this._getSrc(t),n=i.src;if("file"===i.type)return this._readFile(n,function(i){a._compress(i,t,e,r)});this._compress(n,t,e,r)},_compress:function(t,e,r,a){var i=this;this._loadImage(t,function(t){var n=i._getImageType(e),o=i._getCanvas(t.naturalWidth,t.naturalHeight);o.getContext("2d").drawImage(t,0,0);var s=o.toDataURL(n,r/100);a(s)})},crop:function(t,e,r){var a=this,i=this._getSrc(t),n=i.src;if("file"===i.type)return this._readFile(n,function(i){a._crop(i,t,e,r)});this._crop(n,t,e,r)},_crop:function(t,e,r,a){var i=this;this._loadImage(t,function(t){if(n(r.x)&&n(r.y)&&r.w>0&&r.h>0){var o=r.w,s=r.h;r.maxWidth&&r.maxWidth0?(n=Math.floor(t.naturalWidth*r.ratio),o=Math.floor(t.naturalHeight*r.ratio)):"number"==typeof r.width&&"number"==typeof r.height&&(n=Math.floor(r.width),o=Math.floor(r.height));var s=i._getCanvas(n,o);s.getContext("2d").drawImage(t,0,0,t.naturalWidth,t.naturalHeight,0,0,n,o);var c=i._getImageType(e),u=s.toDataURL(c,r.compress/100);a(u)})},rotate:function(t,e,r){var a=this,i=this._getSrc(t),n=i.src;return"file"===i.type?this._readFile(n,function(){a._rotate(n,t,e,r)}):e%360==0?r(n):void this._rotate(n,t,e,r)},_rotate:function(t,e,r,a){var i=this;this._loadImage(t,function(t){var n=t.naturalWidth,o=t.naturalHeight;90!==(r%=360)&&270!==r||(n=t.naturalHeight,o=t.naturalWidth);var s=i._getCanvas(n,o),c=s.getContext("2d");c.clearRect(0,0,n,o),c.fillStyle="white",c.fillRect(0,0,n,o),c.translate(n/2,o/2),c.rotate(r*Math.PI/180),c.drawImage(t,-t.naturalWidth/2,-t.naturalHeight/2);var u=i._getImageType(e),f=s.toDataURL(u,1);a(f,n,o),s=null,c=null})},_loadImage:function(t,e){var r=this._createImage(t);r.onload=function(){e(r)}},_readFile:function(t,e){var r=new FileReader;r.onload=function(t){var r=t.target.result;e(r)},r.readAsDataURL(t)},_getCanvas:function(t,e){var r=document.createElement("canvas");return r.width=t,r.height=e,r},_createImage:function(t){var e=new Image;return e.src=t,e},_getSrc:function(t){var e=t,r="url";if(this._isImageElement(t)){var a=t.src;if(!a)throw new Error("Element must hava src");e=a,r="element"}else this._isVideoElement(t)?(e=t,r="video"):this._isFileObject(t)&&(e=t,r="file");return{src:e,type:r}},_isFileObject:function(t){return"object"===(void 0===t?"undefined":a(t))&&t.type&&t.size>0},_isImageElement:function(t){return"object"===(void 0===t?"undefined":a(t))&&"IMG"===t.tagName},_isVideoElement:function(t){return"object"===(void 0===t?"undefined":a(t))&&"VIDEO"===t.tagName},_getImageType:function(t){var e=this._getSrc(t),r=e.src,a=e.type,i="image/jpeg";if("file"===a){var n=t.type,s=n.match(/(image\/[\w]+)\.*/)[0];void 0!==s&&(i=s)}else{var c=o.exec(r);c&&c[1]&&(i="image/"+c[1])}return i}}}]); -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Daycaca-A pure JavaScript library to handle image via canvas 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 34 |
35 |

Daycaca

36 |

A pure JavaScript library to handle image via canvas

37 |

38 | Install Now 39 |

40 |
41 |

How To Use

42 |
43 |

Browser

44 |
<script src="./dist/daycaca.min.js"></script>
45 |

Npm

46 |
$ npm install daycaca --save
47 |

In your JS File

48 |
daycaca.setConfig({});
49 |

view more details

50 |
51 | 52 |
53 |

Examples

54 |
55 |

Base64

56 |
daycaca.base64('./images/test-base64.png', () => {
 57 |   //...
 58 | });
59 |

60 | 61 |

62 |

63 |

compress

64 | 65 |

before

66 | 67 | 68 |
daycaca.base64('./images/test-compress.jpg', 10, () => {
 69 |   //...
 70 | });
71 |

72 | 73 |

74 |

Crop

75 | 76 |

裁剪前

77 | 78 | 79 |
daycaca.crop('./images/test-compress.jpg', {
 80 |   x: 20,
 81 |   y: 20,
 82 |   w: 120,
 83 |   h: 60
 84 |   }, () => {
 85 | //...
 86 | });
87 |

88 | 89 |

90 |

Rotate

91 | 92 |

before

93 | 94 | 95 |
daycaca.rotate(el, 90, () => {
 96 | //...
 97 | });
98 |

99 | 100 |

101 |

Resize

102 | 103 |

before

104 | 105 | 106 |
daycaca.resize(el, 2, () => {
107 |       //...
108 | });
109 |

110 | 111 |

112 |
113 |
114 | 115 |
116 |
117 |
118 | The Project Made ❤️ by Jack Pu 119 |
120 | 121 | 122 | 123 |
124 | 125 | 126 | 129 | 130 | 131 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // a canvas lib to compress or crop images 2 | 3 | const isNumber = num => (typeof num === 'number'); 4 | const imageReg = /[./](png|jpeg|jpg|gif|bmp)/; 5 | 6 | const defaultConfig = { 7 | ratio: 1, 8 | compress: 80, 9 | enableWebWorker: false, 10 | }; 11 | 12 | 13 | module.exports = { 14 | setConfig(config) { 15 | this._config = Object.assign(defaultConfig, config) 16 | }, 17 | 18 | /** 19 | * init image for reset size and rotation 20 | */ 21 | init(src, callback) { 22 | const scrTypes = src.split(';'); 23 | let srcType = null; 24 | const image = this._createImage(src); 25 | if (scrTypes.length > 1) { 26 | srcType = scrTypes[0].replace('data:', ''); 27 | } 28 | image.onload = () => { 29 | const cvs = this._getCanvas(image.naturalWidth, image.naturalHeight); 30 | const ctx = cvs.getContext('2d'); 31 | ctx.drawImage(image, 0, 0); 32 | const newImageData = cvs.toDataURL(srcType); 33 | callback(newImageData); 34 | }; 35 | }, 36 | 37 | /** 38 | * encode image to base64 39 | * @param {Element|String} el 40 | * @param {Function} callback 41 | */ 42 | base64(el, callback) { 43 | const { src, type } = this._getSrc(el); 44 | if (type === 'file') { 45 | return this._readFile(src, callback); 46 | } else if (type === 'video') { 47 | const video = el; 48 | const cvs = this._getCanvas(video.videoWidth, video.videoHeight); 49 | const ctx = cvs.getContext('2d'); 50 | ctx.drawImage(video, 0, 0); 51 | const newImageData = cvs.toDataURL(); 52 | callback(newImageData, cvs); 53 | } 54 | return this.init(src, callback); 55 | }, 56 | 57 | /** 58 | * compress image 59 | * @param {el|String} src the source of image 60 | * @param {Number} the quality of image ( 100 = the highest quality) 61 | * @param {Function} callback 62 | */ 63 | compress(source, quality, callback) { 64 | const { src, type } = this._getSrc(source); 65 | if (type === 'file') { 66 | return this._readFile(src, (data) => { 67 | this._compress(data, source, quality, callback); 68 | }); 69 | } 70 | this._compress(src, source, quality, callback); 71 | }, 72 | 73 | _compress(src, source, quality, callback) { 74 | this._loadImage(src, (image) => { 75 | const mimeType = this._getImageType(source); 76 | const cvs = this._getCanvas(image.naturalWidth, image.naturalHeight); 77 | const ctx = cvs.getContext('2d'); 78 | ctx.drawImage(image, 0, 0); 79 | const newImageData = cvs.toDataURL(mimeType, quality / 100); 80 | callback(newImageData); 81 | }); 82 | }, 83 | 84 | /** 85 | * crop image via canvas and generate data 86 | */ 87 | crop(source, options, callback) { 88 | const { src, type } = this._getSrc(source); 89 | if (type === 'file') { 90 | return this._readFile(src, (data) => { 91 | this._crop(data, source, options, callback); 92 | }) 93 | } 94 | this._crop(src, source, options, callback); 95 | }, 96 | 97 | _crop(src, source, options, callback) { 98 | this._loadImage(src, (image) => { 99 | // check crop options 100 | if (isNumber(options.x) && 101 | isNumber(options.y) && 102 | options.w > 0 && 103 | options.h > 0) { 104 | let { w, h } = options; 105 | if (options.maxWidth && options.maxWidth < w) { 106 | w = options.maxWidth; 107 | h = (options.h * w) / options.w; 108 | } 109 | if (options.maxHeight && options.maxHeight < h) { 110 | h = options.maxHeight; 111 | } 112 | if (options.fixedWidth && options.fixedHeight) { 113 | w = options.fixedWidth; 114 | h = options.fixedHeight; 115 | } 116 | const cvs = this._getCanvas(w, h); 117 | cvs.getContext('2d').drawImage(image, options.x, options.y, options.w, options.h, 0, 0, w, h); 118 | const mimeType = this._getImageType(source); 119 | const data = cvs.toDataURL(mimeType, options.compress / 100); 120 | callback(data); 121 | } 122 | }); 123 | }, 124 | 125 | resize(source, ratio, callback) { 126 | const { src, type } = this._getSrc(source); 127 | let options = {}; 128 | if (typeof ratio === 'number' || typeof ratio === 'string') { 129 | options = { 130 | ratio, 131 | compress: defaultConfig.compress, 132 | }; 133 | } 134 | if (typeof ratio === 'object') { 135 | options = ratio; 136 | } 137 | if (type === 'file') { 138 | return this._readFile(src, (data) => { 139 | this._resize(data, source, options, callback); 140 | }); 141 | } 142 | this._resize(src, source, options, callback); 143 | }, 144 | 145 | _resize(src, source, options, callback) { 146 | this._loadImage(src, (image) => { 147 | let w = image.naturalWidth; 148 | let h = image.naturalHeight; 149 | if (options.ratio > 0) { 150 | w = Math.floor(image.naturalWidth * options.ratio); 151 | h = Math.floor(image.naturalHeight * options.ratio); 152 | } else if (typeof options.width === 'number' && typeof options.height === 'number') { 153 | w = Math.floor(options.width); 154 | h = Math.floor(options.height); 155 | } 156 | const cvs = this._getCanvas(w, h); 157 | cvs.getContext('2d').drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight, 0, 0, w, h); 158 | const mimeType = this._getImageType(source); 159 | const data = cvs.toDataURL(mimeType, options.compress / 100); 160 | callback(data); 161 | }); 162 | }, 163 | 164 | /** 165 | * rotate image 166 | */ 167 | rotate(source, degree, callback) { 168 | const { src, type } = this._getSrc(source); 169 | if (type === 'file') { 170 | return this._readFile(src, () => { 171 | this._rotate(src, source, degree, callback); 172 | }); 173 | } 174 | if (degree % 360 === 0) { 175 | return callback(src); 176 | } 177 | this._rotate(src, source, degree, callback); 178 | }, 179 | 180 | _rotate(src, source, degree, callback) { 181 | this._loadImage(src, (image) => { 182 | let w = image.naturalWidth; 183 | let h = image.naturalHeight; 184 | degree %= 360; 185 | if (degree === 90 || degree === 270) { 186 | w = image.naturalHeight; 187 | h = image.naturalWidth; 188 | } 189 | let cvs = this._getCanvas(w, h); 190 | let ctx = cvs.getContext('2d'); 191 | ctx.clearRect(0, 0, w, h); 192 | ctx.fillStyle = 'white'; 193 | ctx.fillRect(0, 0, w, h); 194 | ctx.translate(w / 2, h / 2); 195 | ctx.rotate((degree * Math.PI) / 180); 196 | ctx.drawImage(image, -image.naturalWidth / 2, -image.naturalHeight / 2); 197 | const mimeType = this._getImageType(source); 198 | const data = cvs.toDataURL(mimeType, 1); 199 | callback(data, w, h); 200 | cvs = null; 201 | ctx = null; 202 | }); 203 | }, 204 | 205 | _loadImage(src, callback) { 206 | const image = this._createImage(src); 207 | image.onload = () => { 208 | callback(image); 209 | }; 210 | }, 211 | 212 | _readFile(file, callback) { 213 | const reader = new FileReader(); 214 | reader.onload = (event) => { 215 | const data = event.target.result; 216 | callback(data); 217 | }; 218 | reader.readAsDataURL(file); 219 | }, 220 | 221 | _getCanvas(width, height) { 222 | const canvas = document.createElement('canvas'); 223 | canvas.width = width; 224 | canvas.height = height; 225 | return canvas; 226 | }, 227 | 228 | _createImage(src) { 229 | const image = new Image(); 230 | image.src = src; 231 | return image; 232 | }, 233 | 234 | _getSrc(source) { 235 | let src = source; 236 | let type = 'url'; 237 | if (this._isImageElement(source)) { 238 | const imgSrc = source.src; 239 | if (!imgSrc) { 240 | throw new Error('Element must hava src'); 241 | } 242 | src = imgSrc; 243 | type = 'element'; 244 | } else if (this._isVideoElement(source)) { 245 | src = source; 246 | type = 'video'; 247 | } else if (this._isFileObject(source)) { 248 | src = source; 249 | type = 'file'; 250 | } 251 | return { 252 | src, 253 | type, 254 | }; 255 | }, 256 | 257 | _isFileObject(file) { 258 | return (typeof file === 'object' && file.type && file.size > 0); 259 | }, 260 | 261 | _isImageElement(el) { 262 | return (typeof el === 'object' && el.tagName === 'IMG'); 263 | }, 264 | 265 | _isVideoElement(el) { 266 | return (typeof el === 'object' && el.tagName === 'VIDEO'); 267 | }, 268 | 269 | _getImageType(source) { 270 | const { src, type } = this._getSrc(source); 271 | let mimeType = 'image/jpeg'; 272 | if (type === 'file') { 273 | const fileType = source.type; 274 | const outputType = fileType.match(/(image\/[\w]+)\.*/)[0]; 275 | if (typeof outputType !== 'undefined') { 276 | mimeType = outputType; 277 | } 278 | } else { 279 | const arr = imageReg.exec(src); 280 | if (arr && arr[1]) { 281 | mimeType = `image/${arr[1]}`; 282 | } 283 | } 284 | return mimeType; 285 | }, 286 | 287 | }; 288 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["daycaca"] = factory(); 8 | else 9 | root["daycaca"] = factory(); 10 | })(typeof self !== 'undefined' ? self : this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 0); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, exports, __webpack_require__) { 79 | 80 | "use strict"; 81 | 82 | 83 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 84 | 85 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 86 | 87 | // a canvas lib to compress or crop images 88 | 89 | var isNumber = function isNumber(num) { 90 | return typeof num === 'number'; 91 | }; 92 | var imageReg = /[./](png|jpeg|jpg|gif|bmp)/; 93 | 94 | var defaultConfig = { 95 | ratio: 1, 96 | compress: 80, 97 | enableWebWorker: false 98 | }; 99 | 100 | module.exports = { 101 | setConfig: function setConfig(config) { 102 | this._config = _extends(defaultConfig, config); 103 | }, 104 | 105 | 106 | /** 107 | * init image for reset size and rotation 108 | */ 109 | init: function init(src, callback) { 110 | var _this = this; 111 | 112 | var scrTypes = src.split(';'); 113 | var srcType = null; 114 | var image = this._createImage(src); 115 | if (scrTypes.length > 1) { 116 | srcType = scrTypes[0].replace('data:', ''); 117 | } 118 | image.onload = function () { 119 | var cvs = _this._getCanvas(image.naturalWidth, image.naturalHeight); 120 | var ctx = cvs.getContext('2d'); 121 | ctx.drawImage(image, 0, 0); 122 | var newImageData = cvs.toDataURL(srcType); 123 | callback(newImageData); 124 | }; 125 | }, 126 | 127 | 128 | /** 129 | * encode image to base64 130 | * @param {Element|String} el 131 | * @param {Function} callback 132 | */ 133 | base64: function base64(el, callback) { 134 | var _getSrc = this._getSrc(el), 135 | src = _getSrc.src, 136 | type = _getSrc.type; 137 | 138 | if (type === 'file') { 139 | return this._readFile(src, callback); 140 | } else if (type === 'video') { 141 | var video = el; 142 | var cvs = this._getCanvas(video.videoWidth, video.videoHeight); 143 | var ctx = cvs.getContext('2d'); 144 | ctx.drawImage(video, 0, 0); 145 | var newImageData = cvs.toDataURL(); 146 | callback(newImageData, cvs); 147 | } 148 | return this.init(src, callback); 149 | }, 150 | 151 | 152 | /** 153 | * compress image 154 | * @param {el|String} src the source of image 155 | * @param {Number} the quality of image ( 100 = the highest quality) 156 | * @param {Function} callback 157 | */ 158 | compress: function compress(source, quality, callback) { 159 | var _this2 = this; 160 | 161 | var _getSrc2 = this._getSrc(source), 162 | src = _getSrc2.src, 163 | type = _getSrc2.type; 164 | 165 | if (type === 'file') { 166 | return this._readFile(src, function (data) { 167 | _this2._compress(data, source, quality, callback); 168 | }); 169 | } 170 | this._compress(src, source, quality, callback); 171 | }, 172 | _compress: function _compress(src, source, quality, callback) { 173 | var _this3 = this; 174 | 175 | this._loadImage(src, function (image) { 176 | var mimeType = _this3._getImageType(source); 177 | var cvs = _this3._getCanvas(image.naturalWidth, image.naturalHeight); 178 | var ctx = cvs.getContext('2d'); 179 | ctx.drawImage(image, 0, 0); 180 | var newImageData = cvs.toDataURL(mimeType, quality / 100); 181 | callback(newImageData); 182 | }); 183 | }, 184 | 185 | 186 | /** 187 | * crop image via canvas and generate data 188 | */ 189 | crop: function crop(source, options, callback) { 190 | var _this4 = this; 191 | 192 | var _getSrc3 = this._getSrc(source), 193 | src = _getSrc3.src, 194 | type = _getSrc3.type; 195 | 196 | if (type === 'file') { 197 | return this._readFile(src, function (data) { 198 | _this4._crop(data, source, options, callback); 199 | }); 200 | } 201 | this._crop(src, source, options, callback); 202 | }, 203 | _crop: function _crop(src, source, options, callback) { 204 | var _this5 = this; 205 | 206 | this._loadImage(src, function (image) { 207 | // check crop options 208 | if (isNumber(options.x) && isNumber(options.y) && options.w > 0 && options.h > 0) { 209 | var w = options.w, 210 | h = options.h; 211 | 212 | if (options.maxWidth && options.maxWidth < w) { 213 | w = options.maxWidth; 214 | h = options.h * w / options.w; 215 | } 216 | if (options.maxHeight && options.maxHeight < h) { 217 | h = options.maxHeight; 218 | } 219 | if (options.fixedWidth && options.fixedHeight) { 220 | w = options.fixedWidth; 221 | h = options.fixedHeight; 222 | } 223 | var cvs = _this5._getCanvas(w, h); 224 | cvs.getContext('2d').drawImage(image, options.x, options.y, options.w, options.h, 0, 0, w, h); 225 | var mimeType = _this5._getImageType(source); 226 | var data = cvs.toDataURL(mimeType, options.compress / 100); 227 | callback(data); 228 | } 229 | }); 230 | }, 231 | resize: function resize(source, ratio, callback) { 232 | var _this6 = this; 233 | 234 | var _getSrc4 = this._getSrc(source), 235 | src = _getSrc4.src, 236 | type = _getSrc4.type; 237 | 238 | var options = {}; 239 | if (typeof ratio === 'number' || typeof ratio === 'string') { 240 | options = { 241 | ratio: ratio, 242 | compress: defaultConfig.compress 243 | }; 244 | } 245 | if ((typeof ratio === 'undefined' ? 'undefined' : _typeof(ratio)) === 'object') { 246 | options = ratio; 247 | } 248 | if (type === 'file') { 249 | return this._readFile(src, function (data) { 250 | _this6._resize(data, source, options, callback); 251 | }); 252 | } 253 | this._resize(src, source, options, callback); 254 | }, 255 | _resize: function _resize(src, source, options, callback) { 256 | var _this7 = this; 257 | 258 | this._loadImage(src, function (image) { 259 | var w = image.naturalWidth; 260 | var h = image.naturalHeight; 261 | if (options.ratio > 0) { 262 | w = Math.floor(image.naturalWidth * options.ratio); 263 | h = Math.floor(image.naturalHeight * options.ratio); 264 | } else if (typeof options.width === 'number' && typeof options.height === 'number') { 265 | w = Math.floor(options.width); 266 | h = Math.floor(options.height); 267 | } 268 | var cvs = _this7._getCanvas(w, h); 269 | cvs.getContext('2d').drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight, 0, 0, w, h); 270 | var mimeType = _this7._getImageType(source); 271 | var data = cvs.toDataURL(mimeType, options.compress / 100); 272 | callback(data); 273 | }); 274 | }, 275 | 276 | 277 | /** 278 | * rotate image 279 | */ 280 | rotate: function rotate(source, degree, callback) { 281 | var _this8 = this; 282 | 283 | var _getSrc5 = this._getSrc(source), 284 | src = _getSrc5.src, 285 | type = _getSrc5.type; 286 | 287 | if (type === 'file') { 288 | return this._readFile(src, function () { 289 | _this8._rotate(src, source, degree, callback); 290 | }); 291 | } 292 | if (degree % 360 === 0) { 293 | return callback(src); 294 | } 295 | this._rotate(src, source, degree, callback); 296 | }, 297 | _rotate: function _rotate(src, source, degree, callback) { 298 | var _this9 = this; 299 | 300 | this._loadImage(src, function (image) { 301 | var w = image.naturalWidth; 302 | var h = image.naturalHeight; 303 | degree %= 360; 304 | if (degree === 90 || degree === 270) { 305 | w = image.naturalHeight; 306 | h = image.naturalWidth; 307 | } 308 | var cvs = _this9._getCanvas(w, h); 309 | var ctx = cvs.getContext('2d'); 310 | ctx.clearRect(0, 0, w, h); 311 | ctx.fillStyle = 'white'; 312 | ctx.fillRect(0, 0, w, h); 313 | ctx.translate(w / 2, h / 2); 314 | ctx.rotate(degree * Math.PI / 180); 315 | ctx.drawImage(image, -image.naturalWidth / 2, -image.naturalHeight / 2); 316 | var mimeType = _this9._getImageType(source); 317 | var data = cvs.toDataURL(mimeType, 1); 318 | callback(data, w, h); 319 | cvs = null; 320 | ctx = null; 321 | }); 322 | }, 323 | _loadImage: function _loadImage(src, callback) { 324 | var image = this._createImage(src); 325 | image.onload = function () { 326 | callback(image); 327 | }; 328 | }, 329 | _readFile: function _readFile(file, callback) { 330 | var reader = new FileReader(); 331 | reader.onload = function (event) { 332 | var data = event.target.result; 333 | callback(data); 334 | }; 335 | reader.readAsDataURL(file); 336 | }, 337 | _getCanvas: function _getCanvas(width, height) { 338 | var canvas = document.createElement('canvas'); 339 | canvas.width = width; 340 | canvas.height = height; 341 | return canvas; 342 | }, 343 | _createImage: function _createImage(src) { 344 | var image = new Image(); 345 | image.src = src; 346 | return image; 347 | }, 348 | _getSrc: function _getSrc(source) { 349 | var src = source; 350 | var type = 'url'; 351 | if (this._isImageElement(source)) { 352 | var imgSrc = source.src; 353 | if (!imgSrc) { 354 | throw new Error('Element must hava src'); 355 | } 356 | src = imgSrc; 357 | type = 'element'; 358 | } else if (this._isVideoElement(source)) { 359 | src = source; 360 | type = 'video'; 361 | } else if (this._isFileObject(source)) { 362 | src = source; 363 | type = 'file'; 364 | } 365 | return { 366 | src: src, 367 | type: type 368 | }; 369 | }, 370 | _isFileObject: function _isFileObject(file) { 371 | return (typeof file === 'undefined' ? 'undefined' : _typeof(file)) === 'object' && file.type && file.size > 0; 372 | }, 373 | _isImageElement: function _isImageElement(el) { 374 | return (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object' && el.tagName === 'IMG'; 375 | }, 376 | _isVideoElement: function _isVideoElement(el) { 377 | return (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object' && el.tagName === 'VIDEO'; 378 | }, 379 | _getImageType: function _getImageType(source) { 380 | var _getSrc6 = this._getSrc(source), 381 | src = _getSrc6.src, 382 | type = _getSrc6.type; 383 | 384 | var mimeType = 'image/jpeg'; 385 | if (type === 'file') { 386 | var fileType = source.type; 387 | var outputType = fileType.match(/(image\/[\w]+)\.*/)[0]; 388 | if (typeof outputType !== 'undefined') { 389 | mimeType = outputType; 390 | } 391 | } else { 392 | var arr = imageReg.exec(src); 393 | if (arr && arr[1]) { 394 | mimeType = 'image/' + arr[1]; 395 | } 396 | } 397 | return mimeType; 398 | } 399 | }; 400 | 401 | /***/ }) 402 | /******/ ]); 403 | }); --------------------------------------------------------------------------------