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
OhadiosOhadios 

Corrupt PDF when sending as email-attachment from Apex

Hi All,

 

I've created a VF page that allows users to select a list of custom objects related to a particular case, update some field information and attach pictures to any of these related objects. When done, the user clicks on an email that generates an email based on a VF Email template. This part works great.

Instead of sending multiple image attachments on this email, I created a VF page that displays all of these images, and was attempting to generate it as a PDF attachment to attach to the case.

When I load the VF page (which has renderAS="PDF"), it looks great and works as expected.

When I call it from my custom controller using the getContent() method, it is sending a file that I am unable to open using Adobe. When I try I receive the error "insufficient data for an image", and even the text on the page does not render (though, oddly,  the table is visible).

I have no clue how to attempt and troubleshoot it, so I will appreciate any help!

 

Here is my controller extendsion part which calls my page:

Messaging.EmailFileAttachment myAttach = new Messaging.EmailFileAttachment();
myAttach.setFilename(This.Cas.CaseNumber+'_Related_Pictures.pdf');
myAttach.setContentType('application/pdf');
PageReference myPdf = Page.IDS_Quote_Pictures_PDF;
mypdf.setRedirect(true);
myPDF.getParameters().put('ID' , this.Cas.ID);
blob b = myPdf.getContentAsPdf();
myAttach.setbody(b);
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setWhatID(Cas.ID);
email.setTargetObjectId(toContacts[0].theContact.id);
EmailTemplate templateId = [Select id from EmailTemplate where name = 'IDS RMA Quote Email'];
email.setTemplateID(templateId.Id);
email.setSaveAsActivity(true);
email.setToAddresses(toAddresses);
email.setCCAddresses(ccAddresses);
email.setOrgWideEmailAddressId([SELECT id, displayName FROM OrgWideEmailAddress WHERE DisplayName = 'I.D. Systems RMA Department'].id);
if (myAttach != NULL) {
    email.setFileAttachments(new Messaging.EmailFileAttachment[] {myAttach});
        }

 And here is the custom controller that the actual PDF VF page calls:

 

public class IDS_RMA_Quote_Pictures_Getter{

    // Wrapper class to wrap an attachment with a selection and some related details in text
    public class attachFile {
        public Attachment theFile {get;set;}
        public String belongsTo {get;set;}
    
        public attachFile(Attachment theFile) {
        	this.theFile = theFile;
        }
    }
    
    public final Case cas;
    //private final ID cas;
    private List<attachFile> readyAttachments;
        
    public IDS_RMA_Quote_Pictures_Getter(){
        //this.cas = (case)stdController.getRecord();        
        Cas = [Select ID, Subject, CaseNumber, Type_of_RMA__c, Date_RMA_Received__c FROM Case WHERE ID =: ApexPages.CurrentPage().getParameters().get('id')];
    }
    
    public Case getCas() {
    	return cas;   
    }
    
    
    public List<attachFile> getReadyAttachments() {
        System.debug('Starting Getter');
        List<device__C> deviceList = new List<Device__c>();
        deviceList = [SELECT Name,
                      Part_Number__R.Name,
                      Part_Number__R.Description__c,
                      Problem__c,
                      Visual_Inspection_Notes__c,
                      Quoted_Price__c,
                      Quote_Status__c,
                      Customer_Damage__c,
                      In_Warranty__c
                      FROM Device__c 
                      where Quote_Status__c =: 'Quoting' 
                      AND Case__c =: Cas.ID]; 
        System.debug('Devices: '+deviceList);
        
        List<ID> allDeviceIDs = new List<ID>();
        For (device__c d : deviceList) {
         	allDeviceIDs.add(d.ID);   
        }
        System.Debug('Device IDs: '+allDeviceIDs);
        
        List<Attachment> allAttachments = new List<Attachment>();
        allAttachments = [SELECT ID, Name, ParentID, body, ContentType 
                          FROM Attachment 
                          WHERE name != : 'Device_QR_Code.png'
                          AND ContentType LIKE 'image/%'
                          AND (ParentID IN : allDeviceIDs
                                 OR ParentID = : cas.ID)
                         Order by ID desc];
        System.debug('Selected # of Attachments: '+allAttachments.size());
        
        List<attachFile> readyAttachments = new List<attachFile>();
        integer counter = 1;
        
        for (attachment att : allAttachments) {
            attachFile AF = new attachFile(att);
            if (att.ParentID == cas.ID) {
                af.belongsTo = 'Attached to case';
                System.Debug('Device being added to list: '+af);
            } else {
                for (device__c dvc : deviceList) {
                    if (att.ParentID == dvc.ID){
                        af.belongsTo = 'For Part Number ' +dvc.part_number__r.name+' Serial Number: '+dvc.Name;                    
                    }
                }	
            }
            readyAttachments.add(af);
            System.Debug('Device being added to list: '+af);
        }
        System.Debug('Added file to readyAttachments');
        System.debug('Ready Attachments: '+readyAttachments.size());
       
        return readyAttachments;
    }
}

 and lastly, here is the PDF VF page:

<apex:page title="Quote for Repair" showHeader="false" controller="IDS_RMA_Quote_Pictures_Getter">
    <apex:stylesheet value="{!URLFOR($Resource.RepairPDF, 'RFStyle.css')}"/>
    <Apex:form >
        <apex:pageBlock >
        <apex:pageMessages />
            <table width = "100%" align="center">
                <tr width = "100%">
                    <td width = "50%" align="left">
                        <apex:image value="{!URLFOR($Resource.RepairPDF, 'logo.jpg')}"/>
                    </td>
                </tr>
                <tr>
                    <td height="20px">
                        <!-- Spacing between logo and table-->
                    </td>
                </tr>
                <!--<apex:outputText value="Dear Customer"/>-->
                <table width="100%" Class="grid">
                    <tr>                    	
                        <td width="50%" colspan="2" align = "center">
                            <apex:outputText styleClass="headertext" value="Pictures related to RMA #{!cas.CaseNumber}"/>
                        </td>
                    </tr>
                    <tr>
                        <td width="50%" align = "left" >
                        	<apex:outputText value="RMA Type : "/>
                            <apex:outputText value="{!cas.Type_of_RMA__c}"/>
                        </td>
                        <td align = "left">
                            <apex:outputText value="Date RMA Received: "/>	
                            <apex:outputText value="{!cas.Date_RMA_Received__c}"/>
                        </td>
                    </tr>
                </table>
                <!--Here starts the Device List-->
                <apex:variable value="{!1}" var="pgCount"/> 
                <apex:pageBlockSection title="Attached Images" columns="1">
                    <apex:repeat value="{!readyAttachments}" var="ra">
                        <div style="{!if(pgCount = 1, 'page-break-after:auto;', 'page-break-after:always;')}">
                            <apex:outputText value="{!ra.belongsTo}" />
                            <apex:image url="/servlet/servlet.FileDownload?file={!ra.theFile.ID}"/>
                            <apex:variable var="pgCount" value="{!pgCount+ 1}"/>
                        </div>
                    </apex:repeat>
                </apex:pageBlockSection>
            </table>            
        </apex:pageBlock>            
    </Apex:form>
</apex:page>

 

Best Answer chosen by Admin (Salesforce Developers) 
OhadiosOhadios
Pat, It turns out that I had an image referenced from Static Resource. It was not printing on the PDF, so I didn't really think about it, but when I started redesigning my template I suddenly realized it is not printing. Once I removed this image, the PDF now opens on Adobe Reader and Standard without an issue. It was, after all, a corrupt image like I suspected at first - I just did not realize I had this image :) It seems like my issue is now resolved! I really appreciate your help. Ohad

All Answers

Pat PattersonPat Patterson

Hi Ohadios,

 

I've seen this post over on the Salesforce StackExchange - your issue might be related: Is it possible to use images in Visualforce generated PDFs which are not static resources?

 

The key point seems to be: any external URLs you want salesforce to make a HTTP(s) call to need to be defined under Setup > Security Controls > Remote Site Settings. Make sure the protocol (HTTP vs HTTPS) matches the image link!

 

You may also need to ensure that your VF/Apex is using the most recent API version - it looks like the PDF rendering engine was updated in V25.

 

Cheers,

 

Pat

OhadiosOhadios

Pat,

 

I really appreciate your response.

i've already looked at this article before, and unfortunately it is not related to my issue.

 

I have a possible solution for a part of my issue - but it seems the issue might actually be an Adobe Reader bug that may or may not have been fixed in newer versions (since we use a licensed version of Adobe Standard, I cannot get the version 10 or 11 which supposedly fixed this issue).

I will test tomorrow and post an update here.... but I would need to perform more research to identify why this is happening in the first place.

 

Ohad

Pat PattersonPat Patterson

Hi Ohad - if you can generate a PDF (perhaps with dummy data) I can try loading it into Adobe Reader 11.0.04 and see what happens.

OhadiosOhadios

Pat,

 

Here's a sample PDF file that has a few images that I am unable to open with Adobe Reader Standard 9.5

I am able to view the PDF with the images when I view it through Chrome or Google Apps' viewer...

 

I haven't cleaned up the template yet, but still working on the functionality :)

 

I'll appreciate if you'd let me know if you can open it.:

 

https://drive.google.com/file/d/1UVdGqJ5KlY6JTnAJdUjOKOIRrIfHZpWhzZN2qhQagLW_1UwRR8T82SfpONf_/edit?usp=sharing

 

Ohad

Pat PattersonPat Patterson

Interesting. Adobe Reader 11.0.4 says 'Insufficient data for an image.', but Mac OS X Preview opens it and the first page of three is:

PDF output

OhadiosOhadios

Pat,

 

What you saw on when you opened on MAC was the correct content.

As this is does not appear to be related to the version of Adobe Reader that the user has, I am not sure what else I can do to identify the cause of this issue...

I a using a simple VF component with a renderAs="PDF" via email template.

I don't think it will be a good idea to start emailing these PDF's to our customers if many of them will experience this issue..

 

Do you have any idea where I can go from here?

Pat PattersonPat Patterson

Something in the rendering is not working on the default Adobe client - I think you should open a support case (with Salesforce). It's possible that there is an issue in our PDF rendering.

 

Cheers,

 

Pat

OhadiosOhadios

Thanks, I will.

I will post update here when I have more to share.

OhadiosOhadios
Pat, It turns out that I had an image referenced from Static Resource. It was not printing on the PDF, so I didn't really think about it, but when I started redesigning my template I suddenly realized it is not printing. Once I removed this image, the PDF now opens on Adobe Reader and Standard without an issue. It was, after all, a corrupt image like I suspected at first - I just did not realize I had this image :) It seems like my issue is now resolved! I really appreciate your help. Ohad
This was selected as the best answer
Pat PattersonPat Patterson

Like!