18

Good Morning Friends,

I am creating a Visualforce for my users to upload photos and these photos are saved in the attachments object, but I wonder if there is any way before the picture is saved I can give a resize the image to 800x600 when the image is larger than this size, if less is saved normally.

Could anyone help me in this task? Thanks to all

8

Here's a (mostly) client-side version that should run on all modern browsers (NOTE: Modern does not include IE8 or lower).

Does not use view state, and accepts any image type the browser does. Error checking is sparse, as this is only a demonstration.

This uses a drag-and-drop interface, but you could also build a traditional file selector interface (not included here).

Controller

public with sharing class droppable {
    @RemoteAction public static Id saveImage(String name, String contentType, String data) {
        Document d = new Document(Name=name, FolderId=UserInfo.getUserId(), contentType=contentType, Body=EncodingUtil.base64Decode(data));
        Database.insert(d, true);
        return d.id;
    }
}

Visualforce Page

<apex:page controller="droppable">
    <style>
    #droparea {
        position: relative;
        height: 5em;
        font-size: 3em;
        color: #ccc;
        border: 5px dotted #ccc;
    }
    #droparea div {
        position: absolute;
        top: 50%;
        left: 0;
        right: 0;
        text-align: center;
        margin-top: -0.5em;
        margin-left: auto;
        margin-right: auto;
    }
    </style>
    <script>
    (function() {
        var maxWidth = 800, maxHeight = 600, fileName;
        function canDropHere(event) {
            var allowed = event.dataTransfer.files && event.dataTransfer.files.length && event.dataTransfer.files[0].type.match(/^image\//);
            event.stopPropagation();
            event.preventDefault();
            event.dataTransfer.dropEffect = allowed? "copy": "none";
            return !allowed;
        }
        function onDrop(event) {
            var fr = new FileReader();
            fr.addEventListener("load", onFileLoad, true);
            try {
                fileName = event.dataTransfer.files[0].name;
                fr.readAsDataURL(event.dataTransfer.files[0]);
            } catch(e) { alert(e); }
            event.stopPropagation();
            event.preventDefault();
            return false;
        }
        function onFileLoad(event) {
            var sx, sy, scale, p1,
                img     = document.createElement("img"),
                canvas  = document.createElement("canvas"),
                context = canvas.getContext("2d");
            img.src     = event.currentTarget.result;
            if(img.width > maxWidth || img.height > maxHeight) {
                scale = Math.min(maxWidth/img.width, maxHeight/img.height);
                sx    = Math.floor(img.width*scale);
                sy    = Math.floor(img.height*scale);
            } else {
                sx = img.width;
                sy = img.height;
            }
            canvas.width = sx;
            canvas.height = sy;
            context.drawImage(img, 0, 0, sx, sy);
            p1 = canvas.toDataURL().match(/data:(.+);base64,(.+)/);
            {!$RemoteAction.droppable.saveImage}(fileName, p1[1], p1[2], onSaveResult);
        }
        function onSaveResult(result, event) {
            alert('File was saved as: '+result);
        }
        function onLoad() {
            var droparea = document.querySelector("#droparea");
            droparea.addEventListener("drop", onDrop, true);
            droparea.addEventListener("dragenter", canDropHere, true);
            droparea.addEventListener("dragover", canDropHere, true);
        }
        addEventListener("load", onLoad, true);
    }());
    </script>
    <div id="droparea">
        <div>
            Drop an image file here
        </div>
    </div>
</apex:page>
  • 1
    awesome solution – Sergej Utko Dec 18 '13 at 20:06
10

I don't have specific code to share, but if HTML5 is a possibility then converting the image to a Canvas tag might be able to do this. You can manipulate the canvas and then convert the result into a base64 string.

8

I'm not aware of a way to manipulate images within Apex. This would be beyond the capabilities of Apex. One approach however could be to push the uploaded image out to an external process to handle the resizing. After the file has been uploaded push the file to a third party web service using a apex call out and have the web service return the resized image.

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_callouts.htm

This still leaves the problem of handling the resizing, but this could easily be handled in other languages and made available via a web service for your apex to use.

6

I had a similar need recently and ended up using HTML 5 canvas for this purpose based on what joshbirk said. It turned out to be pretty straight forward.

Here is a link to working demo:

http://free-12415f14c3a-124e539428a-12ea33928a3.mysandbox.cs11.force.com/ResizeImage

and the github link https://github.com/bkhakurel/ImageResizeApex

4

Obviously you can specify the height and width in an image tag in a VF page, but there is nothing built in to Salesforce that can do the image manipulation/processing that you are seeking. You might want to check out the AppExchange, but in my scan I didn't see anything there.

Here is the idea to add Apex Image Processing. Vote it up.

As @Killian said, you could upload the image and then callout to a web service to resize it for you. If you end up implementing it on your own I'd suggest taking a look at ImageMagick. It is open source, pretty mature and well documented.

  • Except that HTML5 now offers a client-side resizing mechanism that's supported on about 90% of the global market of browsers. – sfdcfox Dec 18 '13 at 16:03
  • @sfdcfox - That's awesome! Should definitely use that now. Feel free to add a separate detailed answer. 1.5 yrs later is not too late if it is helpful. :-) – Peter Knolle Dec 18 '13 at 16:18
  • 2
    Since you asked so nicely, I've made one for you to look at. – sfdcfox Dec 18 '13 at 19:51
  • @sfdcfox - Awesome! – Peter Knolle Dec 18 '13 at 19:54
  • I'm a fan of having a server side solution. Adding this capability to Apex seems like a reasonable request. What if you want to generate a different size down the line? – dana Aug 26 '14 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.