By Shelakel


2012-03-18 12:07:21 8 Comments

I'm trying to figure out if my code is at fault or the current HTML5 File API implementation.

The code below works. The bug appears when repeating the process after already loading the image once.

The second time a file is selected the image blob loads, then there's a flicker and the image disappears. Subsequent selections after that usually work fine (sometimes there's erratic behavior if the file is big). Repeating the process for the same file selection generally works (as a fix).

Any help would be greatly appreciated.

JavaScript libraries used

  • JQuery 1.7.1

  • JQuery Tools 1.2.6

  • JCrop 0.9.9

Steps - Summary

  1. The user selects a file via the traditional <input type="file" /> dialog.

  2. An onchange handler executes for the input and checks if a file was selected, if so, then verifies that the MIME type is image/jpeg or image/png and that the selected file size is smaller than 250KB. If this validation fails it resets the selection.

  3. At this point the file (image) to be uploaded is valid. Next it checks if the browser supports the File API CreateObjectURL via if (typeof window.URL == 'undefined') return; (if it doesn't, skips the next steps)

  4. It loads the image blob into the current picture preview (one used to display the current image) and also into a dynamically generated image element which is added into a jquery tools' overlay with jcrop cropping functionality.

  5. The user then crops the image via jcrop and closes the overlay, seeing the cropped preview of the image to be uploaded (only if the browser supports CreateObjectURL and the user cropped the image)

The Code

The HTML

<div style="height: 100px; overflow: hidden; width: 100px; margin-bottom: 5px;">
    <img id="PhotoPreview" alt="Photo" src="/Content/no-photo.png" />
</div>
<input type="file" id="Photo" name="Photo" onchange="photoChanged(this.files)" />
<input type="hidden" id="PhotoCrop" name="PhotoCrop" value="" />

The JavaScript window.URL = window.URL || window.webkitURL;

function photoChanged(files) {
    if (!files.length) return;
    var file = files[0];
    if (file.type != 'image/jpeg' && file.type != 'image/png') {
        alert('The photo must be in PNG or JPEG format');
        $("#Photo").val('');
        return;
    }
    var fileSizeLimit = 250;
    var fileSize = file.size / 1024;
    if (fileSize > fileSizeLimit) {
        var fileSizeString = fileSize > 1024 ? (fileSize / 1024).toFixed(2) + "MB" : (fileSize).toFixed(2) + "KB";
        alert("The photo file size is too large, maximum size is " + fileSizeLimit
                + "KB. This photos' file size is: " + fileSizeString);
        $("#Photo").val('');
        return;
    }

    if (typeof window.URL == 'undefined') return;

    var preview = document.getElementById('PhotoPreview');
    $(preview).removeClass('profile-photo');
    preview.src = window.URL.createObjectURL(file);
    preview.onload = function () {
        var img = new Image();
        $("#PhotoOverlay div").empty().append(img);
        window.URL.revokeObjectURL(this.src);
        img.src = window.URL.createObjectURL(file);
        img.onload = function () {
            window.URL.revokeObjectURL(this.src);
            $(this).Jcrop({
                onSelect: onImageCropSelect,
                aspectRatio:
                310 / 240,
                minSize: [100, 100],
                setSelect: [0, 0, 100, 100]
        });

        $("#PhotoOverlay")
            .css({ width: this.width + 'px', : 'auto'})
            .overlay()
            .load();
        };
    };
}

function onImageCropSelect(e) {
    $("#PhotoCrop").val(e.x + ',' + e.y + ',' + .x2 + ',' + e.y2);

    var rx = 100 / e.w;
    var ry = 100 / e.h;

    var height = $("#PhotoOverlay div img").height();
    var width = $("#PhotoOverlay div img").width();

    jQuery('#PhotoPreview').css({
        width: Math.round(rx * width) + 'px',
        height: Math.round(ry * height) + 'px',
        marginLeft: '-' + Math.round(rx * e.x) + 'px',
        marginTop: '-' + Math.round(ry * e.y) + 'px'
    });
}

$(function () {
    $("#PhotoOverlay").overlay({
        mask: {
            color: '#ebecff',
            loadSpeed: 200,
            opacity: 0.9
        }
    });
});

Feel free to use the code (my contribution for any help received here).

Update

I have come across another question on stackoverflow regarding a similar issue (image loading then disappearing) in regards to the use of JCrop. I'm currently betting on JCrop being the culprit.

I've also read that when img.onload executes the image isn't always 'ready', hence the strange behavior and additional checks to .actualWidth/.actualHeight with a setTimeout might solve the issue. I'll investigate it.

Update

I have a working proof of concept using a FileReader and readAsDataUrl instead of using the CreateObjectURL and using a CANVAS to draw a preview instead of a margin based overflow:hidden solution. Needs some refinement then I'll post the code here.

1 comments

@fullpipe 2012-08-12 23:23:41

often erratic behavior occurs when you set img.src before declare img.onload

function imageLoadHandler() { ... }

var img = new Image();
img.onload = function() { imageLoadHandler() }
img.src = window.URL.createObjectURL(file);
if(img.complete) { imageLoadHandler() } //fix for browsers that don't trigger .load() event with image in cache

hope this helps

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] Preview an image before it is uploaded

1 Answered Questions

[SOLVED] Image Select and Crop on Browser

2 Answered Questions

[SOLVED] Jcrop image does not show correctly in preview

1 Answered Questions

1 Answered Questions

[SOLVED] Cropping an image with a preview using jcrop

2 Answered Questions

[SOLVED] How to crop large image in small form without trimming before crop?

1 Answered Questions

[SOLVED] Using imagick to crop large image not working

1 Answered Questions

[SOLVED] JCrop cuts edge of image

2 Answered Questions

[SOLVED] Using Jcrop ,could not refresh preview pane correctly when changing image

  • 2012-12-22 16:51:29
  • Ryan Hu
  • 3249 View
  • 0 Score
  • 2 Answer
  • Tags:   jcrop

2 Answered Questions

[SOLVED] php scaled image cropping

  • 2012-06-15 01:21:12
  • Jake
  • 622 View
  • 0 Score
  • 2 Answer
  • Tags:   php jquery gd

Sponsored Content