Very strange, but repeatable issue I've run into. I'm using the barbecue Java barcode generator library to generate code128 compliant barcodes which are then handed to cfimage writeToBrowser to finally end up with printable packing/mailing labels. When rendered to screen, everything works perfectly, but as soon as I wrap it in a cfdocument tag, so that we can generate as a pdf for printing on a label printer, I'm ending up with the wrong image on the wrong label in a few cases. It's always the same records that end up reusing an image from an earlier record (and always the same earlier record). I can check in the ColdFusion8\tmpCache\CFFileServlet\_cf_image folder and see that all the correct images were created by the cfimage tag, but for whatever reason, some of the images don't make it into the pdf, but are replaced by a different barcode from an earlier record. I can't see any commonality between the two records and if I intentionally remove the earlier record from the query, the proper barcode shows up.
So, any ideas about where to go from here? Anybody know anything about how cfdocument pulls in images and if there is any kind of caching or prechecking of the images before rendering. I actually checked to make sure the two files didn't have the same MD5 sum to see if there was something happening there where CF thinks it's the same image. They were not the same.
I've tried this on two CF 8.01 boxes with the same result. Always the same records, same images, same problem, even if I limit the query to only the two problem records. I'm totally stumped. Anybody?
Not sure it's helpful, but here's the code, at least the relevant parts. As I said, I've confirmed that this is all doing what it's supposed to and if I take off the cfdocument, it renders to the screen perfectly every time.
<cfdocument format="PDF" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">
<cfset labelCounter = 1 />
<cfoutput query="qryGetShippingLabelData" group="Lab_Code">
<!--- Do some stuff --->
<cfoutput group="shipGroup">
<cfloop from=1 to=#numLabels# index="i">
<cfset bcText = "" />
<cfif labelCounter NEQ 1><cfdocumentitem type="pagebreak" /></cfif>
#labelHead#
<cfoutput>
<cfset bcText = bcText & numberFormat(study_id,"00000") & iif(singleSampleBox,1,numSamples) />
</cfoutput>
<cfset bcText = numberFormat(Lab_ID,"00000") & bcText />
<p><cfimage action="writeToBrowser" source="#getCode128(bcText)#" /></p>
#labelFoot#
<cfset labelCounter = labelCounter + 1 />
</cfloop>
</cfoutput>
</cfoutput>
</cfdocument>
Well, we're on the same page there. I've done all that you've mentioned and it's always correct (keep in mind, outputing to screen is always working, it's just inside cfdocument that I see this problem and it's always the same records). The grouping and looping is defintely working as expected and urls to images are the correct urls, even in the pdf, but the image is not what the url is pointing to. I've pretty well convinced myself that it has to be something about how cfdocument gets images.
As one more piece of data to add, I just tried adding a random integer at the beginning of the bcText, which obviously then generates a different barcode image and it worked correctly, even in the pdf. So it's something about the particular image files that get created. I'm thinking only an Adobe CF engineer with knowledge of the inner workings of cfdocument is going to be able to help me. Anyone know who that might be?
jeff.c wrote:
Not sure it's helpful, but here's the code, at least the relevant parts. As I said, I've confirmed that this is all doing what it's supposed to and if I take off the cfdocument, it renders to the screen perfectly every time.
<cfdocument format="PDF" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">
<cfset labelCounter = 1 />
<cfoutput query="qryGetShippingLabelData" group="Lab_Code">
<!--- Do some stuff --->
<cfoutput group="shipGroup">
<cfloop from=1 to=#numLabels# index="i">
<cfset bcText = "" />
<cfif labelCounter NEQ 1><cfdocumentitem type="pagebreak" /></cfif>
#labelHead#
<cfoutput>
<cfset bcText = bcText & numberFormat(study_id,"00000") & iif(singleSampleBox,1,numSamples) />
</cfoutput>
<cfset bcText = numberFormat(Lab_ID,"00000") & bcText />
<p><cfimage action="writeToBrowser" source="#getCode128(bcText)#" /></p>
#labelFoot#
<cfset labelCounter = labelCounter + 1 />
</cfloop>
</cfoutput>
</cfoutput>
</cfdocument>
The code needs improving. The PDF may render correctly after that, who knows.
1) You have, at the centre of it all, code that is within 3 loops. It will help to scope the variables, such as qryGetShippingLabelData.x and shipGroup.y.
2) The cfouput tag in the following stretch is unnecessarily in the way:
<cfoutput>
<cfset bcText = bcText & numberFormat(study_id,"00000") & iif(singleSampleBox,1,numSamples) />
</cfoutput>
Then again, if you drop this cfoutput tag you will get:
<cfset bcText = bcText & numberFormat(study_id,"00000") & iif(singleSampleBox,1,numSamples) />
<cfset bcText = numberFormat(Lab_ID,"00000") & bcText />
That looks like repetition to me. At least, it doesn't appear to me that that was the intention.
Nope. All grouping and loops are necessary based on the shape of the data and the required output based on the number of labels required for each row in the source query. I'm doing something at each stage of the grouping (although I removed some of that because it wasn't really relevant to the question) to build these labels. I'm quite confident that the grouping and looping is correct and not part of the problem. In fact, I've built a simple test page that removes all the complexity of my grouping and query and will still produce this problem (although you have to have the barbecue library to test).
<cfset bbq = createObject("java", "net.sourceforge.barbecue.BarcodeFactory") />
<cfset ih = createObject("java", "net.sourceforge.barbecue.BarcodeImageHandler") />
<cfscript>
function getCode128 (data) {
barcode = bbq.createCode128(data);
barcode.setBarWidth( 1 );
barcode.setBarHeight( 50 );
barcode.setDrawingText( false );
barcode.setDrawingQuietSection( false );
barcode.setResolution( 200 );
newImg = ih.getImage( barcode );
barcodeImage = ImageNew(newImg);
return barcodeImage;
}
</cfscript>
<cfset list = "00413001811,00403001811" />
<cfdocument format="pdf" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">
<html>
<head>
</head>
<body>
<cfloop list="#list#" index="i">
<p><cfimage action="writetobrowser" source="#getCode128("#i#")#" /></p>
<p><cfoutput>#i#</cfoutput></p>
</cfloop>
</body>
</html>
</cfdocument>
-==cfSearching==- wrote:
function getCode128 (data) {
barcode = bbq.createCode128(data);
barcode.setBarWidth( 1 );
After seeing the function code, first thing I would recommend is VAR scoping all of the function local variables. Then try it again.
In fact, I would VAR newImg and barcodeImage as well.
-==cfSearching==- wrote:
In fact, I would VAR newImg and barcodeImage as well.
Yep, that is why I said all function local variables. I was only trying to highlight the fact that were no VAR scope declarations at the top of the function. (I did not look over the variable names in detail :-)
Nice of you, but you needn't explain. It was an oversight. I was already thinking VAR myself, and so just skimmed 'barcode' and 'VAR'. Sorry.
jeff.c wrote:
Nope. All grouping and loops are necessary based on the shape of the data and the required output based on the number of labels required for each row in the source query. I'm doing something at each stage of the grouping (although I removed some of that because it wasn't really relevant to the question) to build these labels. I'm quite confident that the grouping and looping is correct and not part of the problem. In fact, I've built a simple test page that removes all the complexity of my grouping and query and will still produce this problem (although you have to have the barbecue library to test).
<cfset bbq = createObject("java", "net.sourceforge.barbecue.BarcodeFactory") />
<cfset ih = createObject("java", "net.sourceforge.barbecue.BarcodeImageHandler") />
<cfscript>
function getCode128 (data) {
barcode = bbq.createCode128(data);
barcode.setBarWidth( 1 );
barcode.setBarHeight( 50 );
barcode.setDrawingText( false );
barcode.setDrawingQuietSection( false );
barcode.setResolution( 200 );
newImg = ih.getImage( barcode );
barcodeImage = ImageNew(newImg);
return barcodeImage;
}
</cfscript>
<cfset list = "00413001811,00403001811" />
<cfdocument format="pdf" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">
<html>
<head>
</head>
<body>
<cfloop list="#list#" index="i">
<p><cfimage action="writetobrowser" source="#getCode128("#i#")#" /></p>
<p><cfoutput>#i#</cfoutput></p>
</cfloop>
</body>
</html>
</cfdocument>
The question remains why it fails with, but works without, cfdocument. Does cfdocument introduce a new page context? I wonder. If so, then what -==cfSearching==- said about varring the variables would immediately make sense. Unvarred variables belong to the context of the current page.
Another issue may arise from <cfloop list="#list#" index="i">. You implicitly assume that ColdFusion will process the list elements in the exact order in which they appear in the list. I suspect ColdFusion wont always. It may internally apply some kind of sorting, and begin with the last element in the list.
@BKBK: I don't want to sidetrack the thread here, but that last statement about assuming the order of processing on a list in the CFLOOP tag is pretty concerning. I've never witnessed any behavior other than processing the list exactly in the order provided, and I have a hard time believing that we've just been lucky for 15 years. That /is/ in fact a key assumption in lots of CFML code. Do you have a basis for that statement, either in the docs or repeatable behavior in code you can share? To have them processed in anything other than the order provided seems so counterintuitive as to render the whole concept of using a list to drive any sort of iteration as basically useless...
--
/ron
cf_ron wrote:
@BKBK: I don't want to sidetrack the thread here, but that last statement about assuming the order of processing on a list in the CFLOOP tag is pretty concerning. I've never witnessed any behavior other than processing the list exactly in the order provided, and I have a hard time believing that we've just been lucky for 15 years. That /is/ in fact a key assumption in lots of CFML code. Do you have a basis for that statement, either in the docs or repeatable behavior in code you can share? To have them processed in anything other than the order provided seems so counterintuitive as to render the whole concept of using a list to drive any sort of iteration as basically useless...
No need worrying or running for the hills, Ron. I wrote that piece without due attention. What I omitted says more about what I was thinking.
I was trying to puzzle out why ColdFusion would start looping a list at position 2, or at any position other than 1 for that matter. What I wished I had said follows.
Another issue may arise from <cfloop list="#list#" index="i">. If the list is indeed as it appears in the code, then there is no issue. However, suppose the list was comprised of the keys of a struct. That is, the list of keys is structKeyList(theStruct), and you've stated the list in the code as a simplified test page. You implicitly assume that ColdFusion will process the list elements in the exact order in which they appear in the list. I suspect ColdFusion wont always. It may internally apply some kind of sorting, and begin with the last element in the list.
Lots of interesting ideas, and appreciate the tips on var and scoping but, alas, as I suspected, this is definitely cfdocument losing it's mind. See code below:
<cfdocument format="pdf" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">
<html>
<head></head>
<body>
<div><img id="_cfimg6949878617879408634" src="_cfimg6949878617879408634.png" /></div>
<p>00413001811</p>
<div><img id="_cfimg300382366701370250" src="_cfimg300382366701370250.png" /></div>
<p>00403001811</p>
</body>
</html>
</cfdocument>
These are the two images I pulled from the temp directory where cfimage creates them. Moved them to my test folder and ran the above code and got a pdf with the correct image in the first image tag, but then the same image repeated in where the second image should have been. And before you ask, yes, I'm certain the images are different. In fact, here they are:
As before, running without the cfdocument tags renders the correct images in the correct spots. Can we now just agree that cfdocument is the culprit and maybe at least an acknowledgement from an Adobe rep that there may be an issue here?
jeff.c sent me a copy of his code and image files referenced above, and I have duplicated this behavior on a fully-updated 9.01 box. Same exact behavior, so it is clearly not something unique to 8.01 or something that has been patched in 9.x. I have a CF10 box I will try this on in a bit, as well...
Update: also does not work on CF10 beta -- same behavior.
--
/ron
I, too, have tested on CF 10 Beta. I painted a stripe across one of the barcodes for easier recognition.
(respectively: _cfimg6949878617879408634.png, _cfimg300382366701370250.png)
Then I ran the following code, first, without cfdocument, then with cfdocument.
<!---<cfdocument format="pdf" pagewidth="4" pageheight="6.0" pagetype="CUSTOM" margintop="0.17" marginbottom="0.05" marginleft="0.17" marginright="0.17">--->
<html>
<head></head>
<body>
<div><img id="_cfimg6949878617879408634" src="_cfimg6949878617879408634.png" /></div>
<p>00413001811</p>
<div><img id="_cfimg300382366701370250" src="_cfimg300382366701370250.png" /></div>
<p>00403001811</p>
</body>
</html>
<!---</cfdocument>--->
In both cases, the result was:
(Update: Grr... I just love this forum software.)
I think I was finally able to reproduce the behavior on 9.01. But it only happens when setDrawingText(..) is false.
<cfscript>
/* deliberately refactored to eliminate var scoping issues as a possible cause */
function getCode128 ( data, hideText ) {
var bbq = createObject("java", "net.sourceforge.barbecue.BarcodeFactory");
var ih = createObject("java", "net.sourceforge.barbecue.BarcodeImageHandler");
var barcode = bbq.createCode128( arguments.data );
barcode.setBarWidth( 1 );
barcode.setBarHeight( 50 );
barcode.setDrawingQuietSection( false );
barcode.setResolution( 200 );
if ( structKeyExists(arguments, "hideText") and arguments.hideText ) {
barcode.setDrawingText( false );
}
return ImageNew(ih.getImage( barcode ));
}
</cfscript>
<cfset numbers = ["00413001811","00403001811","00413001811","00403001811"] />
<cfdocument format="pdf">
<cfloop from="1" to="#arrayLen(numbers)#" index="i">
<cfset imgText = numbers[i] />
<cfset hideText = i lte 2 />
<cfoutput>
[#i#] #imgText# <cfimage action="writetobrowser" source="#getCode128(imgText, hideText)#" /><br />
</cfoutput>
</cfloop>
</cfdocument>
jeff.c wrote:
maybe at least an acknowledgement from an Adobe rep that there may be an issue here?
Well these are user-to-user forums. If you want to speak with an adobe representative, you need to use official channels. (While I have seen an occaisional comment here and there, it is rare. So it is extremely unlikely you would get a response from an Adobe employee here).
Message was edited by: -==cfSearching==-
@BKBK - Your test would validate my hypothesis that cfdocument is doing something to look at the images and determine if they have already been loaded and, if so, reuse the already loaded image. Whatever that comparison is based on is treating these two images as the same image. Since you've altered the original image, I'm not surprised that it now works correctly, but if you go back to the original images, unaltered, I'm quite confident you'll see the same behavior. For what it's worth, I compared the MD5 sum of the two images and they do not match.
@cfSearching - What you're seeing would also validate what I'm thinking. Once you include the text, you've fundamentally altered the signature of the image and cfdocument isn't mistaking them anymore. I'm not comfortable just including the barcode text though and hoping that it solves the problem. In my mind, it's still possible and likely that the underlying engine could still be confused in comparing images when I'm generating hundreds of these barcodes in a pop, and if it only happens very occasionally, then it's almost more problematic since I'd have to validate every single label to make sure it's right. In any case, you're right. I think I need to try and get some help from Adobe. I'm filing a bug right now.
UPDATE: Bug filed in adobe Bugbase - https://bugbase.adobe.com/index.cfm?event=bug&id=3158895
Message was edited by: jeff.c
I'm not comfortable just including the barcode text though and hoping
that it
solves the problem. In my mind, it's still possible and likely
that the underlying
engine could still be confused in comparing images
We are on the same page there. I would not rely on it either. It just helps illustrate the issue a bit more clearly.
-Leigh
jeff.c wrote:
@BKBK - Your test would validate my hypothesis that cfdocument is doing something to look at the images and determine if they have already been loaded and, if so, reuse the already loaded image. Whatever that comparison is based on is treating these two images as the same image. Since you've altered the original image, I'm not surprised that it now works correctly, but if you go back to the original images, unaltered, I'm quite confident you'll see the same behavior. For what it's worth, I compared the MD5 sum of the two images and they do not match.
Your confidence is justified! I reran my above test with the original image. I did reproduce the issue.
I think I was finally able to reproduce the behavior on 9.01. But it only happens when setDrawingText(..) is false.
I further tested the same code on CF 10 Beta. Irrespective of whether I used barcode.setDrawingText(false) or barcode.setDrawingText(true), I did reproduce the issue. Also, when I changed the order of the numbers from ["00413001811","00403001811"] to ["00403001811","00413001811"], the barcode image changed, but the issue persisted.
Leigh, you might want to change the text rendered red in your code to quoted strings.
Yes, you are right but that is courtesy of this lovely forum software ;-). After it mangled the original (with quotes) three times, I finally gave up. I am not sure it lets you edit posts after other responses are added. I will check the web interface later.
With Jeff.c's earlier images:
I used the following simplified code, and tried every which way to not reproduce the cfdocument problem. For example, I displayed the images on a separate CFM page, downloaded the page by cfhttp, and used cfdocument to display the page content. All my attempts failed. The problem persists.
<cfdocument format="pdf">
<p><img src="_cfimg6949878617879408634.png"></p>
<p><img src="_cfimg300382366701370250.png"></p>
</cfdocument>
FWIW, I was able to get past this issue by changing the cfimage tag to produce jpg images rather than png. Now, I have no way of knowing if this actually solved the problem or simply fixed it for these two images I was comparing and if I will now have to be on the lookout for other images with the same problem.
I did get a reply from Rupesh Kumar (Adobe CF Engineer) from a question I submitted on his ColdFused blog where he stated that the thought this had been fixed in 9.01. I assured him it had not and pointed him to the bug I filed.
jeff.c wrote:
I did get a reply from Rupesh Kumar (Adobe CF Engineer) from a question I submitted on his ColdFused blog where he stated that the thought this had been fixed in 9.01. I assured him it had not and pointed him to the bug I filed.
Well at least now you have a firm confirmation of your suspicion it is a it is a bug. Since it sounds like a known issue, did he mention anything about cause or possible work-arounds?
North America
Europe, Middle East and Africa
Asia Pacific