Hi,
Edit Microsoft has released a fix for this problem contact support for this
As all of you know the Image class in Dynamics Ax 4.0 and 2009 can only run on client. This poses a problem when you want to print for example invoices with your company logo on it. Having this found out I went to look for an alternative!
I’ve added this code to the top of the PDFViewer class in the writeBitmap(OutputBitmapField _field, OuputSection _section) method
if( isRunningOnServer() &&
_field.name() == #FieldLogo)
{
this.BLOGWriteBitmapOnServer(_field,_section);
super(_field, _section);
return;
}
Code language: PHP (php)
For the method BLOGWriteBitmapOnServer(OutputBitmapField _field, OuputSection _section) I have copied everything from the writeBitmap and started by replacing the Image object with a System.Drawing.Image object, you can make a company parameter for this file path.
img = System.Drawing.Image::FromFile(imgStr);
Code language: PHP (php)
After compiling there are a few errors witch I’ve corrected and ended up with this code.
public void BLOGWriteBitmapOnServer(OutputBitmapField _field, OuputSection _section)
{
#File
BinData bin = new BinData();
//Image img;
container data, imgInfoData;
str s;
real x1,x2, y1,y2;
Struct br;
int imageObjectNo = 0;
int newwidth, newheight;
real pdfPreviewScale = 0.8;
boolean generateXImage = false;
container c;
str fn;
FileIOPermission writePermission;
FileIOPermission readPermission;
boolean grayScale = false;
System.Drawing.Image img;
str imgStr;
int widthTemp, heightTemp;
CompanyInfo companyInfo = companyInfo::find();
;
new InteropPermission(InteropKind::ClrInterop).assert();
imgStr = companyInfo.BLOGCompanyLogoFile;
br = this.boundingRectTwips(currentPage, _section, _field);
x1 = br.value('x1'); y1 = br.value('y1');
x2 = br.value('x2'); y2 = br.value('y2');
if (_field.type() == 10) // resourceId, DB_RESId
{
//img = new Image(_field.resourceId());
img = System.Drawing.Image::FromFile(imgStr);
if (resourceIdImageMap.exists(_field.resourceId()))
imageObjectNo = resourceIdImageMap.lookup(_field.resourceId());
else
{
imageObjectNo = this.nextObjectNo();
resourceIdImageMap.insert(_field.resourceId(), imageObjectNo);
generateXImage = true;
}
if (debugLevel >= 1)
info ('Image in resource ' + int2str(_field.resourceId()));
}
else if (_field.type() == 7) // queue
{
c = _field.value();
if (c)
{
//img = new Image(c);
img = System.Drawing.Image::FromFile(imgStr);
imageObjectNo = this.nextObjectNo();
}
generateXImage = true;
if (debugLevel >= 1)
{
if (img)
info ('Image in container');
else
info ('No image in container');
}
}
else // string containing filename
{
//img = new Image(_field.imageFileName());
img = System.Drawing.Image::FromFile(imgStr);
if (stringImageMap.exists(_field.imageFileName()))
imageObjectNo = stringImageMap.lookup(_field.imageFileName());
else
{
imageObjectNo = this.nextObjectNo();
stringImageMap.insert(_field.imageFileName(), imageObjectNo);
generateXImage = true;
}
if (debugLevel >= 1)
info ('File is ' + _field.imageFileName());
}
if (img)
{
if (generateXImage)
{
fn = System.IO.Path::GetTempFileName();
widthTemp = img.get_Width();
heightTemp = img.get_Height();
img.Save(fn);
// revert previous assertion
CodeAccessPermission::revertAssert();
// assert read permissions
readPermission = new FileIOPermission(fn, #io_read);
readPermission.assert();
// BP deviation documented (note that the file io assert IS included above)
bin.loadFile(fn);
data = bin.getData();
// Get rid of the temporary file.
//WinAPIServer::deleteFile(fn);
CodeAccessPermission::revertAssert();
new InteropPermission(InteropKind::ClrInterop).assert();
System.IO.File::Delete(fn);
if (bitmapEncode85)
s = bin.ascii85Encode();
else
s = BinData::dataToString(data);
objectOffsetMap.insert(imageObjectNo, binBuffer.size());
this.appendTextToBuffer(int2str(imageObjectNo) + ' 0 obj '
Code language: PHP (php)
This could probably been done much cleaner, but it does the job. ๐
20 responses to “Dynamics Ax printing logo’s from batch”
Kevin,
This is REALLY nice thanks. I’m having sort of a weird problem with it though. I wrote a process that queues up the invoices that we’ve generated during that day and at night I go through and print a copy of the invoices to a PDF file and then email them out. The problem is that about 10% of the PDF’s are now corrupt. I’ve included an entire bad PDF file below and also the header of a good one. I’m attaching a b+w jpg (our logo) to the pdf. I tried a gif but AX didn’t seem to like that. Any ideas would be great. Thanks.
Paul
AX2009 SP1 RU4 + EE localization
Bad:
%PDF-1.3
% Invoice 00477715 – Report
% Generated by ppica on 2/9/2011 at 20:02:14
5 0 obj <>
1 0 obj <> endobj
2 0 obj <>endobj
3 0 obj <> endobj
4 0 obj
[/PDF /Text /ImageC]
endobj
xref
0 6
0000000000 65535 f
0000000286 00000 n
0000000350 00000 n
0000000394 00000 n
0000000450 00000 n
0000000082 00000 n
trailer <>
startxref
488
%%EOF
Good:
%PDF-1.3
% Invoice 00477717 – Report
% Generated by ppica on 2/9/2011 at 20:02:16
5 0 obj <>
1 0 obj <> endobj
2 0 obj <>endobj
8 0 obj <<
/Type/XObject /Subtype/Image /ColorSpace /DeviceRGB
/Name /I8 /BitsPerComponent 8
/Filter [/ASCII85Decode/DCTDecode] /DecodeParms[null<>]
/Length 20511
/Width 479 /Height 367
>>
stream
(followed by the binary data for the jpg and everything else)
Hmm we are using a jpg file too, sometimes we get an error ‘Could not convert Glyphs’ but I don’t think its related. I should do some more testing with this code I don’t have any time now ๐ If you find a solution for your problem let me know ๐
Unfortunately, my solution was pretty lame. Since this is a batch process that sends copies of the invoices out I simply check the file size on the PDF that’s generated and if it’s less that 5k I throw it out and try again until I get a good one and then move on.
The only thing that seemed to help was putting in a small delay. It’s almost like things were happening too fast within AX and the OS couldn’t keep up with reading in the jpg and then reading in PDF to attach to the email. Adding the delays in there has gotten my success rate up to around 95% as opposed to 90%.
Still a wonderful piece of code. ๐ I can’t thank you enough!
Paul
Hi Paul,
Does your batch process run multi threaded? If so try running it with a single thread.
Kevin
Nope, not multi-threaded. ๐ I usually don’t do that unless the job takes a huge amount of time. As it is, even with the delays I’ve added this job (which only runs once a day off hours) takes less than 2 minutes.
Paul
Thanks a lot for this helpfull post !!
Meanwhile there exists a hotfix from Microsoft. Contact your Microsoft Support and you’ll get a solution.
Thank you, I’ll edit my post.
Regards,
Kevin
I know I’m too late to this party, but will thow in my 2 cents nevertheless…
In my wanderings through GDI+, when doing a batch of image generation, I found marked performance improvement if I forcibly called for garbage collection between image instances.
GC.Collect(); // I think was the code
I’m fairly new to doing DAX programming. I can see “System.GC” in my X++ intellisense, but, it doesn’t allow me to compile the aforementioned line of code.
Hi,
Thanks for your comment ๐
Actually now that I come to think of it, all of the Image instances should be disposed along all node paths.
*edit* this should call the garbage collector.
By the way I’ve just downloaded the hotfix and this patches the server so this will probably be a much better solution.
Regards,
Kevin
Thanks for the post but i don’t solve my problem.
I’ve search the hotfix but i didn’t found it.
can you tell me which hotfix is?
i work with AX 4.0 and you?
thank, bye
Hello Sara,
This code is from Ax 2009 SP1 KRU7, I’m guessing it was KB2667355. If you can’t find it you should log a technical support call.
Kind Regards,
Kevin
Thanks Kevin,
it was hard but at last i found the hot fix!!
http://support.microsoft.com/kb/937345
thanks a lot, Sara
Hi, Can anyone please guide me how can I re-size an image using the same method described above for image processing. Your response will be highly appreciated.
Hi Faisal,
Have you tried setting the ResizeBitmap property to Yes on the Bitmap control of your report?
Kind regards,
Kevin
Kevin,
This was exactly what I was looking for and struggling with for a quite a while. You have saved me a lot of time and effort to get this to work. The hotfix works like a charm.
Thanks,
Bob
Can you tell me what this means “companyInfo.BLOGCompanyLogoFile;” .
I know its a field of table and its data type must be String but what data it should contain ?
Can you please let me know immediately as i am facing this issue since long time and have not got any solution.
Hi Lalit,
It’s the path to the image file, why don’t you use the Microsoft hotfix this is a way betters solution. You can find it on partnersource.
Kind regards,
Kevin
Which hotfix you are referring to?
Can you please provide me the link for it to download ?
Also can you please provide me the steps to install ?
Please contact Microsoft for the hotfix.
Kind regards,
Kevin