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
Rakesh K 60Rakesh K 60 

Apex logging malformed base64 string

Hi,

I'm writing a code where I need to query the product's object, get the product image URL, convert the Image in the URL to a base64 string for my other REST input. Here is the code that I'm using.

 
String url='https://myOrg.demo.my.salesforce.com/servlet/servlet.FileDownload?file=0152w000001Jex4';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
Http binding = new Http();
HttpResponse res = binding.send(req);
Blob image = res.getBodyAsBlob();
String encRes=EncodingUtil.base64Encode(image);

for (Integer i = 0; i < encRes.length(); i=i+300) {
    Integer iEffectiveEnd = (i+300 > (encRes.length()-1) ? encRes.length()-1 : i+300);
    System.debug(encRes.substring(i,iEffectiveEnd));
}

The output that I get is as below.
User-added image

when I downloaded the same image and uploaded it online to get the base64 I get it as below. (cropped the bottom part of the output.).

User-added image

I'm unable to understand why it is printing Li4U strings at the end.
Where am I going wrong in my code and how can I fix this.

Thanks
 
SwethaSwetha (Salesforce Developers) 
HI Rakesh,
Can you explain what you are trying to accomplish in the for loop?
I see that system.debug(encRes) does not have the Li4U string. 

Using System.debug(encRes.substring(0,1000)); also does not give the Li4U string
Rakesh K 60Rakesh K 60
Hi Swetha,

I had the for loop as the output gets truncated in logs. The issue doesn't come when you are giving any image from online, it's happening for me with the image in product object. In the above code, I directly took the image from soql result. 

Thanks 
AnudeepAnudeep (Salesforce Developers) 
Hi Rakesh, 

As per my understanding, whenever you have an image saved within SFDC, this image file is hosted as a Salesforce file, but actually, it's converted into a servlet.

And, what is it about? It means that whenever you're accessing the servlet URL, you're getting a preview within the SFDC environment, not accessing the file preview itself.

For accessing the image itself throughout an URL, you would need several steps to get a shareable link performing some Apex transformations, thereafter, you would be able to convert it into Base64.

There's a standard nowadays, however, if Salesforce changes the way the URL is formed, the code will stop working.

My recommendation is to host the images in a CDN (Content-Delivery-Network) such as Google Drive.

But if you want to test, it follows the code I was able to get a shareable link (not needed auth, and you can reach out to the image file directly).
 
public with sharing class GeneratePublicLink {
    
   	//It must receive the objectId in which has a file attached.
    public static String createStructure(Id objectId){
        
        //Reference: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_contentdocumentlink.htm
        ContentDocumentLink cdl = [ SELECT contentdocument.id
                                    FROM ContentDocumentLink 
                                    WHERE linkedentityid =: objectId 
                                    LIMIT 1];
        
        //Reference: https://developer.salesforce.com/docs/atlas.en-us.sfFieldRef.meta/sfFieldRef/salesforce_field_reference_ContentVersion.htm
        ContentVersion cVersion = [ SELECT Id, FileType, ContentBodyId
                                    FROM contentversion 
                                    WHERE contentdocumentid =: cdl.contentdocument.id ];
        
        //Reference: https://developer.salesforce.com/docs/atlas.en-us.sfFieldRef.meta/sfFieldRef/salesforce_field_reference_ContentDistribution.htm
        ContentDistribution cDistribuition = new ContentDistribution();
        cDistribuition.Name = 'Test';
        cDistribuition.ContentVersionId = cVersion.id;
        cDistribuition.PreferencesAllowViewInBrowser= true;
        cDistribuition.PreferencesLinkLatestVersion=true;
        cDistribuition.PreferencesNotifyOnVisit=false;
        cDistribuition.PreferencesPasswordRequired=false;
        cDistribuition.PreferencesAllowOriginalDownload= true;
        
        insert cDistribuition;
        
        ContentDistribution cdCreated = [ SELECT Id, DistributionPublicUrl 
                                          FROM ContentDistribution
                                          WHERE Id =: cDistribuition.Id ];
        
        return createPublicLink(cVersion, cdCreated);        
    }
    
    private static String createPublicLink(ContentVersion cVersion, ContentDistribution cDist) {
        
        String fileType = cVersion.FileType.toLowerCase().capitalize();
        String cVersionId = cVersion.Id;
        String cBodyId = cVersion.ContentBodyId;
        String originalUrl = String.valueOf(cDist.DistributionPublicUrl);
        String cDistParam = originalUrl.substring(originalUrl.indexOf('/a/'));
        String orgId = ConnectApi.Organization.getSettings().orgId;
        String baseDomain = Url.getOrgDomainUrl().toExternalForm();
        baseDomain = baseDomain.substringBefore('.') + '--c.documentforce.com';
        
        String theUrl = baseDomain + '/sfc/dist/version/renditionDownload?rendition=ORIGINAL_' +
            fileType + '&versionId=' + cVersionId + '&operationContext=DELIVERY&contentId=' + cBodyId +
            '&page=0&d=' + cDistParam + '&oid=' + orgId + '&dpt=null&viewId=';
        
        return theUrl;
    }
}

Let me know if this helps, if it does, please mark this answer as best so that others facing the same issue will find this information useful. Thank you