GithubHelp home page GithubHelp logo

alessiomaffeis / vue-picture-input Goto Github PK

View Code? Open in Web Editor NEW
889.0 21.0 156.0 2.23 MB

Mobile-friendly picture file input component for Vue.js 2-3 with image preview, drag and drop, EXIF orientation, and more

License: MIT License

Vue 96.50% JavaScript 3.50%
vue component input picture image preview

vue-picture-input's Introduction

vue-picture-input

Mobile-friendly picture file input component for Vue.js 2-3 with image preview, drag and drop, EXIF orientation, and more.

vue-pictur-input-demo

Installation

npm

npm install --save vue-picture-input

yarn

yarn add vue-picture-input

Usage

<template>
  <div class="hello">    
    <picture-input 
      ref="pictureInput"
      width="600" 
      height="600" 
      margin="16" 
      accept="image/jpeg,image/png" 
      size="10" 
      button-class="btn"
      :custom-strings="{
        upload: '<h1>Bummer!</h1>',
        drag: 'Drag a 😺 GIF or GTFO'
      }"
      @change="onChange">
    </picture-input>
  </div>
</template>
<script>
import PictureInput from 'vue-picture-input'

export default {
  name: 'app',
  data () {
    return {
    }
  },
  components: {
    PictureInput
  },
  methods: {
    onChange (image) {
      console.log('New picture selected!')
      if (image) {
        console.log('Picture loaded.')
        this.image = image
      } else {
        console.log('FileReader API not supported: use the <form>, Luke!')
      }
    }
  }
}
</script>

You can also use it directly in the browser through unpkg's CDN (or jsDelivr):

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/vue"></script>
  <script src="https://unpkg.com/vue-picture-input"></script>
  <title>In the browser!</title>
</head>
<body>
  <div id="app">
    <p>{{ message }}</p>
    <picture-input></picture-input>
  </div>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      },
      components: {
        'picture-input': PictureInput
      }
    })
  </script>
</body>
</html>

Example project

Try it on CodeSandbox: https://codesandbox.io/s/github/alessiomaffeis/vue-picture-input-example

Props

  • width, height: (pixels, optional) the maximum width and height of the preview container. The picture will be resized and centered to cover this area. If width is not specified, the preview container will expand to full width. If height is not specified, it will be set equal to width.
  • crop: (boolean, optional) set :crop="false" if you wish to disable cropping. The image will be resized and centered in order to be fully contained in the preview container. Default value: true.
  • margin: (pixels, optional) the margin around the preview container. Default value: 0.
  • radius: (percentage, optional) The border-radius value for the container. Set radius="50" to get a circular container. Default value: 0.
  • plain: (boolean, optional) Set :plain="true" to remove the inner border and text. Default value: false.
  • accept: (media type, optional) the accepted image type(s), e.g. image/jpeg, image/gif, etc. Default value: 'image/*'.
  • size: (MB, optional) the maximum accepted file size in megabytes.
  • removable: (boolean, optional) set :removable="true" if you want to display a "Remove Photo" button. Default value: false.
  • hideChangeButton: (boolean, optional) set :hideChangeButton="true" if you want to hide the "Change Photo" button. Default value: false.
  • id, name: (string, optional) the id and name attributes of the HTML input element.
  • buttonClass: (string, optional) the class which will be applied to the 'Change Photo' button. Default value: 'btn btn-primary button'.
  • removeButtonClass: (string, optional) the class which will be applied to the 'Remove Photo' button. Default value: 'btn btn-secondary button secondary'.
  • prefill: (image url or File object, optional) use this to specify the path to a default image (or a File object) to prefill the input with. Default value: empty.
  • prefillOptions: (object, optional) use this if you prefill with a data uri scheme to specify a file name and a media or file type:
  fileName: (string, optional) the file name
  fileType: (string, optional) the file type of the image, i.e. "png", or
  mediaType: (string, optional) the media type of the image, i.e. "image/png"
  • toggleAspectRatio: (boolean, optional) set :toggleAspectRatio="true" to show a button for toggling the canvas aspect ratio (Landscape/Portrait) on a non-square canvas. Default value: false.
  • autoToggleAspectRatio: (boolean, optional) set :autoToggleAspectRatio="true" to enable automatic canvas aspect ratio change to match the selected picture's. Default value: false.
  • changeOnClick: (boolean, optional) set :changeOnClick="true" to open image selector when user click on the image. Default value: true.
  • aspectButtonClass: (string, optional) the class which will be applied to the 'Landscape/Portrait' button. Default value: 'btn btn-secondary button secondary'.
  • zIndex: (number, optional) The base z-index value. In case of issues with your layout, change :zIndex="..." to a value that suits you better. Default value: 10000.
  • alertOnError: (boolean, optional) Set :alertOnError="false" to disable displaying alerts on attemps to select file with wrong type or too big. Default value: true.
  • customStrings: (object, optional) use this to provide one or more custom strings (see the example above). Here are the available strings and their default values:
  • capture: (string, optional) use this if you want to allow image capture from capture devices (e.g. camera)
{
  upload: '<p>Your device does not support file uploading.</p>', // HTML allowed
  drag: 'Drag an image or <br>click here to select a file', // HTML allowed
  tap: 'Tap here to select a photo <br>from your gallery', // HTML allowed
  change: 'Change Photo', // Text only
  remove: 'Remove Photo', // Text only
  select: 'Select a Photo', // Text only
  selected: '<p>Photo successfully selected!</p>', // HTML allowed
  fileSize: 'The file size exceeds the limit', // Text only
  fileType: 'This file type is not supported.', // Text only
  aspect: 'Landscape/Portrait' // Text only
}

Events

  • change: emitted on (successful) picture change (prefill excluded). The image is passed along with the event as a Base64 Data URI string. If you need to access the underlying image from the parent component, add a ref attribute to picture-input (see the example above). You may want to use this.$refs.pictureInput.image (Base64 Data URI string) or this.$refs.pictureInput.file (File Object)
  • prefill: emitted on default image prefill.
  • remove: emitted on picture remove.
  • click: emitted on picture click.
  • error: emitted on error, along with an object with type, message, and optional additional parameters.

TODOs

  • Client-side resizing and cropping
  • Add tests

Contributions

All contributions are welcome, as long as they are within the scope of the project. Please open a new issue before submitting a pull request.

You should follow the Javascript Standard Style guidelines: https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style

vue-picture-input's People

Contributors

alessiomaffeis avatar asichi avatar bennyalex avatar clarkzsd avatar cvaize avatar dependabot[bot] avatar ejlocop avatar farin avatar fatlinesofcode avatar gorbunovav avatar hootlex avatar indr avatar julianfox avatar katlasik avatar markkimsal avatar mattapril avatar peterbaricic avatar pi0 avatar ryanhaidy avatar saratitan avatar sebastientainon avatar tobyryuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-picture-input's Issues

when used multiple picture-inputs and remove one, picture in canvas stays

Hello @alessiomaffeis , thanks for this plugin, very useful

I'm trying to use multiple picture-inputs in a component, actually users should add and remove options on a form

So my problem is:
I add multiple picture-inputs, lets say 3 of them
Select a picture for 2nd one
When I deleted 2nd option it should be disappear with it's selection and preview
But instead of that; one option dissappears but preview stays

I know it sounds complicated, so I prepared a demo on jsfiddle: https://jsfiddle.net/ugurarici/eywraw8t/164462/

And for a quick look you can see it in action here: https://gph.is/2uhzBUs

Maybe it's because of the way i constructed it (by creating a loop with photoOptions array and adding and deleting options by adding and deleting new elements to/from photoOptions array)

Thanks again, looking for your answer and suggestions about how to solve it.

:crop="false" bug

If crop=false sometimes image scales incorrectly. My fix at drawImage in the !crop branch:

        if (this.imageRatio > 1) {
          scaledHeight = scaledWidth / this.imageRatio
          if (scaledHeight > this.previewHeight){
            scaledHeight = this.previewHeight;
            scaledWidth  = scaledHeight * this.imageRatio;

            offsetX = (this.previewWidth - scaledWidth) / 2
          }
          else{
            offsetY = (this.previewHeight - scaledHeight) / 2
          }
        } else {
          scaledWidth = scaledHeight * this.imageRatio
          if (scaledHeight > this.previewHeight){
            scaledWidth  = this.previewWidth;
            scaledHeight = scaledWidth / this.imageRatio;

            offsetY = (this.previewHeight - scaledHeight) / 2
          }
          else{
            offsetX = (this.previewWidth - scaledWidth) / 2
          }
        }

Default Picture

Hi
Assume that the form to edit News, is there any way to fill its vue-picture-input component with its image?

Clear input

There is a way to clear it manualy? Needs to be mentioned in Docs :)

Drag and drop of URLs

In my app, I would like to allow users to drag and drop an image from a different webpage.

If I drop an image it shows an error:
image

Would it be possible to fire a different event to process the drop data in a different way ?

There is a sample of what I cant to accomplish: http://jsfiddle.net/kkcMH/7/

Loading from url

Thank you for making the excellent vue picture input. My question is: how would I load the image not by click or drop, but from a given url? What function would I have to use for that?

fails on prefill in ie11

ie11 doesn't support File constructor OOB
I fixed this with next code found here jimmywarting/FormData#11 :
let File = window.File

try {
new File([], '')
} catch(e) {
File = class File extends Blob {
constructor(chunks, filename, opts = {}){
super(chunks, opts)
this.lastModifiedDate = new Date()
this.lastModified =+ this.lastModifiedDate
this.name = filename
}
}
}

This file type is not supported error after prefill

Hi,

The plugin works great without prefill. However, if I prefill an image that works fine. But if I then want to upload/select a new image, I get the error (This file type is not supported). If I dismiss the error the image is still inserted, and it is a valid image. If I dont prefill any image and select the same image, I do not get the error.

I use: accept="image/jpeg,image/png"

Cant's resize img size with v-model

I want to resize img with vue

picture-input(v-bind:width="iwidth"  v-bind:height="iheight" @change="onChange")
input.input(v-model="iwidth" placeholder="width")
input.input(v-model="iheight" placeholder="height")

data () {
  return {
    iwidth: 500,
    iheight: 250
  }
}

And I don't need the button, but still can't set with css, only using javascript to set style.

Empty 'file' with .ico file

If I upload an ICO file, the name and type in file in $ref is empty and not regonized by the server.

Edit: Fixed by using an other ico file. File was probely invalid.

Edit 2: Issue still valid, i have to change an ico in order to get the correct file. Strange issue..

How can I use this with Browserify?

Thanks for creating and sharing this library!

It works great for me with Webpack, but Browserify+Vueify is choking on the single-file-component syntax:

SyntaxError: Unexpected token: operator (<) while parsing file: /Users/maxheiber/project/node_modules/vue-picture-input/PictureInput.vue

When I copy PictureInput.vue into the same directory as the one from which I'm requireing it everything works fine. Maybe Browserify doesn't like applying transforms inside node_modules?

As a workaround, in our Gulp script, I tried:

browserify().require(files).transform(vueify, {global: true})

instead of:

browserify().require(files).transform(vueify, {}})

but it made no difference.

Do you have any recommendations? If there's no easy fix for Browserify, would you accept a PR for adding a build step to vue-picture-input?

v-model support

Hi,

Is it possible to add v-model support since all vue components normally work that way?

Simply add the value prop, set a data prop (eg model = this.value) and make sure to $emit('input', this.model) to support this.

Default image onerror

Hi ya,

Nice plugin! thanks!
Just wondering if you could add an onerror prefill option? prehaps. So if my image can't be found then i can put in a default?

Thanks

Add unit tests

I'm using the library and so far so good but it'll be better to have unit tests for reliability.

Preload outer-source

I'm using outer source for my images. and on preload that's not accepted. there is a way to enable it?

preloadImage (source) { if (typeof source === 'object') { this.imageSelected = true this.image = '' if (this.supportsPreview) { this.loadImage(source) } else { this.$emit('change') } return } let headers = new Headers() headers.append('Accept', 'image/*') fetch(source, { method: 'GET', mode: 'same-origin', headers: headers }).then(response => { return response.blob() }) .then(imageBlob => { let e = { target: { files: [] } } const fileName = source.split('/').slice(-1)[0] let fileType = fileName.split('.').slice(-1)[0] fileType = fileType.replace('jpg', 'jpeg') e.target.files[0] = new File([imageBlob], fileName, { type: 'image/' + fileType }) this.onFileChange(e) }) .catch(err => { console.log('Failed loading prefill image: ' + err.message) }) } },

Feature request: Remove image?

What's the best way to remove the image after input?

Eg. User fills form, uploads a profile image but decided not to send image before submitting.

Is there a built in method?

babel config conflict

I'm trying to migrate a project from vue-cli 2.x to 3.0, every thing works fine except this module for which i get this error:

 ERROR  Failed to compile with 1 errors                                                                                                                                                                                                10:10:46

 error  in ./node_modules/vue-picture-input/PictureInput.vue

Module build failed: Error: Cannot find module 'babel-preset-env' from 'C:\webdev\rsg4\node_modules\vue-picture-input'
- Did you mean "@babel/env"?

A suggested fix from @LinusBorg https://forum.vuejs.org/t/errors-moving-to-vue-cli-3-0/29397/6

remove the babel config from their npm package by adding it to .npmignore

Will the suggested workaround be possible.

Thanks in advance.

Charles.

how to save file path - issue solved

Hi i awesome library. I was able to save image. but its saving as base64. i want to save in a directory. like
img/logo.png. How can i do that?

issue is solved.

File not recognized by Laravel

Unfortunately I wasn't able to use this package as is to process uploads via VueJS into Laravel for storing.
From my testing it seemed like Laravel was not getting enough file details (e.g. $request->file('file') and $request->hasFile('file') were failing.

Changing in PictureInput.vue the two references from this.image to this.file did the trick.

Not sure if this has anything to do with my setup, if not, then feel free to consider this as a code modification suggestion.

Multiple Instances Causing Error

When using multiple instances of the component, adding an image to any instance but the last one gets the response FileReader API not supported.

However after adding an image to the last instance of the component, everything works as expected. Meaning if I start by placing an image in the last instance, I can go back to early instances and place images with no issue. Not sure why separate components would be interacting in this way.

To clarify the image itself appears, but the this.$refs.pictureInput.file reference is empty.

Display: flex prevents the component from displaying

Hi,

I wanted to have multiple instances of your component next to each other (as a grid). The best way to that for me would be to have the picture-input tags embed in a div with display:flex.

However, this makes all the picture-input components not displayed.

How to POST image using axios

Hello,

I'm not having much success sending the image data as POST using axios and this plugin. Here's what my request looks like:

this.axios.post(
    this.getApiBaseUrl + '/partners/' + this.getPartnerId + '/basic-details', 
    {
         profile_photo: this.$refs.profilePic.image,
    }
);

At the backend, the profile_photo variable arrives as a string, and not as a file object. Any help will be much appreciated!

Optional height and/or width

This is a very nice plugin, with all the options I can imagine! Good job!

I however cant seem to achieve a rather trivial thing here:
I have to specify both height and width or leave both. If I specify height only or width only it doesn't show

What I want to achieve is very simple: adapt the full width of the container i.e 100%, but specify a height, maybe 300px. How can I achieve this?

z-index goes over everything

It's not that hard to fix on flow but it goes over everything if you don't have relative z-index: 0.

I guess it wont be hard to fix it good luck :)

Remove event emitted also when component is destroyed

Hi,
When watching prefill var, this.removeImage() is triggered when the component is destroyed :

watch: {
    prefill () {
      if (this.prefill) {
        this.preloadImage(this.prefill, this.prefillOptions)
      } else {
         this.removeImage()
      }
    }
  }

I am instancing the picture input component with a for loop in Vue JS. When the user clicks on the remove button, a first "remove" event is triggered. Then I catch the event to remove the image from my array which computes the for loop. At this point, the picture-input component is removed from the UI and a second "remove" event is triggered (which I don't want to catch).

Could be nice if we had the option to choose whether or not to trigger a "remove" event when the component is destroyed or if it was a different event.

Doesn't work.

I guess I've done what I had to do to use this plugin, but it looks like it's not working at all. The drag and drop box is not even showing.

Feature request: Prefill image

I'd like to be able to prefill the image area.

  1. Create a article with a main picture.
  2. Edit the article and the input box is pre-filled with main picture.

vue does not reuse picture-input component

I have a vue component - lets call it 'parent' - which has picture-input as a child component. In html I render picture-input as:

        <picture-input id='profilePictureInput'
                       ref="pictureInput"
                       v-if="credentials.publish_profile === 'true'"
                       @change="imageHasChanged"
                       @remove="imageRemoved"
                       accept="image/jpeg, image/png, image/jpg"
                       size="0.5"
                       margin="0"
                       :crop="false"
                       :width="400"
                       :height="256"
                       :removable="true"
                       :hideChangeButton="true"
                       removeButtonClass="ui red button"
                       v-bind:customStrings="customPictureInputStrings">
        </picture-input>

The problem is, that each time the router navigates to the parent, picture-input is rendered only once in html ( which is okay ) but it creates a new picture-input vue component. In effect, I end up with multiple picture-input vue components. If I then run a function of picture-input, it gets called multiple times, once in each picture-input vue component...

How can I make sure that picture-input only creates one picture-input vue component for given id ? Is the behaviour I am getting the result of a bug in picture-input or am I doing something wrong?

Demo is broken

Demo is not working:
https://codesandbox.io/s/github/alessiomaffeis/vue-picture-input-example

Error
Could not find/install babel plugin 't': Cannot find module 'babel-plugin-t' from '/src'
▶ 10 stack frames were collapsed.
This screen is visible only in development. It will not appear if the app crashes in production.
Open your browser’s developer console to further inspect this error.
This error overlay is powered by `react-error-overlay` used in `create-react-app`.

Feature request: get crop and orientation data

Do you plan to emit the crop and orientation data from the canvas preview?
It seems not possible with the actual code.

I don't know if it's in the scope of vue-picture-input.

My use case would be to create and save on server side the image with the exact crop and orientation than the preview but in full size.

The best approach for me is to emit an object after every change with all the details (crop, orientation) in addition to the image file.

An other solution is to directly generate the image (cropped and oriented) with canvas, but I don't know if it's the right approach especially with the need to generate a full size image.

:prefill emits change

:prefill emits change. which is not that logical since its prefill? not a change?

mobile browser compatible problem

There are some incompatible problems when I use this plugin. Is this project compatible with IE10+? In Wechat's in-app browser, click event has no response, which means this plugin is totally unable to use!

Change fileInput's files value on drag and drop.

Hi there. First of all, thanks for your work on this component.

Earlier today I had issues with the file uploader not updating the input element's file value on drag-and-drop. This was creating problems as I was using Django's forms without any trickery. After some searching I found this Stack Overflow answer which shows that you can set file inputs from FileLists – in this component, this can be accomplished by putting this.$refs.fileInput.files = files near the end of onFileChange.

Is there a reason this isn't implemented currently?

If not, I can create a PR if you wish.

Responsiveness

Responsive part is not realy working. I'm trying to use it small sized like 200x200 and text and the borders are going crazy. is it only me?

[Request] Add remove & change slots

Hey,
it would be nice to have two slots: remove and change to specify an own component for these actions.
When clicking on the slot item, it will call the right methods to remove or to change the image.

Aspect ratio not updated

Hi !
Setting :autoToggleAspectRatio="true" does not update the ratio of the canvas after uploading the file.

Thanks.

Height set to 0 when inside a hidden element

I have vue-picture-input inside of a bootstrap collapse that is hidden on page load.
When expanding the collapsed element the picture is set to height 0 even though i've specified a height and width in the props.

Looks like the initial call to onResize might be the culprit..

Currently I am working around this by wrapping the component in a v-if to only render when the parent div is displayed. But it would be nice if it was set to the correct height initially, because the hieght calculation done by the bootstrap collapse is thrown off as a result, and the expand animation jumps once this component renders.

Component does not work

this component shows on page, but does not work, webpack2, vue2, chrome/safari
what should i do?
i try it on new project(vue init webpack) & on my existing project:
w/ new project picture-input shows "File open dialog", but nothing actions else
w/ existing project component only shows, but dont have reaction on click and drop

it's not working :(

New Feature

Please how do i display an image from a database in the preview panel of vue-picture-input..
Anybody have any idea?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.