Coldfusion 2018 No SOF segment Multi-Page TIFF Error - coldfusion

I have a new CF18 server and I'm getting some errors reading and converting some old images that were readable on my previous CF11 server. FYI GetReadableImageFormats results in "BMP,GIF,JPEG,JPEG 2000,JPEG2000,JPG,PNG,PNM,RAW,TIF,TIFF,WBMP"
Normally I read the files as a Binary and put it into memory for manipulation
<cffile action="readBinary" file="#file_location#" variable="binImage" />
<cfimage action="read" source="#binImage#" name="objImage" isbase64="no">
This now results in an error:
"An exception occurred while trying to read the image. No SOF segment in stream"
Reading the file with action="read" and dumping the left(binImage, 999) results:
"...2015:10:07 17:46:58 Kofax standard Multi-Page TIFF Storage Filter v3.03.000,..."
Then I tried reading it into java using:
<cfset tifFileName="#file_location#">
<cfscript>
ss = createObject("Java","com.sun.media.jai.codec.FileSeekableStream").init(tifFileName);
//create JAI ImageDecoder
decoder = createObject("Java","com.sun.media.jai.codec.ImageCodec").createImageDecoder("tiff", ss, JavaCast("null",""));
</cfscript>
Which yields an error:
"Decoding of old style JPEG-in-TIFF data is not supported."
I found this...
Decoding of old style JPEG-in-TIFF data is not supported
Do you think using TwelveMonkeys ImageIO the best path to follow for my issue?
UPDATE: Based on the suggestion that there is an invalid marker 0xFF9E I tried the following:
<cffile action="readBinary" file="#file_location#" variable="binImage" />
<cfset hexEncoding = binaryEncode(binImage, "hex")>
<cfset new_hexEncoding = replaceNoCase(hexEncoding, 'FF9E', 'FFE9', 'ALL')>
<cfset binImage = binaryDecode(new_hexEncoding, "hex")>
isImage(binImage) returns "NO" and the "No SOF segment in stream" error persists. I looped over the hexEncoding and found the FF9E string 23x. I've never edited raw image code so I'm not sure my replace is correct.
Edit: At this point I'm fairly certain my Search and Replace hexEncoding, 'FF9E', 'FFE9' logic is flawed. there is no occurance of 0xff9e in the binaryEncoded binImage.

This was driving me nuts. I tried everything I could find short of installing extra JAVA libraries or routing it through other executables to make the conversion. In my case there is only one JPEG in a TIFF, so I wrote something that literally grabs the binary data for the JPEG out of the TIFF (doesn't account for pages) and serves it up. Once you have the binary of the JPEG you can write it to a file, do conversions on it, even stream it direct to the browser. Here ya go future people who need this. I didn't write it to do pages or detect what kind of tiff it is since for my uses I already know all that. These things are .bin files, but they are all the same single page jpeg in a tiff and I needed a way to serve them up quickly in a format that browsers don't hate. This runs fast enough to be served up on the fly. Is there a better way? Probably, but this works, self contained, copy and paste, and makes complete sense to anyone that needs to edit it.
<cfscript>
strFileName = "test.tiff";
blnOutputImageToBrowser = true;
blnSaveToFile = true;
strSaveFile = GetDirectoryFromPath(GetCurrentTemplatePath())&"test.jpg"
imgByteArray = FileReadBinary(strFileName);
//Convert to HEX String
hexString = binaryEncode(imgByteArray,"hex"); //Convert binary to HEX String, so we can pattern search it
//Set HEX Length
hexLength = arraylen(imgByteArray);
//Find Start of JPG Data in HEX String
jpegStartHEX = find("FFD8FF",hexString);
jpegStartBIN = (jpegStartHEX-1)/2; //-1 because CF arrays start on 1 and everyone else starts on 1. /2 because the HEX string positions are double the byte array positions
objByteBuffer = CreateObject("java","java.nio.ByteBuffer"); //Init JAVA byte buffer class for us to use later (this makes it go faster than trying to convert the hex string back to binary)
//Find Stop of JPG Data
jpegStopHEX = 0;
jpegStopBIN = 0;
intSearchIDX = jpegStartHEX+6; //Might as well start after the JPEG start block
blnStop = false;
while (intSearchIDX < len(hexString) && jpegStopHEX == 0 && !blnStop) {
newIDX = find("FFD9",hexString,intSearchIDX);
if (newIDX == 0) {
blnStop=true;
}
else {
if (newIDX%2 == 0) { //bad search try again (due to indexing in CF starting on 1 instead of 0, the even numbers are in between hex code [they are pairs like 00 and FF])
intSearchIDX = newIDX+1;
}
else { //Found ya
jpegStopHEX = newIDX;
blnStop=true;
}
}
}
jpegStopBIN = (jpegStopHEX-1)/2; //-1 because CF arrays start on 1 and everyone else starts on 1. /2 because the HEX string positions are double the byte array positions
//Dump JPG Binary into ByteArray from the start and stop positions we discovered
jpegLengthBIN = jpegStopBIN+2-jpegStartBIN;
objBufferImage = objByteBuffer.Allocate(JavaCast( "int", jpegLengthBIN ));
objBufferImage.Put(imgByteArray,JavaCast( "int", jpegStartBIN ),JavaCast( "int", jpegLengthBIN ));
if (blnSaveToFile) { //Dump byte array into test file
fileWrite(strSaveFile,objBufferImage.Array());
}
if (blnOutputImageToBrowser) {
img = ImageNew( objBufferImage.Array() );
ImageResize(img,"1200","","highestPerformance"); //Because we might as well show an example of resizing
outputImage(toBinary(toBase64(img))); //You could skip loading the byte array as an image object and just plop the binary in directly if you don't need to manipulate it any
}
</cfscript>
<cffunction name="outputImage" returntype="void">
<cfargument name="binInput" type="binary">
<cfcontent variable="#binInput#" type="image/png" reset="true" />
<cfreturn>
</cffunction>

Related

Base64 decoding error in coldfusion

I'm trying to decode a base64 string with #ToString( ToBinary( stringToDecode ) )# and coldfusion gives an error saying the parameter must be a base-64 encoded string. The string comes from a third party, and is supposed to be a pdf file. Here is a part of it:
JVBERi0xLjUKJeLjz9MKMSAwIG9iago8PC9UeXBlL1hPYmplY3QvUmVzb3VyY2VzPDw+Pi9TdWJ0 eXBlL0Zvcm0vQkJveFswIDAgMTUuNDQgMTUuNDZdL01hdHJpeCBbMSAwIDAgMSAwIDBdL0xlbmd0 aCAyMi9Gb3JtVHlwZSAxL0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCk9lHxbaEDXZpIO1A/Gj mGuxQdW3qkgKZW5kc3RyZWFtCmVuZG9iagoyIDAgb2JqCjw8L1R5cGUvWE9iamVjdC9SZXNvdXJj ZXM8PD4+L1N1YnR5cGUvRm9ybS9CQm94WzAgMCAxNS40NCAxNS4xOV0vTWF0cml4IFsxIDAgMCAx IDAgMF0vTGVuZ3RoIDIyL0Zvcm1UeXBlIDEvRmlsdGVyL0ZsYXRlRGVjb2RlPj5zdHJlYW0KtDN8 NkUKYx04Gj8V9LfOboGvN9VRIgplbmRzdHJlYW0KZW5kb2JqCjMgMCBvYmoKPDwvVHlwZS9YT2Jq ZWN0L1Jlc291cmNlczw8Pj4vU3VidHlwZS9Gb3JtL0JCb3hbMCAwIDE1LjQ0IDE1LjcyXS9NYXRy aXggWzEgMCAwIDEgMCAwXS9MZW5ndGggMjIvRm9ybVR5cGUgMS9GaWx0ZXIvRmxhdGVEZWNvZGU+
What I had thought was the spaces were a problem, but I did a replace to replace all " " with "" and they are still in there. Is there something else I should be doing?
In my testing I can take a local pdf and convert it to a string to mimic the string you are getting from the API. I can then take it and convert it back to a PDF.
When I use the string you put above I cannot get it to work. Not sure if something is list from you pasting it here or not.
Here is my code, maybe you can alter it to use the string right from the api.
<cffile action="readbinary" file="#expandPath('./test.pdf')#" variable="thefile"/>
<cfset the_string = toString(theFile)/>
<cfscript>
patrick_string = ToBase64("JVBERi0xLjUKJeLjz9MKMSAwIG9iago8PC9UeXBlL1hPYmplY3QvUmVzb3VyY2VzPDw+Pi9TdWJ0 eXBlL0Zvcm0vQkJveFswIDAgMTUuNDQgMTUuNDZdL01hdHJpeCBbMSAwIDAgMSAwIDBdL0xlbmd0 aCAyMi9Gb3JtVHlwZSAxL0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCk9lHxbaEDXZpIO1A/Gj mGuxQdW3qkgKZW5kc3RyZWFtCmVuZG9iagoyIDAgb2JqCjw8L1R5cGUvWE9iamVjdC9SZXNvdXJj ZXM8PD4+L1N1YnR5cGUvRm9ybS9CQm94WzAgMCAxNS40NCAxNS4xOV0vTWF0cml4IFsxIDAgMCAx IDAgMF0vTGVuZ3RoIDIyL0Zvcm1UeXBlIDEvRmlsdGVyL0ZsYXRlRGVjb2RlPj5zdHJlYW0KtDN8 NkUKYx04Gj8V9LfOboGvN9VRIgplbmRzdHJlYW0KZW5kb2JqCjMgMCBvYmoKPDwvVHlwZS9YT2Jq ZWN0L1Jlc291cmNlczw8Pj4vU3VidHlwZS9Gb3JtL0JCb3hbMCAwIDE1LjQ0IDE1LjcyXS9NYXRy aXggWzEgMCAwIDEgMCAwXS9MZW5ndGggMjIvRm9ybVR5cGUgMS9GaWx0ZXIvRmxhdGVEZWNvZGU+");
string2 = toBinary(ToBase64(the_string));
binencode=BinaryEncode(string2, "Base64");
</cfscript>
<cffile action="write" file="#expandPath('./randy.pdf')#" output="#thefile#" addnewline="No" />
click
Updated Code:
<cffile action="readbinary" file="#expandPath('./test.pdf')#" variable="thefile"/>
<cfset the_string = toBase64(theFile)/>
<cfscript>
string2 = toBinary(the_string);
</cfscript>
<cffile action="write" file="#expandPath('./randy.pdf')#" output="#string2#" addnewline="No" />
click
Here's an updated cfscript way of doing it in case anyone is interested:
<cfscript>
// read the binary file and save it as a variable
myPdf = fileReadBinary( expandPath( "/test.pdf" ) );
// encode as base64
myPdf = toBase64( myPdf );
// output the base64 version to the browser
writedump( myPdf );
// convert back to binary
myPdf = toBinary( myPdf );
// write to a new PDF file
fileWrite( expandPath( "/new.pdf" ), myPdf );
</cfscript>

How to skip unsupported image using cfimage processing?

I am using ColdFusion 10.
When trying to read some image files, ColdFusion returns no values and no error messages are shown.
I tried to re-size an image using cfimage tag. It is crashing. So I tried to get info about the image using "imageinfo" function. It returns blank. Please help me to either get some info or skip the image. Can anyone help me?
I tried reading the file which caused the anomaly using
<cfimage action="read" source="full pathname" name="image">
<cfset image = imageRead(full pathname)>
and many other ColdFusion documented functions. No error was shown. No output was obtained. I used cffile which showed unsupported file type error.
<cffile
action = "readBinary" file = "full pathname" variable = "variable name"
>
Thanks Rino
Try using this function for reading images.
<cfimage> tag or imageNew() can have issues while trying to read image files which are corrupted or files saved with changed extensions (background transparent .png files saved as .jpeg) while uploading.
I think the main problem with these files is that there is a chance coldfusion doesn't throw an error of any sort when we try to read files mentioned above.
<cfscript>
public function readImage(fullpath){
//trying java imageio
var imageFile = createObject("java", "java.io.File").init(fullpath);
// read the image into a BufferedImage
var ImageIO = createObject("java", "javax.imageio.ImageIO");
try {
var bi = ImageIO.read(imageFile);
return ImageNew(bi);
} catch(any e) {
//try for bad formatted images
//create java file object, passing in path to image
var imageFile = createObject("java","java.io.File").init(fullpath);
//create a FileSeekableStream, passing in the image file we created
var fss = createObject("java","com.sun.media.jai.codec.FileSeekableStream").init(imageFile);
//create ParameterBlock object and initialize it (call constructor)
var pb = createObject("java","java.awt.image.renderable.ParameterBlock").init();
//create JAI object that will ultimately do the magic we need
var JAI = createObject("java","javax.media.jai.JAI");
try {
//pass in FileSeekableStream
pb.add(fss);
//use the JAI object to create a buffered jpeg image.
var buffImage = local.JAI.create("jpeg", pb).getAsBufferedImage();
//pass the buffered image to the ColdFusion imagenew()
var New_Image = imagenew(buffImage);
//make sure we close the stream
fss.close();
return New_Image;
} catch (any e) {
if (isDefined("fss")) {
fss.close();
}
rethrow;
}
}
}
</cfscript>

Parametrising encoded web service requests

I am trying to parametrise web service requests in a web performance test. Using Fiddler2 I have recorded a sequence of over 60 web service requests for a transaction performed by my desktop application and saved them as a .webtest file. This web test runs without any errors and the responses that I have checked look correct.
When the web service requests are viewed in Visual Studio 2012 they appear in plain text and so I should be able to edit them to parametrise the values in the SOAP requests. For example, most of the requests contain the text <Database>db1a</Database> (actually it has <Database>db1a</Database>) and I want to change them to get the database name from a context parameter. There are several other items to replace with parameters. For this one transaction there are over 60 web service requests and I have other transactions to record. The .webtest file contains XML and the requests looks like:
<Request Method="POST" Version="1.1" Url="http://example.com/somewhere.asmx" ThinkTime="83" Timeout="60" ParseDependentRequests="True" FollowRedirects="True" RecordResult="True" Cache="False" ResponseTimeGoal="0" Encoding="utf-8">
<Headers>
<Header Name="Content-Type" Value="text/xml; charset=utf-8" />
<Header Name="SOAPAction" Value=""http://example.com/webservices/VariousActionNamesHere"" />
</Headers>
<StringHttpBody ContentType="text/xml; charset=utf-8">PAA/AHgAbQBsACAAdg
... lots more characters not shown
+AA==</StringHttpBody>
</Request>
The StringHttpBody field contains an encoded version of the SOAP request. Visual Studio shows it as plain text. What is the encoding of this field and how can I decode and encode it?
I have installed Release 3.0 of the “Web and Load Test Plugins for Visual Studio Team Test” from http://teamtestplugins.codeplex.com/ . They provide a slightly better interface for editing the SOAP requests one at a time. But they do not allow mass changes.
Converting the web test to a coded web test (ie into C#) shows the SOAP requests as simple text and they could be edited there but I would prefer to keep the flexibility of a .webtest file.
Update: I have posted a partial answer to the question. Whilst it works, it feels the wrong way to do the work because it feels too complicated. So I am looking for a better overall approach.
StringHttpBody is base64 encoded. The raw body of the request is converted to a UTF-16 byte array and then base64 encoded, like so:
Convert.ToBase64String(Encoding.Unicode.GetBytes(oSession.GetRequestBodyAsString()));
For a quick view, you can copy/paste this string into Fiddler's Tools > TextWizard screen then use the From Base64 option to decode.
Here is part of an answer to working with the StringHttpBody fields. This is about decoding and encoding the fields to allow easier understanding and modification.
Read the input XML and find the contents of the StringHttpBody fields. Replace each field contents with the result of calling the following routine on the original contents. Write the all the lines to a new intermediate file. The byte array contains UTF-16 characters as high and low bytes. (All the characters I have seen so far have high byte zero.)
private string DecodeBody(string source) {
byte[] outBytes = Convert.FromBase64String(source);
StringBuilder sb = new StringBuilder();
Assert( (outBytes.Length % 2) != 0 );
for (int ix = 0; ix < outBytes.Length; ix += 2) {
Assert(outBytes[ix] != 0);
sb.Append((char)outBytes[ix + 1]);
}
return sb.ToString();
}
Now have a file containing a simple text version of the .webtest file. This file can easily be edited to parameterise fields of the requests. Have an routine used similar to the one above and writing to another intermediate file. The routine has statements such as:
source = source.Replace("<Database>db1a</Database>", "<Database>{{DatabaseName}}</Database>");
The final intermediate file is then reencoded to create a new .webtest file. Just as before the contents of the StringHttpBody fields are found and replaced with the result of calling a routine. The encoding routine is:
private string EncodeBody(string source) {
StringBuilder sb = new StringBuilder();
byte[] outBytes = new byte[2 * source.Length];
for (int ix = 0; ix < source.Length; ix++) {
char ch = source[ix];
outBytes[2 * ix] = (byte)(((int)ch) & 0xFF);
outBytes[2 * ix + 1] = (byte)((((int)ch) / 256) & 0xFF);
}
sb.Append(Convert.ToBase64String(outBytes));
return sb.ToString();
}
The flow of files is thus:
decode original.webtest > intermediate1
parameterise intermediate1 > intermediate2
encode intermediate2 > final.webtest
On the small number of .webtest files I have tried the encode operation is the inverse of the decode operation, the original file from before decoding is identical to the file after encoding. Having the two intermediate files allows easy checking and searching of the contents of the unencoded file and the effect of the parameterise step.
For
[StringHttpBody ContentType="application/json"]
To Decode the body:
var encodedString = childNode.InnerText;
var encodedStringBytes = Convert.FromBase64String(encodedString);
var decodedString = Encoding.Unicode.GetString(encodedStringBytes);
JObject jsonString =JsonConvert.DeserializeObject(decodedString);
To Encode the body:
childNode.InnerText =
Convert.ToBase64String(Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(jsonString)));
I think this might help.

Authenticating DotNetNuke Users in ColdFusion

Is there any way to authenticate users from other web apps using the DNN logins?
We have a main site that is using DNN and user logins are stored in the asp net membership table. From what I have been reading, the passwords are encrypted using the machine key and then salted. I see where this info is, but can't seem to encrypt passwords correctly using this method.
I'm trying with a Coldfusion web application on the same server where our DNN site is, but it doesn't want to work. You'd think it would be strait forward with the ColdFusion encryption function:
Encrypt(passwordstring, key [, algorithm, encoding, IVorSalt, iterations])
No matter what I try, I never get a matching value.
Any help, insight or pointing me in the right direction would be greatly appreciated!
(Edit: Original answer did not work in all cases. Substantially revised ...)
From what I have read, DNN uses an "SHA1" hash by default. The thread #barnyr posted shows it simply hashes the concatenated salt and password, but with a few twists.
DNN uses UTF-16LE to extract the password bytes, rather than CF's typical UTF-8.
It also extracts the salt and password bytes separately, which may produce different results than just decoding everything as a single string, which is what hash() does. (See demo below)
Given that CF9's Hash function does not accept binary (supported in CF11), I do not think it is possible to duplicate the results with native CF functions alone. Instead I would suggest decoding the strings into binary, then using java directly:
Code:
<cfscript>
thePassword = "DT!#12";
base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
// extract bytes of the salt and password
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(thePassword, "UTF-16LE" );
// next combine the bytes. note, the returned arrays are immutable,
// so we cannot use the standard CF tricks to merge them
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
// hash binary using java
MessageDigest = createObject("java", "java.security.MessageDigest").getInstance("SHA-1");
MessageDigest.update(dataBytes);
theBase64Hash = binaryEncode(MessageDigest.digest(), "base64");
WriteOutput("theBase64Hash= "& theBase64Hash &"<br/>");
</cfscript>
Demo of Differences:
<cfscript>
theEncoding = "UTF-16LE";
thePassword = "DT!#12";
base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
// extract the bytes SEPARATELY
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(thePassword, theEncoding );
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
separateBytes = ArrayUtils.addAll( saltBytes, passBytes );
// concatenate first, THEN extract the bytes
theSalt = charsetEncode( binaryDecode(base64Salt, "base64"), theEncoding );
concatenatedBytes = charsetDecode( theSalt & thePassword, theEncoding );
// these are the raw bytes BEFORE hashing
WriteOutput("separateBytes= "& arrayToList(separateBytes, "|") &"<br>");
WriteOutput("concatenatedBytes"& arrayToList(concatenatedBytes, "|") );
</cfscript>
Results:
separateBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|77|-40|-14|104|68|0|84|0|33|0|64|0|49|0|50|0
concatenatedBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|-3|-1|68|0|84|0|33|0|64|0|49|0|50|0
Most likely the password is not encrypted, it is hashed. Hashing is different from encrypting, because it is not reversible.
You would not use ColdFusion's encrypt() function for this, you would use its hash() function.
So the questions you'll need to answer to figure out how to hash the passwords in CF to be able to auth against the DNN users are:
What algorithm is DNN using to hash the passwords?
How is the salt being used with the password prior to hashing?
Is DNN iterating over the hash X number of times to improve security?
All of those questions must be answered to determine how CF must use the hash() function in combination with the salt and user-submitted passwords.
I'll make some assumptions to provide an answer.
If we assume that noiteration is being done and that the salt is simply being appended to the password prior to using SHA1 to hash the password, then you'd be able to reproduce the hash digest like this:
<cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") />
(Posting a new response to keep the "encrypted" process separate from "hashing")
For "encrypted" keys, the DNN side uses the standard algorithms ie DES, 3DES or AES - depending on your machineKey settings. But with a few differences you need to match in your CF code. Without knowing your actual settings, I will assume you are using the default 3DES for now.
Data To Encrypt
The encrypted value is a combination of the salt and password. But as with hashing, DNN uses UTF-16LE. Unfortunately, ColdFusion's Encrypt() function always assumes UTF-8, which will produce a very different result. So you need to use the EncryptBinary function instead.
// sample valus
plainPassword = "password12345";
base64Salt = "x7le6CBSEvsFeqklvLbMUw==";
hexDecryptKey = "303132333435363738393031323334353637383930313233";
// first extract the bytes of the salt and password
saltBytes = binaryDecode(base64Salt, "base64");
passBytes = charsetDecode(plainPassword, "UTF-16LE" );
// next combine the bytes. note, the returned arrays are immutable,
// so we cannot use the standard CF tricks to merge them
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
Encryption Algorithm
With block ciphers, ColdFusion defaults to ECB mode. (See Strong Encryption in ColdFusion) Whereas .NET defaults to CBC mode, which requires an additional IV value. So you must adjust your CF code to match.
// convert DNN hex key to base64 for ColdFusion
base64Key = binaryEncode(binaryDecode( hexDecryptKey, "hex"), "base64");
// create an IV and intialize it with all zeroes
// block size: 16 => AES, 8=> DES or TripleDES
blockSize = 8;
iv = javacast("byte[]", listToArray(repeatString("0,", blocksize)));
// encrypt using CBC mode
bytes = encryptBinary(dataBytes, base64Key, "DESede/CBC/PKCS5Padding", iv);
// result: WBAnoV+7cLVI95LwVQhtysHb5/pjqVG35nP5Zdu7T/Cn94Sd8v1Vk9zpjQSFGSkv
WriteOutput("encrypted password="& binaryEncode( bytes, "base64" ));

Converting Files to PDF and attaching to another PDF in Coldfusion

So I'm doing a project that generates a PDF of information that was previously filled out in a form. Along with this information, documents were attached to support the information in the form.
I generate the PDF with the normal info from my DB, but I also want to convert their uploaded files (if .doc or .docx) to PDF format and stick in the same PDF. (So it is all in one place.)
I know how to convert to PDF, problem is how do you attach those newly generated PDFs to the current one with the other information on it?
you have 2 options:
merge all PDFs into one using <cfpdf action="merge"...>
really attach files in your main pdf but as CFPDF does not support it (yet?) you have to use iText:
<cfscript>
try {
// Source of THE main PDF and destination file
inputFile = ExpandPath("myDoc.pdf");
outputFile = ExpandPath("myDocPlusAttachments.pdf");
// the file to attach (can be of any type)
attach1 = ExpandPath("myAttachment.doc");
// prepare everything
reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( inputFile );
outStream = createObject("java", "java.io.FileOutputStream").init( outputFile );
stamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( reader, outStream );
// attachment the file
stamper.addFileAttachment("My Attached File", javacast("null", ""), attach1, "myAttachment.doc");
// display the attachment pane when the pdf opens (Since 1.6)
writer = stamper.getWriter();
writer.setPdfVersion( writer.VERSION_1_6 );
}
finally {
// always cleanup objects
if (IsDefined("stamper")) {
stamper.close();
}
if (IsDefined("outStream")) {
outStream.close();
}
}
</cfscript>
Just found where I got that piece of code: ColdFusion 9: Adding Document Level Attachments to a PDF with iText
You need to use the CFPDF tag, and use the merge action.