0

Is there by any chance a way of letting the user select an image from his hard drive and without submitting it to the server use this image in the browser?

I need this because I want the users to be able to crop an image before sending this cropped image to the server (thus saving a post and some bytes of data).

What I tried to do is using an input type file and then capturing the submit event, but the value from the input is just a fake path (useless).

Any help would be greatly appreciated.

Pablo Mescher
  • 26,057
  • 6
  • 30
  • 33
  • It would be bad if web-based javascript could manipulate files on the client's hard drive. – A. Webb Nov 01 '12 at 13:06
  • but in my case the user is willingly filling an input with the image. I'm not trying to hack my way through the user's harddrive – Pablo Mescher Nov 01 '12 at 13:08
  • This question is relevant: http://stackoverflow.com/questions/3489133/full-path-from-file-input-using-jquery As you can't get the path there's no way to load the image, for example through a `` element. In fact, as I just discovered, if you even try to create an `img` element loading a local file path you'll get the error `Not allowed to load local resource:` in your browser's console. – M1ke Nov 01 '12 at 13:08
  • @PabloMescher Sure, *you* might not be trying to hack the user's files, but there's no way for the browser to know that your intentions are not malicious. Hence JS interactions with the file selection dialogue (and the file system in general) are extremely limited by design. – Vala Nov 01 '12 at 13:14
  • so theres no way to get the image data? sad.. – Pablo Mescher Nov 01 '12 at 13:18

5 Answers5

5

Here is a very basic example (with many globals, without input validation...) of image scaling: http://jsfiddle.net/89HPM/3/ . It's using the File API and a canvas element. As @anu said the save can be done using toDataUrl method of the canvas. In similar way you can achieve crop.

JavaScript

(function init() {
    document.getElementById('picture').addEventListener('change', handleFileSelect, false);
    document.getElementById('width').addEventListener('change', function () {
        document.getElementById('canvas').width = this.value;
        renderImage();
    }, false);
    document.getElementById('height').addEventListener('change', function () {
        document.getElementById('canvas').height = this.value;
        renderImage();
    }, false);
}());

var currentImage;

function handleFileSelect(evt) {
    var file = evt.target.files[0];
        if (!file.type.match('image.*')) {
            alert('Unknown format');
        }
    var reader = new FileReader();

    reader.onload = (function(theFile) {
        return function(e) {
            currentImage = e.target.result;            
            renderImage();
        };
    })(file);

    reader.readAsDataURL(file);
 }

function renderImage() {
    var data = currentImage,
        img = document.createElement('img');
    img.src = data;
    img.onload = function () {
    var can = document.getElementById('canvas'),
        ctx = can.getContext('2d');
        ctx.drawImage(this, 0, 0, can.width, can.height);
    };
}​

HTML

<input type="file" name="picture" id="picture" /><br />
<input type="text" id="width" value="200" />
<input type="text" id="height" value="200" /><br />
<canvas width="200" height="200" style="border: 1px solid black;" id="canvas"></canvas>​

Here is a blog post which I made about that basic example: blog.mgechev.com

Minko Gechev
  • 25,304
  • 9
  • 61
  • 68
  • 1
    Great. And then save the canvas as image using `toDataURL()`. Waiting for the day when all browsers will behave properly specially IE :) – Anupam Nov 01 '12 at 13:30
  • This works nicely, but I think I'll save me the trouble of writing a fallback version for older browsers and post the file to the server. Thank you anyway – Pablo Mescher Nov 01 '12 at 13:32
4

New HTML5 File API is probably the closest solution to what your looking for:

http://www.html5rocks.com/en/tutorials/file/dndfiles/

It allows you to browse for and read files within Javascript. Do whatever processing you like, and then upload to the server. Anything besides this is going to be very tricky indeed, and probably an unavoidable trip to the server and back.

Downside here is browser support.....as always

Paystey
  • 3,287
  • 2
  • 18
  • 32
  • Well, browser support is a main issue in this case. I guess the answer to my question is "no, you can't". – Pablo Mescher Nov 01 '12 at 13:21
  • Once you have this you'll also need a graphics library in mind to actually work on the image. Whilst there are some such as [Pixastic](http://www.pixastic.com) which will let you manipulate an image as it appears on screen I don't know of any which will let you then send the altered image data to a server, unless you can get a binary output of `canvas` contents. – M1ke Nov 01 '12 at 13:23
  • OK; I've converted my two comments so far into an answer which sums up why this can't be achieved. – M1ke Nov 01 '12 at 13:27
2

I am not sure which browsers work perfectly but HTML5 got DnD and File API. Let me give you steps which can work for you using FileAPI.

  1. DnD API: Starts with the drop event when the user releases the mouse and the mouse-up event occurs.
  2. DnD API: Get the DataTransfer object from the drop event
  3. File API: Call DataTransfer.files to get a FileList, representing the list of files that were dropped.
  4. File API: Iterate over all the individual File instances and use a FileReader object to read their content.
  5. File API: Using the FileReader.readAsDataURL(file) call, every time a file is completely read, a new “data URL” (RFC 2397) formatted object is created and an event wrapping it is fired to the onload handler on the FileReader object. FYI: The “data URL” object is Base64-encoded binary data, with a spec-defined header sequence of chars. Browsers understand them.

  6. HTML5 DOM: set the image href to the File Data URL

Anupam
  • 7,966
  • 3
  • 41
  • 63
thecodejack
  • 12,689
  • 10
  • 44
  • 59
  • Thanks for your answer, but as far as I know this is only supported in chrome, so it won't do. – Pablo Mescher Nov 01 '12 at 13:20
  • It is supported in mozilla too. I am using `FileReader` object to show a thumbnail of the image before uploading. And other HTML5 stuff for drag n drop, upload progress etc – Anupam Nov 01 '12 at 13:23
0

You can't, for the following reasons:

  • For the reasons stated in this post: Full path from file input using jQuery

  • The fact that if you even try to create an img element loading a local file path you'll get the error Not allowed to load local resource: in your browser's console.

  • The fact that once you have an image in place you can only alter it's appearance on screen and not alter the file on the system or send the altered image up to the server

  • You've stated that you need cross browser support, so HTML5 File API and Canvas API are out, even though they would only allow part of the functionality anyway.

Community
  • 1
  • 1
M1ke
  • 6,166
  • 4
  • 32
  • 50
0

I've just solved a problem closed to yours.

As everybody said you can't got the real image file address. But, you can create a temporary path and show the image in your page without submiting it to server. I'll show how easy it is, next to next paragraph. Once you show it you can use some javascripts events to "pseudo-crop-it" and get the crop params (corners). Finaly you can add the params to some hidden field and submit the form. As a result you may use som php to crop the submited image at server and to save the result using a number of image formats as .png, jpg, gif, etc. Sorry if i do not write a complete solution, have not enough time.

/* some scripting to bind a change event and to send the selected image
to img element */
$(document.ready(function(){
  $("input:file").each(function(){
    var id = '' + $(this).attr('id');   
    var idselector = '#'+id, imgselector=idselector+'-vwr';
    $(idselector).bind("change", function( event ){
      (imgselector).fadeIn("fast").attr('src', 
       URL.createObjectURL(event.target.files[0]));
    });
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<!-- create a img element to show the selected image and an input file element to select the image.
ID attribute is the key to have an easy and short scripting
note they are related suffix -vwr makes the difference
-->
<img src="" id="image-input-vwr" alt="image to be cropped">
<input type="file" id="image-input" name="image_input">

Hope it help some body as it is a very old question.

Luis G. Quevedo