midma101
midma101

Reputation: 139

HTML canvas element creating undesired white border

There's probably a real simple explanation for this, but I'm struggling really hard to find it. I'm trying to implement a crop picture feature and I'm getting an undesired border on the right and bottom sides of the picture, as seen here: https://i.sstatic.net/kLQSI.jpg. I think I've narrowed it down to something having to do with the first image translation that happens when I crop the picture. Here's the applicable code (the doubling of the cropped image size in submitPhotoUpload is due to some unknown halving of the picture height in my code. Advice for that would be welcome too):

cropPhoto: function(evt){

    var formType = App.UploadPhotoView.whichForm;

    var canvas = document.getElementById("crop-canvas-preview-"+formType);
    var context = canvas.getContext("2d");
    if(this.canvasHidden){
        canvas.style.display = 'inline';
        App.UploadPhotoView.canvasHidden = false;
    }

    var x1 = App.UploadPhotoView.x1;
    var y1 = App.UploadPhotoView.y1;
    var width = App.UploadPhotoView.width;

    var previewSize = $("#upload-div-"+formType).height() * 0.25;
    var resizeX = App.UploadPhotoView.scalingFactorX;
    var resizeY = App.UploadPhotoView.scalingFactorY;
    var img = document.getElementById("preview-photo-"+formType);

    context.clearRect(0, 0, previewSize, previewSize);
    context.drawImage(img, x1*resizeX, y1*resizeY, width*resizeX,
                      width*resizeY, 0, 0, previewSize*2, previewSize);
},

submitPhotoUpload: function(){
    var formType = "pic";
    if ($('#preview-photo-'+formType).attr('src') != '#') {
        var uploadImage = new Image();
        uploadImage.src = document.getElementById('crop-canvas-preview-'+formType).toDataURL();

        var canvas = document.createElement('canvas');
        canvas.width = uploadImage.width * 3;
        canvas.height = uploadImage.height * 6;

        canvas.getContext('2d').drawImage(uploadImage, 0, 0, canvas.width, canvas.height);

        var newPhoto = App.Photo.createRecord({
            filename: canvas.toDataURL(),
            location: this.get('location'),
            description: this.get('description')
        });
        this.get('store').commit();
        resetPhotoUpload(formType);
    }else{
        this.set('submissionFailed', true);
    }
},

Upvotes: 1

Views: 1402

Answers (1)

user1693593
user1693593

Reputation:

The reason is that you are using fractional values with the clearing and clipping.

The clearRect call will clear on sub-pixel basis which means it can leave "half" pixel clipped.

The clip however cannot clip the image with sub-pixels as images are pixel based and will truncate the value to match an integer value, hence you get a small gap in the final result.

Luckily this is easy to get around by simply forcing the values to integer values:

ONLINE DEMO HERE

context.clearRect(0, 0, previewSize|0, previewSize|0);
context.drawImage(img, (x1*resizeX)|0, (y1*resizeY)|0, (width*resizeX)|0,
                  (width*resizeY)|0, 0, 0, previewSize|0, previewSize|0);

Of course, you might consider doing this outside the function call. If you need a more accurate rounding just add 0.5 to the values before doing as here, shifting 0 bits (which force a float number to integer) or use Math.round() instead.

Here is the result:

Result

left: cleared and clipped using frational positions, right: using integer values

Upvotes: 2

Related Questions