function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
TehNrdTehNrd 

Best way to host images for CMS type site?

I'm curious what is the best way to host images for CMS type sites. Let's say I have a custom object called Building. It has some fields such as Height, Number of Floors, Year Built, etc. I'd also like to attach an image of the building to the record. Then I have a custom visualforce component that pulls all this data and image into a nice clean output.

 

There appears to be no good way to handle the images. RTF are not an option as the output is impossible to work with. Attaching as documents is like building something with toothpicks and bubble gum as it requires exact naming of the documents so they can be queried properly.

 

There used to be an idea for an image field type that would address this issue perfectly. Upload a single image to a field and then when outputting this field you would get a simple <img> tag. Ideally there would also be something like this: http://sites.force.com/ideaexchange/ideaView?c=09a30000000D9xt&id=08730000000BrdBAAS

Best Answer chosen by Admin (Salesforce Developers) 
TehNrdTehNrd

Here is the best way to do this with the features availabile today. Straight from the man who would know, http://twitter.com/Cinarkaya/status/13764901069 .

 

 

<apex:page controller="Image" showHeader="false" standardStylesheets="false" >
    <apex:image value="{!URLFOR($Action.Attachment.Download, mainImage)}"/>
</apex:page>

 

public class Image {

    public Id mainImage {get; set;}
    
    public Image(){
        //You would want some error handling around this query in case URL doesn't have Id parameter defined
        mainImage = [select Id from Attachment where ParentId = :ApexPages.currentPage().getParameters().get('id') AND Name = 'image.jpg'].Id;
    }
}

This requires no hardcoding for image URL but it does require hard coding file name in controller query. As mentioned before the most brittle piece of doing it this way is the document name must follow an exact naming convention. As Wes mentioned the best way to handle this would be to build a custom page to upload images so you could systematically set the file names.

 

-Jason

 

 

 

All Answers

WesNolte__cWesNolte__c

Hey

 

I quite like this approach

 

<apex:image url="{!myimageurl}" width="256" height="256"/>

 

 

 

getmyimageurl () {  
    document doc = [  query the document table for the image by exact name  limit 1]
    string imageid = doc.id; 
    imageid = imageid.substring(0,15);
    return '/servlet/servlet.FileDownload?file=' + imageid;
}

 Wes

 

TehNrdTehNrd

This definelty works and is probably the best way to do things with the toolset we have today but there are still issues that concern me.

 

1) Hardcoding is bad and I would always be afraid of 'servelt/servlet.FileDownload?fid=' changing.

2) This approach requires document names to be exact and follow a standarized process. This is prone to human error. The best way to manage this would be to create a custom page to manage image attachments. This would probably work well but it is simply more work.

 

I feel like an vanilla image field would address all of these issues.

rtuttlertuttle

Base64 of a binary image stored in a text area?

 

 

-Richard

TehNrdTehNrd

Imagine the look on a users face when I say, "Oh, no worries. Just store the Base64 of a binary image in the Text field called Image".

 

There also wouldn't really be a good way to preview the image as well.

rtuttlertuttle

LOL  -  I was kind of thinking you'd handle the conversion yourself.  But I suppose you could make them convert to base64.

 

 

-Richard

AnshulVermaAnshulVerma
Hey , Why not do the following:- 1. Create a custom VF component which will take following three parameters:- a) Custom Setting name:- would contain unique name of the document b) Height of image c) width of image 2. VF Component controller:- Would select the document from database .. based on label name being passed 3. VF Component:- would display the image with the path retrieved from controller and height & width set as per the parameters passed. 4. Later on if you want to change the images pro grammatically you can do so by modifying the Custom setting. Does that fulfill your requirement?
TehNrdTehNrd

Ya, I would, but I can't bring myself to store a media file as text file.

TehNrdTehNrd

@ 

 

 

rtuttlertuttle

Okay so store it as a document.  

 

 

http://www.salesforce.com/us/developer/docs/pages/ Content/pages_compref_inputFile.htm

 

 

-Richard

rtuttlertuttle

Bottom line I think is we need an image field.  I agree with you 100% on that.  Until then I think anything you do is going to have pros/cons, mostly cons.  Maybe you could write down the pros and cons and do a quick analysis and figure which one you'd have less evil with.

 

 

-Richard

TehNrdTehNrd

@rtuttle

 

Documents This still requires hard coding of image URL which is something that makes uneasy: 

 

'/servlet/servlet.FileDownload?file=' + imageid;
TehNrdTehNrd

Your last post slipped in before mine.

 

Yup, I think we can all agree there are ways to get this done but not any best practice ways. An image field that outputted a single <img> tag would be ideal.

rtuttlertuttle

Yea I don't really see an easy way out of this one.  I honestly think if I had to approach this I'd store it as base64 in the database.  Problem is I'm not sure how well the conversion back to blob would work with trying to use the image.  I imagine you could expose the blob and use it as an image, but not sure how well that would work.

WesNolte__cWesNolte__c

Hey

 

The hardcoding of the URL is a bit of a sore point, but it isn't an arb servlet path, it is documented (officially). As far as name management goes I'd present users with a read only list of image names, and since you can arrange documents into folders, selecting all documents in a particular folder would give you all doc names. That way you only need to maintain the folder name.

 

Or, you could add a field that stores 'tags' against a Document, and just select all documents with a specific tag in the correct context. There are a few ways to manage it and as far as my experience goes SF has made this a lot easier than on other platforms.

 

Good luck mr Nrd.

 

Wes

TehNrdTehNrd

Here is the best way to do this with the features availabile today. Straight from the man who would know, http://twitter.com/Cinarkaya/status/13764901069 .

 

 

<apex:page controller="Image" showHeader="false" standardStylesheets="false" >
    <apex:image value="{!URLFOR($Action.Attachment.Download, mainImage)}"/>
</apex:page>

 

public class Image {

    public Id mainImage {get; set;}
    
    public Image(){
        //You would want some error handling around this query in case URL doesn't have Id parameter defined
        mainImage = [select Id from Attachment where ParentId = :ApexPages.currentPage().getParameters().get('id') AND Name = 'image.jpg'].Id;
    }
}

This requires no hardcoding for image URL but it does require hard coding file name in controller query. As mentioned before the most brittle piece of doing it this way is the document name must follow an exact naming convention. As Wes mentioned the best way to handle this would be to build a custom page to upload images so you could systematically set the file names.

 

-Jason

 

 

 

This was selected as the best answer
WesNolte__cWesNolte__c

Very cool, best practise noted.

rtuttlertuttle

After re-reading the use case I don't see a problem with having to hardcode the file names.  My thought is you would have had to do it anyway if there was an image field type.  The field name would have been a static name you'd reference in code, so not really a big deal (although a great deal easier to access).

 

You could also skip the query and pull all the images in like this and manipulate them from the class name with jQuery.  You'd still need a front end to control the attachments since you need to control the filename.

 

<apex:repeat value="{!myObject.Attachments}" var="att">

<apex:image styleClass="cmsImage {!if(begins(att.Name,'buildingImage'),'buildingImage','')}" src="{!urlfor($Action.Attachment.Download,att.Name)}" style="display:none;"/>

</apex:repeat>

 

Not sure how helpful this would be.  I try to avoid writing apex as much as possible anymore.

 

 

-Richard

TehNrdTehNrd

Excellent point about having to hard code the field name anyway.

 

One issue that could potentially come up with the repeat solution you provided is the Request Time limit for force.com sites. Even though you have written no apex the page is still querying all of the attachments even thought only one will be displayed and I would guess this will increase the Request Time. It is probably very small but it could add up for busier sites.

AnshulVermaAnshulVerma

@TechNrd:- Really a good way to achieve a common problem.

 

But, I believe you can eradicate the issue of hardcoding the image name by saving the image name in Custom Setting. That ways it would not be hardcoded.

tomb ralytomb raly
always use image compressors to reduce the image size and it will make website speed faster when you compress jpeg to 300kb (https://compresskaru.com/compress-jpeg-to-300kb/) online.