├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── babel.config.js ├── jest.config.js ├── package.json ├── postcss.config.js ├── prettier.config.js ├── public ├── demo.html ├── favicon.ico └── index.html ├── src ├── App.vue ├── components │ ├── ImageUploader.vue │ └── index.js ├── main.js └── utils │ └── exif.js ├── tests └── unit │ ├── .eslintrc.js │ └── example.spec.js ├── vue.config.js └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ['plugin:vue/essential', '@vue/prettier'], 7 | rules: { 8 | 'no-console': process.env.NODE_ENV === 'production' ? ['error', { allow: ['warn', 'warning', 'error'] }] : 'off', 9 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 10 | }, 11 | parserOptions: { 12 | parser: 'babel-eslint', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | 23 | # misc 24 | src/utils/exif-full.js 25 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | dist/demo.html -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres (more or less) to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ___ 8 | ## [2.3] - 2020-01-27 9 | ### Fixed 10 | - Update entry points so that the plugin can be used as SFC with local registration ref [issue #32](https://github.com/kartoteket/vue-image-upload-resize/issues/32). 11 | ### Changed 12 | - Slimmed down npm tarball to essentiel files only. 13 | 14 | 15 | ## [2.2] - 2019-12-11 16 | ### Changed 17 | - Changed verbose output object to allways return an exif property (which is `null` if no exifdata) 18 | - Updated all non-major dependencies 19 | 20 | ## [2.1.2] - 2019-11-29 21 | ### Added 22 | - Aded a section on use with nuxt.js (thanks @atymic ) 23 | ### Changed 24 | - Update eslint-utils to 1.4.3 25 | 26 | ___ 27 | ## [2.1.1] - 2019-08-19 28 | ### Changed 29 | - Changed default value of capture property to 'false' to access both camera and gallery on mobile devices, ref [issue #17](https://github.com/kartoteket/vue-image-upload-resize/issues/17 30 | 31 | ___ 32 | ## [2.1.0] - 2019-08-18 33 | ### Added 34 | - New inline exif-reader utility based on exif.js, ref [issue #15](https://github.com/kartoteket/vue-image-upload-resize/issues/15) 35 | - New output format "info" that includes details on image dimensions, ref [issue 19](https://github.com/kartoteket/vue-image-upload-resize/issues/19) 36 | 37 | ### Changed 38 | - Updated dependecies. 39 | - Updated Readme. 40 | - Re-organized 'verbose' output to include dataUrl, the new info output and and exif data. 41 | 42 | ### Removed 43 | - exif-js-js dependecy, ref [issue #15](https://github.com/kartoteket/vue-image-upload-resize/issues/15) 44 | 45 | ## [2.0.4] - 2019-01-23 46 | ### Fixed 47 | - A bump release to update npm dist files with 2.0.3 changes 48 | 49 | ## [2.0.3] - 2018-12-20 50 | ### Fixed 51 | - Fixes missing binding on accept attribute (thanks @XeO3 ) 52 | 53 | ## [2.0.2] - 2018-12-13 54 | ### Added 55 | - [codebox.io demo](https://codesandbox.io/s/mqnow97omj?module=%2Fsrc%2Fcomponents%2FHelloWorld.vue) 56 | ### Changed 57 | - Updated Readme to reflect new Plugin arcitecture 58 | - Update dependencies vue and vue-template-compiler 59 | 60 | ## [2.0.1] - 2018-12-12 61 | ### Fixed 62 | - Fixed incorrect paths in package.json 63 | 64 | ## [2.0.0] - 2018-12-12 65 | 66 | ### Added 67 | - This CHANGELOG file 68 | - New prop/attribute 'accept' to open for use with other filetypes than just 'image/*' (thank you [@Pitouli](https://github.com/Pitouli)) 69 | - New prop 'doNotResize' to ignore mutation of selected file types (thank you [@Pitouli](https://github.com/Pitouli)) 70 | - Added 'file' as outputformat 71 | - Attached exif-data to verbose output. Ref issue #5 (thank you [@adamcolejenkins](https://github.com/adamcolejenkins)) 72 | 73 | ### Changed 74 | - Total re-factor to the Vue CLI-3 framework 75 | 76 | 77 | # Non-tracked earlier versions 78 | ## [1.1.5] - 2018-01-31 79 | ## [1.1.4] - 2017-11-20 80 | ## [1.1.3] - 2017-11-10 81 | ## [1.1.2] - 2017-11-01 82 | ## [1.1.1] - 2017-11-01 83 | ## [1.1.0] - 2017-11-01 84 | ## [1.0.2] - 2017-10-17 85 | ## [1.0.1] - 2017-09-28 86 | ## [1.0.0] - 2017-09-14 87 | ## [0.5.0] - 2017-08-07 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kartoteket (3by5) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Image Upload and Resize 2 | A Vue.js Plugin Component for client-side image upload with optional resizing and exif-based autorotate. 3 | 4 | This plugin was created for the use in a webapp scenario where we had a large number of end users uploading camera photos from their mobile devices on partly low end data plans. The primary purpose is therefor _client-side resizing_ and if needed exif-based auto-rotation. It can however also be use simply as a file upload component. 5 | 6 | Based on [ImageUploader] (https://github.com/rossturner/HTML5-ImageUploader) by Ross Turner. The plugin makes use of an optional dependency [JavaScript Canvas to Blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob) (for blob output). 7 | 8 | [![vue2](https://img.shields.io/badge/vue-2.x-brightgreen.svg)](https://vuejs.org/) 9 | 10 | ## Demo 11 | [![Edit Vue Image Upload and Resize ](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/mqnow97omj?module=%2Fsrc%2Fcomponents%2FHelloWorld.vue) 12 | 13 | 14 | ## Installation 15 | ### yarn 16 | ```bash 17 | yarn add vue-image-upload-resize 18 | ``` 19 | ### npm 20 | ```bash 21 | npm install --save vue-image-upload-resize 22 | ``` 23 | 24 | ### Usage 25 | 26 | #### Global Registration 27 | In script entry point 28 | ```js 29 | import ImageUploader from 'vue-image-upload-resize' 30 | Vue.use(ImageUploader); 31 | ``` 32 | 33 | #### Local Registration 34 | In component 35 | ```js 36 | import ImageUploader from 'vue-image-upload-resize' 37 | export default { 38 | components: { 39 | ImageUploader 40 | }, 41 | // ... 42 | } 43 | ``` 44 | 45 | 46 | #### Using with Nuxt.js 47 | 48 | Currently the componenet is tied to the `window` object, so it can't be server side rendered. 49 | To get around this you need to install the componenet as a client side plugin. 50 | 51 |
Instructions 52 |

53 | 54 | 1) Create a new file: `plugins/vue-image-upload.js`, and add the following code: 55 | ```js 56 | import Vue from 'vue' 57 | import ImageUploader from 'vue-image-upload-resize' 58 | 59 | Vue.use(ImageUploader) 60 | ``` 61 | 62 | 2) In your `nuxt.config.js`, add the [client plugin](https://nuxtjs.org/api/configuration-plugins): 63 | 64 | ```js 65 | export default { 66 | // ... other config 67 | plugins: [ 68 | { src: '~/plugins/vue-image-upload.js', mode: 'client' }, 69 | ] 70 | } 71 | ``` 72 | 73 | 3) When you use the componenent inside a page, make sure to wrap it in `` tags (`` in v < 2.9.0, [docs](https://nuxtjs.org/api/components-client-only/)). 74 | ```html 75 | 82 | ``` 83 | 84 |

85 |
86 | 87 | 88 | 89 | ## As global script 90 | ```html 91 | 92 | ``` 93 | The global script automatically registers as a global componenet. See [public/demo.html](https://github.com/kartoteket/vue-image-upload-resize/blob/master/public/demo.html) for example use. 94 | 95 | 96 | ## Markup 97 | 98 | ```html 99 | 116 | ``` 117 | 118 | ## Input label slot 119 | An optional label tag can be added as a slot 120 | 121 | ### Example 122 | ```html 123 | 124 | 132 | 133 | 134 | ``` 135 | 136 | ## Settings 137 | 138 | ### Props 139 | 140 | #### id 141 | The ID for the file input, required if more than one instance should be used on the same page. 142 | * default fileInput 143 | * type String 144 | 145 | #### maxWidth 146 | An integer in pixels for the maximum width allowed for uploaded images, selected images with a greater width than this value will be scaled down. 147 | * type: Number 148 | * default: 1024 149 | 150 | #### maxHeight 151 | An integer in pixels for the maximum height allowed for uploaded images, selected images with a greater height than this value will be scaled down. 152 | * type: Number, 153 | * default: 1024 154 | 155 | #### maxSize 156 | *NB Is broken, see https://github.com/rossturner/HTML5-ImageUploader/issues/13.* 157 | A float value in megapixels (MP) for the maximum overall size of the image allowed for uploaded images, selected images with a greater size than this value will be scaled down before upload. If the value is null or is not specified, then maximum size restriction is not applied 158 | * type: Number, 159 | * default: null 160 | 161 | #### quality 162 | A float between 0 and 1.00 for the image quality to use in the resulting image data, around 0.9 is recommended. 163 | * type: Number, 164 | * default: 1.00 165 | 166 | #### scaleRatio 167 | Allows scaling down to a specified fraction of the original size. (Example: a value of 0.5 will reduce the size by half.) Accepts a decimal value between 0 and 1. 168 | * type: Number, 169 | * default: null 170 | 171 | #### autoRotate 172 | A boolean flag, if true then EXIF information from the image is parsed and the image is rotated correctly before upload. If false, then no processing is performed, and unwanted image flipping can happen. This functionality is based on the library [exif-js] https://github.com/exif-js/exif-js. 173 | * type: Boolean, 174 | * default: false 175 | 176 | #### preview 177 | A boolean flag to toogle an img-tag displaying the uploaded image. When set to false no img-tag is displayed. 178 | * type: Boolean, 179 | * default: true 180 | 181 | #### outputFormat 182 | Sets the desired format for the returned image. Available formats are 183 | - **string** - image as base64 string. 184 | - **info** - object with image info only [name, type, newWidth, newHeight, orgWidth, orgHeight, aspectRatio (as Float), modifiedTimestamp, modifiedDate]. 185 | - **verbose** - object with 'dataUrl' (image as base64 string), 'info' (image info) and 'exif' data (`null` if not available). 186 | - **blob** - image as A Blob object. **NB: The *'blob'* format requires that the [blueimp-canvas-to-blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob) library is loaded.** If not, a warning is echoed to the console. 187 | - **file** - unmodified uploaded File object. 188 | 189 | * type: String, 190 | * default: 'string' 191 | 192 | #### className 193 | Sets the desired class name for the input element 194 | * type: String or Array 195 | * default: 'fileinput' 196 | 197 | #### capture 198 | Sets an optional capture attribute (camera, user, environment) to the input element (only for mobile devices). 199 | The "camera" value let's the browser decide which camera to use, while the "user" and "environment" values tell the browser to prefer the front and rear cameras, respectively. To also access the device gallery capture must be set to 'false' 200 | * type: String 201 | * default: false (off) 202 | 203 | #### accept 204 | Specifies the types of files that can be submitted through the file upload. The types can be valid file extension starting with the STOP character (e.g: ".gif, .jpg, .png") or wildcare file types (e.g. audio/*, video/*, image/*"). To specify more than one value, separate the values with a comma 205 | * type: String 206 | * default: 'image/*' 207 | 208 | #### doNotResize 209 | Specifies filetypes that will not be resized. Accepts an array of image's extension. If only 1 extension, it can be provided directly as a string. 210 | * type String or Array 211 | * default: null 212 | 213 | #### debug 214 | How much to write to the console. 0 = silent. 1 = quiet. 2 = loud 215 | * type: Number, 216 | * default: 0 217 | 218 | ### Events 219 | 220 | #### @input 221 | Returns the processed image in requested outputformat. From this event you can add optional hooks. 222 | 223 | ```html 224 | 225 | ``` 226 | 227 | ```js 228 | methods: { 229 | setImage: function (file) { 230 | this.hasImage = true 231 | this.image = file 232 | } 233 | } 234 | 235 | ``` 236 | 237 | #### @onUpload 238 | On start of upload. 239 | 240 | #### @onComplete 241 | On end of upload. 242 | 243 | 244 | 245 | ## Optional dependencies 246 | If ```outformat="blob"``` the required libraby canvas-to-blob.min.js must be available. If the plugin is loaded with ``` 252 | ``` 253 | 254 | If loaded as module, npm handles all dependecies. 255 | 256 | ## Roadmap and todos 257 | 1. Progress report 258 | 2. Support multiple files 259 | 3. Implement completion callback 260 | 4. Propper unit testing of events 261 | 5. ~~Clean up scaffolding and project files~~ 262 | 6. Exclude optional dependecies from package 263 | 264 | ## Project setup 265 | ``` 266 | yarn install 267 | ``` 268 | 269 | ### Compiles and hot-reloads for development 270 | ``` 271 | yarn run serve 272 | ``` 273 | 274 | ### Compiles and minifies for production 275 | ``` 276 | yarn run build 277 | ``` 278 | 279 | ### Compiles and minifies lib bundle 280 | ``` 281 | yarn run build-lib 282 | ``` 283 | 284 | ### Run your tests 285 | ``` 286 | yarn run test 287 | ``` 288 | 289 | ### Lints and fixes files 290 | ``` 291 | yarn run lint 292 | ``` 293 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/app'], 3 | } 4 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest', 5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 6 | '^.+\\.jsx?$': 'babel-jest', 7 | }, 8 | moduleNameMapper: { 9 | '^@/(.*)$': '/src/$1', 10 | }, 11 | snapshotSerializers: ['jest-serializer-vue'], 12 | testMatch: ['**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'], 13 | testURL: 'http://localhost/', 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-image-upload-resize", 3 | "version": "2.3.0", 4 | "description": "A simple Vue.js component for client-side image upload with resizing", 5 | "author": "Svale Fossåskaret ", 6 | "scripts": { 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint", 10 | "build-lib": "vue-cli-service build --target lib --name vue-image-upload-resize src/components/index.js", 11 | "build-wc": "vue-cli-service build --target wc --name vue-image-upload-resize src/components/ImageUploader.vue", 12 | "test": "vue-cli-service test:unit" 13 | }, 14 | "dependencies": { 15 | "blueimp-canvas-to-blob": "^3.14.0", 16 | "vue": "^2.5.17" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "^3.2.0", 20 | "@vue/cli-plugin-eslint": "^3.2.0", 21 | "@vue/cli-plugin-unit-jest": "^3.2.0", 22 | "@vue/cli-service": "^3.2.0", 23 | "@vue/eslint-config-prettier": "^5.0.0", 24 | "@vue/test-utils": "^1.0.0-beta.20", 25 | "babel-core": "7.0.0-bridge.0", 26 | "babel-eslint": "^10.0.1", 27 | "babel-jest": "^24.8.0", 28 | "eslint": "^5.8.0", 29 | "eslint-plugin-prettier": "^3.1.0", 30 | "eslint-plugin-vue": "^5.0.0-0", 31 | "vue-template-compiler": "^2.5.17" 32 | }, 33 | "files": [ 34 | "dist", 35 | "src/components/ImageUploader.vue", 36 | "src/utils/exif.js" 37 | ], 38 | "keywords": [ 39 | "vue", 40 | "upload", 41 | "uploader", 42 | "img", 43 | "image", 44 | "resize" 45 | ], 46 | "license": "MIT", 47 | "main": "dist/vue-image-upload-resize.umd.js", 48 | "module": "dist/vue-image-upload-resize.common.js", 49 | "unpkg": "dist/vue-image-upload-resize.umd.min.js", 50 | "browser": { 51 | "./sfc": "src/ImageUploader.vue" 52 | }, 53 | "repository": { 54 | "type": "git", 55 | "url": "git+https://github.com/kartoteket/vue-image-upload-resize.git" 56 | }, 57 | "bugs": { 58 | "url": "https://github.com/kartoteket/vue-image-upload-resize/issues" 59 | }, 60 | "homepage": "https://github.com/kartoteket/vue-image-upload-resize#readme" 61 | } 62 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'es5', 3 | tabWidth: 2, 4 | semi: false, 5 | singleQuote: true, 6 | printWidth: 200, 7 | } 8 | -------------------------------------------------------------------------------- /public/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue Image Upload and Resize Demo Page 6 | 7 | 8 | 9 | 19 | 20 | 21 |
22 | 35 | 36 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartoteket/vue-image-upload-resize/64f28fb678bba3d62c715fdba8756390df0cf66d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-image-upload-resize 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 48 | 49 | 62 | -------------------------------------------------------------------------------- /src/components/ImageUploader.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 575 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-image-upload-resize 3 | * Based on ImageUploader (c) Ross Turner (https://github.com/rossturner/HTML5-ImageUploader) 4 | * Adapted by (c) 2018 Svale Fossåskaret (http://kartoteket.as/team/svale.html / @Fossesvale) 5 | * @license MIT. 6 | */ 7 | // Import vue component 8 | import component from './ImageUploader.vue' 9 | 10 | // Declare install function executed by Vue.use() 11 | export function install(Vue) { 12 | if (install.installed) return 13 | install.installed = true 14 | Vue.component('ImageUploader', component) 15 | } 16 | 17 | // Create module definition for Vue.use() 18 | const plugin = { 19 | install, 20 | } 21 | 22 | // Auto-install when vue is found (eg. in browser via