It all started with a question a developer posted in the Universal Thread Visual FoxPro forum:
Does anyone know how to create a monochrome bitmap or monochrome tiff file from a VFP report?
I need to automate the process. We are using this for a faxing application and it must work in a multi-user environment
Well, there is ReportListener object in VFP9 that can solve at least a part of this task. Its OutputPage method can render the output of a report to a bitmap file. The code is very simple (requires VFP9):
LOCAL oListener As ReportListener, nPageIndex
oListener = CREATEOBJECT("ReportListener")
oListener.ListenerType=3 && renders all pages at once
* make sure the report can load and run
REPORT FORM MyReport PREVIEW OBJECT oListener
FOR nPageIndex=1 TO oListener.PageTotal
cOutputFile = "tmp"+TRANS(nPageIndex)+".bmp"
cOutputFile, 105, 0,0,768,1024) && 105=bitmap
I run the code and voila! It created one bitmap file for each page of my report. But the output files were nothing but small: 32 bits per pixel, 3.28 MB each. Still I was half way through.
After that I tried to find a solution using C# .NET, any solution at all. The Bitmap object did not help either. It failed to Clone to the PixelFormat.Format1bppIndexed, each time producing the System.OutOfMemoryException. That appeared consistent with GpStatus=3 returned by the GdipGetImageGraphicsContext function in my VFP tests.
Finally I gave up on GDI+ and switched to good old GDI API calls. And they worked perfectly, credits to the LoadImage for doing the actual conversion.
The code above implements:
PROCEDURE SaveBitmapAsMonochrome(srcfile As String, dstfile As String)
To create HBITMAP from a bitmap file I use the LoadImage with LR_LOADFROMFILE and LR_MONOCHROME flags. This way, it takes care of all color-to-monochrome mumbo-jumbos, which fact I am very happy with.
The source HBITMAP is selected into a memory device context. Then both of them are passed to the SaveBitmapToFile procedure.
The procedure is a bit hard-coded, which means it produces monochrome bitmap files only. It creates BITMAPINFOHEADER and BITMAPFILEHEADER structures, extracts bitmap binary data using the GetDIBits function and then saves everything to a file.
* * *
The writing and reading from temporary file makes the C# code noticeably slow on large files, which appears to be an unavoidable pay-off for the utter simplicity of this approach.