Replacing a link within a PDF with image

Hi,

We are using aspose.total for java with coldfusion. I have a link in the PDF file which points to a web page. My requirement is to replace that link with an image. I am using the addImage method of class com.aspose.pdf.facades.PdfFileMend. The image is put above the link using the coordinates of the link. However, when you hover over the image, the link is still shown.

How can I replace the link so that the link totally disappears rather than hiding it by putting the image on top of it?

Regards

@Batrinux,

Kindly send us all details of the scenario, including source PDF and code. We will investigate and share our findings with you.

Telnet PERM Exempt Offer (NO Retention W PDM) Template [Template]1_Filled_Signed.pdf (168.0 KB)

Please find the attached PDF file. Pls look at the bottom of the page on the left side where the signatures are placed. The signatures are placed over the link “Click here to sign” and the link pointed to the page where the user could sign the document. Once I have put the signature image on top of the link, the link gets hidden but when you hover over it you’ll notice that the area where the link used to exist and the mouse changes to a cursor. I need to totally remove that link and then put the signature image at the position.

Also I am placing the signature image using the llx, lly, urx, ury coordinates of the text that is to be replaced, however when I place the image at those coordinates, the signature image appears above the text and not over it. I had to do a -20 to the lly coordinate to move the signatures over the link, the llx coordinate seems to be ok. Is there some issue with the coordinates being read and when something is placed at such coordinates using aspose?

Below is the coldfusion code the put the signature image at the coordinates saved earalier:

<CFOBJECT
	action = "create"
	type="java"
	class="com.aspose.pdf.facades.PdfFileMend"
	name="x">
	
<cfoutput>
	<cfset x.bindPdf(filepath)>
	<cfloop list="#qryGetDocsAndTemplates.CandidateSignatureLocations#" index="eachSet" delimiters=";">
		<cfset pageNum = ListFirst(eachSet,"^")>
		<cfset coords = ListLast(eachSet,"^")>
		<cfset llx = ListFirst(coords)>
		<cfset lly = ListGetAt(coords,2)>
		<cfset lly = lly - 20>
		<cfset urx = llx + 80>
		<cfset ury = lly + 60>
		<cfset x.addImage("#imagepath#", pageNum, llx, lly, urx, ury)>
	</cfloop>
	<cfset x.save(newfilepath)>

</cfoutput>

@Batrinux,

This is the output PDF, kindly send us your input PDF and signature icon. We will investigate and share our findings with you.

Telnet PERM Exempt Offer (NO Retention W PDM) Template [Template].pdf (135.7 KB)
42102_Sign.png (3.4 KB)

Please find the input file and the signature file attachments. The PDF attached is the input PDF. In the first step, we fill out all the placeholders like [CandidateFullName], [Address] etc. in the input PDF with actual values from the database. We store the llx and lly coordinates of the text “[CandidateSignature]” in the database. We then replace the “[CandidateSignature]” with a link “Click here to sign”. The following PDF is generatedTelnet PERM Exempt Offer (NO Retention W PDM) Template [Template]2_Filled.pdf (161.8 KB).

Later when the candidate has signed the document we generate the filled and signed document and place the signatures (attached file above) at the coordinates which were stored earlier. However we have to do a lly-20 to place the signatures at the correct location otherwise the signatures appear above the line “Click here to Sign”. This filled and signed PDF was attached in the earlier response.

Hope this helps. Pls let me know if anything else is needed as well.

@Batrinux,

You can remove LinkAnnotation. Please try the following code example which is tested with the latest version 18.1 of Aspose.Pdf for .NET API.

[C#]

string dataDir = @"C:\Pdf\test588\";
Document document = new Document(dataDir + "Telnet PERM Exempt Offer (NO Retention W PDM) Template [Template]2_Filled.pdf");
Aspose.Pdf.Page page = document.Pages[1];
LinkAnnotation annot;
        
AnnotationSelector selector = new AnnotationSelector(
    new Aspose.Pdf.Annotations.LinkAnnotation(page, Aspose.Pdf.Rectangle.Trivial));
page.Accept(selector);
IList list = selector.Selected;
foreach (LinkAnnotation a in list)
{
    TextAbsorber absorber = new TextAbsorber();
    absorber.TextSearchOptions.LimitToPageBounds = true;
    absorber.TextSearchOptions.Rectangle = a.Rect;
    page.Accept(absorber);
    if (absorber.Text.Equals("Click here to Sign"))
    {
        annot = a;
        // Load image into stream
        FileStream imageStream = new FileStream(dataDir + "42102_Sign.png", FileMode.Open);
        // Add image to Images collection of Page Resources
        page.Resources.Images.Add(imageStream);
        // Using GSave operator: this operator saves current graphics state
        page.Contents.Add(new Operator.GSave());
        // Create Rectangle and Matrix objects
        Aspose.Pdf.Rectangle rectangle = new Aspose.Pdf.Rectangle(annot.Rect.LLX, 
            annot.Rect.LLY, annot.Rect.LLX + 80, annot.Rect.LLY + 30);
        Matrix matrix = new Matrix(new double[] { rectangle.URX - rectangle.LLX, 0, 0, rectangle.URY - 
            rectangle.LLY, rectangle.LLX, rectangle.LLY });
        // Using ConcatenateMatrix (concatenate matrix) operator: defines how image must be placed
        page.Contents.Add(new Operator.ConcatenateMatrix(matrix));
        XImage ximage = page.Resources.Images[page.Resources.Images.Count];
        // Using Do operator: this operator draws image
        page.Contents.Add(new Operator.Do(ximage.Name));
        // Using GRestore operator: this operator restores graphics state
        page.Contents.Add(new Operator.GRestore());
        // delete link annotation
        page.Annotations.Delete(annot);
        // Save updated document
        document.Save(dataDir + "AddImage_out.pdf");      
    }
}

This is the output PDF file: AddImage_out.pdf (175.3 KB)

@Imran.rafique,

Can I pls have something similar in java? I will at least know the classes and methods to invoke through coldfusion.

Regards,

I mean we are using aspose.total for java. So java would have been more helpful.

@Batrinux,
Please try the following Java code example:

[Java]

String dataDir = "C:\\Pdf\\test588\\";
Document document = new Document(dataDir + "Telnet PERM Exempt Offer (NO Retention W PDM) Template [Template]2_Filled.pdf");
Page page = document.getPages().get_Item(1);
LinkAnnotation annot;
AnnotationSelector selector = new AnnotationSelector(
		    new LinkAnnotation(page, Rectangle.getTrivial()));
page.accept(selector);
List list = selector.getSelected();
for (Iterator<LinkAnnotation> i = list.iterator(); i.hasNext();)
{
	LinkAnnotation a = i.next();
	TextAbsorber absorber = new TextAbsorber();
	absorber.getTextSearchOptions().setLimitToPageBounds(true);
	absorber.getTextSearchOptions().setRectangle(a.getRect());
	page.accept(absorber);
	if (absorber.getText().equals("Click here to Sign"))
	{
	    annot = a;
	    // Load image into stream
	    java.io.FileInputStream imageStream = new java.io.FileInputStream(new java.io.File(dataDir + "42102_Sign.png"));
			    
	    // Add image to Images collection of Page Resources
	    page.getResources().getImages().add(imageStream);
	    // Using GSave operator: this operator saves current graphics state
	    page.getContents().add(new Operator.GSave());
	    // Create Rectangle and Matrix objects
	    com.aspose.pdf.Rectangle rectangle = new com.aspose.pdf.Rectangle(annot.getRect().getLLX(), 
           annot.getRect().getLLY(), annot.getRect().getLLX() + 80, annot.getRect().getLLY() + 30);
	   Matrix matrix = new Matrix(new double[] { rectangle.getURX() - rectangle.getLLX(), 0, 0, rectangle.getURY() -  rectangle.getLLY(), rectangle.getLLX(), rectangle.getLLY() });
	   // Using ConcatenateMatrix (concatenate matrix) operator: defines how image must be placed
	   page.getContents().add(new Operator.ConcatenateMatrix(matrix));
	   XImage ximage = page.getResources().getImages().get_Item(page.getResources().getImages().size());
	   // Using Do operator: this operator draws image
	   page.getContents().add(new Operator.Do(ximage.getName()));
	   // Using GRestore operator: this operator restores graphics state
	   page.getContents().add(new Operator.GRestore());
	   // delete link annotation
	   page.getAnnotations().delete(annot);
	   // Save updated document
	   document.save(dataDir + "AddImage_outJava.pdf");      
    }
}

Hi,

I have translated the code to ColdFusion. However I am getting an error on the line <cfset page.getContents().add(operator.GSave())>. The error says method GSave cannot be found in class Operator.

						<cfset oPDF.init(filepath)>								
						
						<CFOBJECT
							action = "create"
							type="java"
							class="com.aspose.pdf.Page"
							name="page">
							
						<cfset page = oPDF.getPages().get_Item(1)>
						
						<CFOBJECT
							action = "create"
							type="java"
							class="com.aspose.pdf.AnnotationSelector"
							name="selector">
						
						<CFOBJECT
							action = "create"
							type="java"
							class="com.aspose.pdf.LinkAnnotation"
							name="linkAnnotation">
						
						<CFOBJECT
							action = "create"
							type="java"
							class="com.aspose.pdf.Rectangle"
							name="rectangle">
						
						<cfset selector.init(linkAnnotation.init(page, rectangle.getTrivial()))>
						
						<cfset page.accept(selector)>
						
						<cfset list = selector.getSelected()>
						
						<cfset listcount = list.iterator()>
						
						<cfloop condition="list.iterator().hasNext() gt 0">
							
							<cfset a = list.iterator().next()>
							
							<!---<cfset a = i.next()>--->

							<CFOBJECT
								action = "create"
								type="java"
								class="com.aspose.pdf.TextAbsorber"
								name="textAbsorber">
								
							<cfset textAbsorber.getTextSearchOptions().setLimitToPageBounds(true)>
							<cfset textAbsorber.getTextSearchOptions().setRectangle(a.getRect())>
							<cfset page.accept(textAbsorber)>
							<cfset textVal = textAbsorber.getText()>
							<cfif textVal is "Click here to Sign">
								<cfset annot = a>
								
								<cfobject
									action="create"
									type="java"
									class="java.io.FileInputStream"
									name="imageStream">
								
								<cfset imageStream.init(imagepath)>
								
								<cfset page.getResources().getImages().add(imageStream)>
								
								<CFOBJECT
									action = "create"
									type="java"
									class="com.aspose.pdf.Operator"
									name="operator">
																	
								<cfset page.getContents().add(operator.GSave())>
								
								<CFOBJECT
									action = "create"
									type="java"
									class="com.aspose.pdf.Rectangle"
									name="rectangle">
								
								<cfset rectangle.init(annot.getRect().getLLX(), annot.getRect().getLLY(), annot.getRect().getLLX() + 80, annot.getRect().getLLY() + 30)>
								
								<CFOBJECT
									action = "create"
									type="java"
									class="com.aspose.pdf.Matrix"
									name="matrix">
								
								<cfset matrix.init(rectangle.getURX() - rectangle.getLLX(), 0, 0, rectangle.getURY() -  rectangle.getLLY(), rectangle.getLLX(), rectangle.getLLY())>
								
								<cfset page.getContents().add(operator.ConcatenateMatrix(matrix))>
								
								<cfset ximage = page.getResources().getImages().get_Item(page.getResources().getImages().size())>
								
								<cfset page.getContents().add(operator.Do(ximage.getName()))>
								
								<cfset page.getContents().add(operator.GRestore())>
								
								<cfset page.getAnnotations().delete(annot)>
								
								<cfset oPDF.save(newfilepath)>
								
							</cfif>
						</cfloop>

Any thoughts on how to fix the issue. If I comment the line that gives me the error, I get errors on lines where the object operator is used.

@Batrinux,

Did you try the latest version 17.12 of Aspose.Pdf for Java API? If not, then please download and try the latest version, and then let us know how that goes into your environment.

Yes, I downloaded the latest version, but still I get the same error at places where I have used the Operator object.

Below is the exact error that I get:

The GSave method was not found. Either there are no methods with the specified method name and argument types or the GSave method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 0 methods that match the provided arguments. If this is a Java object and you verified that the method exists, use the javacast function to reduce ambiguity.
The error occurred on line 131.

@Batrinux,

This might due to the naming conflict of the class, e.g. the class becomes part of any other package. Please take a look over this Stack overflow thread: Method was not found, Coldfusion 11, CreateObject

Kindly send all details of the ColdFusion environment, so that we could replicate the same error. Your response is awaited.

While instantiating the class I am specifying the full package name i.e. “com.aspose.pdf.Operator”. And then I am invoking the GSave() method of the “operator” object. Is “GSave” really a method because the aspose documentation says something about it being a extended class.

We are using ColdFusion 11,0,10,300066 on a windows 2012 server with SQL server as the database. Awaiting your response.

Let me know if you need any more information about the environment that we have.

@Batrinux,

Thank you for the details. We are preparing a ColdFusion environment and will let you know for further details. Please spare us a little time and we will get back to you in the next week.

Hi,

Were you able to replicate the error that I am getting by now?

Regards

@Batrinux,

We have prepared an instance of Windows Server 2012 with SQL server and working over the configuration of ColdFusion. We will get back to you soon.