Showing posts with label FoxyPreviewer. Show all posts
Showing posts with label FoxyPreviewer. Show all posts

2025-10-28

Creating Merged Reports and Exporting to PDF using FoxyPreviewer (Chaining / Combining reports)

One of the coolest possibilities brought to VFP9 reports is the ability to merge more than one report in a single run.
This is done by using the clauses NOPAGEEJECT and NORESET:
  • NOPAGEEJECT tells the Report Engine to wait for the next report instead of ejecting the current page.

  • NORESET keeps the page counter continuing from the previous report session.

This simple but powerful combination lets you join several reports into a continuous output — ideal for creating consolidated reports, multi-section documents, or any case where different layouts should appear in a single file.

And the best part: FoxyPreviewer works beautifully with merged reports — whether you just preview them on-screen or export them directly to PDF, Excel, or other formats.

Below are a few common scenarios and how to handle them using FoxyPreviewer.

⚠️ Important: When working with merged reports, the PREVIEW and/or TO FILE clauses must appear in all the REPORT FORM commands in your sequence.
Otherwise, the reports will not merge properly, and you might see only the first one.



🧩 1. Merged Report with Preview

You can easily merge several reports and display them in FoxyPreviewer’s interactive preview window.
Here’s the general idea:

* Sample 1
* Chained report / Normal Preview
DO FoxyPreviewer.App
REPORT FORM (_Samples + "\Solution\Reports\Colors.frx") NOPAGEEJECT PREVIEW
REPORT FORM (_Samples + "\Solution\Reports\Wrapping.frx") NOPAGEEJECT NORESET PREVIEW
REPORT FORM (_Samples + "\Solution\Reports\Percent.frx") NORESET PREVIEW

The reports will appear seamlessly one after another, sharing the same preview session.


🧩 2. Merged Report → Save to PDF and Open in Default PDF Viewer

If you want to create a merged report and automatically save it as a PDF, then open it in the user’s default PDF reader, FoxyPreviewer makes that just as easy:

* Sample 2
* Chained report / Save to file / Preview in default PDF reader
DO FoxyPreviewer.App
lcFile = "c:\Temp\MyReport.pdf"
REPORT FORM (_Samples + "\Solution\Reports\Colors.frx") NOPAGEEJECT TO FILE (lcFile) PREVIEW
REPORT FORM (_Samples + "\Solution\Reports\Wrapping.frx") NOPAGEEJECT NORESET TO FILE (lcFile) PREVIEW
REPORT FORM (_Samples + "\Solution\Reports\Percent.frx") NORESET TO FILE (lcFile) PREVIEW

This approach is great for automated workflows or batch processing — the user gets the final PDF file immediately.


🧩 3. Merged Report → Save to PDF without Preview (Silent)

Sometimes you just need to generate the final PDF file silently — for example, when the output is sent by email or stored in a shared folder.

* Sample 2
* Chained report / Save to file / NO Preview (silent)
DO FoxyPreviewer.App
lcFile = "c:\Temp\MyReport.pdf"
REPORT FORM (_Samples + "\Solution\Reports\Colors.frx") NOPAGEEJECT TO FILE (lcFile)
REPORT FORM (_Samples + "\Solution\Reports\Wrapping.frx") NOPAGEEJECT NORESET TO FILE (lcFile)
REPORT FORM (_Samples + "\Solution\Reports\Percent.frx") NORESET TO FILE (lcFile)

No window is shown; the file is generated in the background, ready to use.


✅ Wrapping Up

Merging reports is one of those features that makes VFP9’s reporting engine truly shine — and with FoxyPreviewer, the possibilities go even further.
You can mix multiple report layouts, include summaries, attach additional pages, and export everything in one clean, professional-looking PDF.

If you haven’t tried it yet, download the latest version from
👉 www.foxypreviewer.com

2025-10-21

FoxyPreviewer3 and VFPA64


FoxyPreviewer has long been a trusted tool in the Visual FoxPro community, offering enhanced reporting capabilities, PDF exporting, previewing, and much more. While full compatibility with VFPA32 and VFPA64 hasn't been a core development goal, many developers have asked how well FoxyPreviewer works in these environments.

I'm happy to share that:


🧩 FoxyPreviewer3 now works well with VFPA64!


There were a few reported issues in the past—ranging from minor glitches to isolated crashes—but these now appear to be resolved. In recent tests and community feedback, FoxyPreviewer has been performing normally under VFPA64, with no significant problems.

⚠️ If you do encounter any issues specific to VFPA, please report them directly to: vfpimaging @ hotmail.com

 


🔍 A Quick Refresher: What FoxyPreviewer Brings

💾 PDF, RTF, XLS, Image Exporting
Easily export reports to multiple formats, including native PDFs, without requiring additional software.

🖨️ Advanced Report Previewer
Modern and flexible preview window with toolbar, zoom, search, annotation, and print features.

🎨 Custom Report Output
Supports dynamic fonts, images, barcodes, and more using ReportListener hooks.

📌 Localization and Configuration
Fully customizable toolbars, multi-language support, and user-friendly settings programmatically or interactively.


🤝 A Word of Thanks

A special thank-you goes to Chen, the developer of VFPA (Visual FoxPro Advanced), for his responsiveness and collaboration in addressing compatibility issues.


🔗 Useful Links

Thanks to the community for the feedback and testing—keep it coming!




⚠️ Important note about VFPA compatibility

FoxyPreviewer is an independent project and has no direct relation to VFPA or its development.
I’m not responsible for VFPA32 or VFPA64, and users should use these versions at their own risk.

FoxyPreviewer is not officially supported in the VFPA environment, and I don’t explicitly test each new release there.
If you decide to use it with VFPA, please make sure to perform your own compatibility testing.


2023-04-16

Capture Form portions - FoxyCapture

Recently Tom Knauf from Germany asked for a feature in FoxyPreviewer3 to allow users to pick specific parts of their reports and export them to the clipboard or save as image in an easy way.

Nothing new on this, I even published about 10 years ago a solution for that, but it was not working anymore.

So, I took the opportunity to create it from scratch, but this time thinking of a good way to make it work safely with FoxyPreviewer3.

FOXYCAPTURE is a custom VFP class that you can toss in any VFP form.

To activate it, just call the method "StartCapture", and select the rectangle portion of your form you's like to capture. After dragging, a shortcut menu will allow you to either save as PNG or send the image to the clipboard.

Source code and a sample form included, please let me know if you find any issues or make any improvements.

Below some animated images showing how it works.


Picture1 - Capture to image file



Picture2 - Capture image to the clipboard, and paste it to WhatsApp web:


Files to include in your project:

  • FoxyCapture.vcx
  • FoxyCapture.vct
  • fc_Save.Bmp
  • fc_Clipboard.bmp


Related Methods / Properties

Method:

StartCapture - Starts capturing the mouse events to capture the form surface


Properties:

BorderColor - Numeric, the RGB value of the border color to drawn to determine the rectangle to be captured

ShowBorder - Logical, determines if the dotted shape borders will appear in the captured image or not


Download link:

LATEST UPDATES

- 2023-04-22 v1.04 - Now instead of trying to bind all the form objects it draws an invisible container on the screen, where the dotted rectangle used for selecting the screen contents is drawn.
This brought the advantage of allowing to select any part of the form, Grids, PageFrames, Textboxes, etc, without the need of Disabling objects. Forms with grids are working fine as well.


2022-05-08

XFRX vs FoxyPreviewer

I felt very honored to know that the VFP guru Rick Schummer presented a session - Visual FoxPro Reporting: XFRX vs. FoxyPreviewer in the 2022 version of VFF - Virtual Fox Fest. The organizers were very generous offering a recorded version of all sessions for free for the community in YouTube.



Rick very quickly and impartially shown some of the main features of both tools. 

Regarding FoxyPreviewer, I have some few considerations or remarks. Of course it would be impossible or Rick to know all the possibilities and features available. I just want to make clear that I feel very thankful for the review. And I am totally aware that the documentation needs some updates, and some points could be better explained, so here I take the opportunity to try to clarify some points.


  • Exporting report to an image file - There are 3 available options:
    - OBJECT TYPE 16 - This is the object type related to exporting to image files. Works exactly the same as the others.
    - OBJECT TYPE 20 - This OBJECT TYPE was not discussed in the presentation. It will choose automatically the ReportListener needed to generate the desired output, according to the file extension passed in the TO FILE clause. The available types are: PDF, RTF, HTML, MHTML, GIF, TIFF, EMF, JPG or PNG.
    REPORT FORM YourReport TO FILE MyImageReport.JPG OBJECT TYPE 20
    - Using the FoxyListener.OutputPage method &&Like regular VFP9
  • The truncated numeric fields in reports - He was very precise in his explanation, but I still would like to add some few information from a FAQ related to this:
When I run my reports with FoxyPreviewer sometimes asterisks symbols ********************* appear instead of the field. This was originally working, before using FoxyPreviewer

That happens because FoxyPreviewer uses the SET REPORTBEHAVIOR 90 mode, that uses GDI+ to render the texts. Unfortunately there is a slight difference of the size of the strings between these modes. To fix it, just edit your report and enlarge that field!

You can set the property - lExpandFields to make the report engine show the field numeric value ignoring the field size.
Using "lExpandFields", FoxyPreviewer retrieves the value that overflowed and resends it to the report engine with an enlarged field width.

This is a known issue, and Lisa Slater Nicholls wrote a short blog post regarding it:
Why do report layouts in VFP9 need wider field/expression controls than in VFP8 and earlier?

And here's another interesting text from Lisa, that explains the reason for that:
With REPORTBEHAVIOR=90, the new report engine uses GDI+ to render output, and text string rendering requires more space than plain old GDI.
The Report Designer uses GDI - not GDI+ - to render the report layout components, including all the text strings that you see. So if you visually right-align a label report element, the report designer records the leftmost co-ordinates of the element (the text start position) in the layout.
The length of the string under GDI+ rendering will most likely be greater than what you would think, based on what you see in the Designer.

  • SET COMPATIBLE ON - Oh, this is a known issue, and I had it fixed before. I just don't know why the fix was not included in the last version. I hope to post an update very soon.
  • ReportPreview.App and ReportOutput.App - As shown by Rick, these files are no longer needed if FoxyPreviewer was elected to be your single ReportEngine. I just feel important to add that if you are used to turn it off, you still need those files to restore the Reporting engine to the default VFP9.
  • Excel bug / Enhancements - Please send me your files and I will be very happy and honored to aply your updates to the main distributable version!
  • lOpenViewer property - In one of your samples Rick was using the property ".lOpenViewer = .T." - That means the generated output file would be opened automatically after generated. But the next REPORT FORM command contained the "TO FILE" and "PREVIEW" clauses. The "PREVIEW" clause means exactly the same - to open the file automatically!
    That's a very interesting usage of FoxyPreviewer. If you want your report to be shown in the default PDF viewer instead of a VFP FORM, just use the command:
    REPORT FORM YourReport OBJECT TYPE 20 TO FILE TempFile.pdf PREVIEW
  • The "PrintingPreferences" - Rick told us he feels some kind of frustration with the fact that the report is closed after you change your report settings in that dialog. But that's exactly what the "PRINTER PROMPT" clause does! From that dialog you have the opportunity to change the printer, copies and other settings and call the printer directly.
  • Rick was asked about embedding the toolbar in the Preview window. As he said, not in v2.99, but docking the toolbar is possible.
  • David Acuña asked about determining the SMTP server values previously. Yes, that's possible. Just set the "cSMTPServer", "nSMTPPort" and other related properties previously, just after FoxyPreviewer was initialized.
  • Maybe I misunderstood the real meaning of Rick's statement when he said that "The configurations are Global, not Per User". In fact, when you start FoxyPreviewer.App it will load the settings from the file "FoxyPreviewerSettings.dbf". This file is automatically generated after the 1st run of Foxy in that folder. Each of your users can have their own Settings Dbf file! You can save a copy of FoxyPreviewerSettings.DBF when your user logs off. Next time, after logging in and before calling FoxyPreviewer.App replace this file with the desired one. So, you can save a settins file for each of your users! When FoxyPreviewer does not find that DBF in its folder it will create a new one.

    Yes, everyone using that APP on that same machine will use those settings, as he mentioned.

    Here are some new thoughts regarding this, using a not very well documented possibility... There is an option to start FoxyPreviewer in a separate folder:

    Immediately after the user logs in your App, and the user is stored as "m.lcUser", people can try the following:

    lcFolder = ADDBS(JUSTPATH(SYS(16)))
    lcUserFolder = lcFolder + "Users\" + m.lcUser && Make sure the folder exists
    DO FOXYPREVIEWER.APP WITH (lcUserFolder)

    This way, every user will easily have his own Settings table. What do you think?


  • Distributing FoxyPreviewer - People just need ONE SINGLE FILE - FoxyPreviewer.App. And there is no need to install it. Just a simple"DO FOXYPREVIEWER.APP" at the beginning of your EXE code and it's done! The recommended is to store it at the same folder of your EXE, and make sure that folder will allow Foxy to create a subfolder and save some custom configuration files.

2021-03-23

Saving a VFP Report at a higher resolution with FoxyPreviewer

VFP9 brought the possibility to save our reports as images, using the ReportListener class, and the OutputPage method:

loListener.OutputPage(lnPage, "\MyReportImage.PNG", 104) && PNG file type


This brings us some useful, but lousy images regarding quality. For instance, the Sample "COLORS.FRX" brings me a 816 x 1056 pixels image - a really poor quality image, if we are thinking of printing or manipulating it further.


But the "OutputPage" method also allows us to draw the report page at any desired image size, by passing a GDI+ Graphics handle instead of the file name widely used.

Here is the working sample - notice that the report engine works only with 96 DPI, so to have better quality, you need to save in bigger dimensions.

Use the function GETREPORTPAGEEX to get your higher resolution reports, here is the parameter list

  • tcFile - The destination image file name
  • toListener - The ReportListener associated with the current report
  • tnPage - The report page number
  • tnEncoder - 100=EMF, 101=TIFF, 102=JPEG, 103=GIF, 104=PNG, 105=BMP
  • tnScale - the scale factor to be applied to the image. 1=Default (low quality), 10=Super high quality
  • tnWidth - The output image width (optional, if using the "tnScale")
  • tnHeight - The output image height (optional, if using "tnScale")


DO FoxyPreviewer.App

LOCAL loListener AS REPORTLISTENER
LOCAL lcFile, lnPage, lnFileType
m.loListener			  = CREATEOBJECT("FoxyListener")
m.loListener.LISTENERTYPE = 3

REPORT FORM (ADDBS(_Samples) + "Solution\Reports\Colors.FRX") OBJECT m.loListener

m.lnFileType = 104 && PNG
	&& 100 - EMF
	&& 101 - TIFF
	&& 102 - JPEG
	&& 103 - GIF
	&& 104 - PNG
	&& 105 - BMP

FOR m.lnPage = 1 TO m.loListener.PAGETOTAL
	m.lcFile = "c:\temp\Test__" + SYS(2015) + "__" + ALLTRIM(STR(m.lnPage)) + ".png"
	GetReportPageEx(m.lcFile, m.loListener, m.lnPage, m.lnFileType, 5) && 5 times bigger image than default
	* For the default lower quality image, use:
	*   loListener.OutputPage(lnPage, "c:\Test" + ALLTRIM(STR(lnPage)) + ".png", lnFileType)
ENDFOR
m.loListener = NULL
RETURN



PROCEDURE GetReportPageEx(tcFile, toListener AS REPORTLISTENER, tnPage, tnEncoder, tnScale, tnWidth, tnHeight)
	LOCAL lhGfx
	*!*	100 - image type EMF
	*!*	101 - image type TIFF
	*!*	102 - image type JPEG
	*!*	103 - image type GIF
	*!*	104 - image type PNG
	*!*	105 - image type BMP
	m.tnEncoder	= EVL(m.tnEncoder, 104) && Default = 104-PNG
	m.tnScale	= EVL(m.tnScale, 1)
	IF EMPTY(m.tnWidth)
		m.tnWidth  = m.toListener.GETPAGEWIDTH()  / 10 * m.tnScale
		m.tnHeight = m.toListener.GETPAGEHEIGHT() / 10 * m.tnScale
	ENDIF

	#DEFINE Gdiplus_PixelFormat_32BppArgb		0x0026200a
	#DEFINE OUTPUTDEVICETYPE_GDIPLUS 			1

	LOCAL loBMP AS GpBitmap OF ADDBS(HOME()) + "/FFC/_GDIPLUS.VCX"
	m.loBMP = NEWOBJECT("GpBitmap", ADDBS(HOME()) + "/FFC/_GDIPLUS.VCX")
	m.loBMP.CREATE(m.tnWidth, m.tnHeight, Gdiplus_PixelFormat_32BppArgb)

	LOCAL loGfx AS GpGraphics OF ADDBS(HOME()) + "/FFC/_GDIPLUS.VCX"
	m.loGfx = NEWOBJECT('GpGraphics', ADDBS(HOME()) + "/FFC/_GDIPLUS.VCX")
	m.loGfx.CreateFromImage(m.loBMP)
	m.lhGfx = m.loGfx.GetHandle()

	m.toListener.OUTPUTPAGE(m.tnPage, m.lhGfx, OUTPUTDEVICETYPE_GDIPLUS, 0, 0, m.tnWidth, m.tnHeight, 0, 0, m.tnWidth, m.tnHeight)
	m.loBMP.SaveToFile(m.tcFile, "image/png")
ENDPROC

2020-11-15

Unicode button icons in Visual FoxPro

A big difficulty foxers have is to update their user interfaces. Since we lost MS support, we need to do almost all UI changes by our own. The Win10 UI today is based in monochrome icons - the ones from the SEGOE UI family - SEGOE UI SYMBOL and SEGOE MDL2 ASSETS. These are true type fonts, that bring tons of icons - the ones that we see all over in Win10.



Unfortunately we can't access those icons directly in VFP, because they use a range higher than the CHR(255) supported by VFP. We still have some options:

1 - Use an ACTIVE-X that supports unicodes

2 - Use "Real Window buttons", that support unicodes - https://github.com/VFPX/Win32API/blob/master/samples/sample_274.md

3 - Get some help from GDI+ - gdiplus.dll and do the drawings for us.


The 3rd option is really nice, but demands a lot, really a lot of work. Fortunately, I did almost all the hard work before, back in 2005, in the GradObjects class, that originally was created to bring gradient backgrounds and buttons to our forms. It recreated every button from the form, and redrawn it to an image file, allowing cool gradient, mouse over and disabled effects.

Having this, I just needed to adapt it, leaving the almost abandoned gradients behind, adding support to unicodes and some adaptations for the mouse over effects.


Here's an updated version of the good and old GRADOBJECTS class, that was intended to generate gradient buttons and backgrounds to our forms back in 2005, in the WinXP times. It's still the same GradObjects, but with some new properties and features. 


The usage is really very simple:

  • Open the GradObjects project
  • Create a form, add some buttons
  • Toss an instance of Gradobjects to your form
  • Set your command button FontName property to "SEGOE MDL2 ASSETS" or any other that you desire.
  • Set the caption property of the button to accept unicodes, by introducing the unicodes between the <UC> </UC> tags, for instance:
          greek <UC>03b5 03b9 03c1 03ae 03bd 03b7</UC> - This will show the word "Peace" in greek characters, in any regular font, like Arial, Tahoma, Segoe UI, etc
          To get the Printer icon from the SEGOE MDL2 ASSETS, set the commandbutton font to it, and add the following to its caption property: "<UC>E749</UC>"


The default "GradObjects" properties will bring you a gradient look, but all you need is to change just 5:

  • BackColor1: Numeric, the RGB of the backcolor
  • BackColor2: Set it to .F. (false), because we don't need gradients here, do we?
  • CaptionForeColor: Numeric, the RGB of the forecolor
  • GradientMode: 0 - We don't need gradients!
  • SelBackColor: Numeric, the RGB of the backcolor when a button is focused or mouse over it
  • SelForeColor: Numeric, the RGB of the forecolor when a button is focused or mouse over it

That's it!

The Unicodes can be obtained directly by the CharMap.EXE or all over the web. Here's an excellent starting point: https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font


For a more detailed information, please refer to the original post for GradObjects: http://vfpimaging.blogspot.com/2006/07/gradient-objects-with-gdi-revisited_48.html



The "GradObjects" object will transform all CommandButtons, Graphical OptionButtons from the same parent object. Use containers, if you need different effects (or none) to some individual controls in your forms.

Start playing with the sample form "TESTUNICODEBTNS.SCX"

 Unicode Buttons Download 


See Also:
Drawing Unicode Texts with GDI+



2018-05-24

FOXYPREVIEWER NEW HOME - www.foxypreviewer.com

As everybody knows, the cool and friendly structure of CodePlex is no longer available, so I decided to create a separate home for it.

From now on, all the releases, documentation, FAQS and more information will be available at www.foxypreviewer.com

Although CodePlex is still available as "ReadOnly", some people had difficulties downloading the latest release and documentation, so some other helpful guys have published some versions of these files. I would like to ask you to remove them, to avoid offering deprecated versions, because that makes it extremely difficult for all of us to provide support for old versions.

I have already a new version with some cool new features ad fixes, and I hope to publish it very soon.

See you at www.foxypreviewer.com !!!

2018-05-11

REPORTLISTENER HEADQUARTERS AND SAMPLES

REPORTLISTENER HQ

REPRODUCED FROM THE CAPTURED VERSION FROM THE WEBARCHIVE
www.reportlistener.com from 2007-08-23



Visual FoxPro 9.0 includes several major improvements to the crusty old Report Writer, making it a powerful, dynamic tool. One the primary ways to extend the capabilities of the Report Writer is through custom Report Listener classes. These classes allow you to hook into the report generation process to customize the appearance of your report. This site is dedicated to the sharing of custom Report Listener classes among the members of the Visual FoxPro community.


Available downloads: 



Converting General fields to Blob fields

 - The new Blob data type in VFP 9 is a General killer--they're much easier to work with than General. Unfortunately, there isn't an easy way to convert the contents of existing General fields into Blob fields; once you've put an image into a General field, it's all but impossible to get it back out. GeneralToBlobListener is a ReportListener subclass that handles this task painlessly.
Last updated: 2005-01-08 
Author: Doug Hennig
Download Converting General fields to Blob fields (Freeware - 7.2K)


HTML Preview with a Navigation Pane

 - Uses a custom ReportListener class and a helper class that work together to generate the output in HTML and GIF files. This HTML file is gererated through an XSL Transformation over a XML document that keeps some metadata of the preview output.
Last updated: 2004-11-03
Author: Fabio Vazquez
Download HTML Preview with a Navigation Pane (Freeware - 6.8K)


Using the GDI+ FFCs to work with output

 - This sample uses the GDI+ foundation classes to change the StringTrimming behavior for the field in the detail band of the report. Note that you have to make one manual change to the report as specified. 
Last updated: 2004-11-02 
Author: Garrett Fitzgerald 
Download Using the GDI+ FFCs to work with output (Freeware - 4.7K)


Font List

 - This code and simple listener generates a report-based list of the fonts on your system. 
Last updated: 2004-11-01 
Author: Garrett Fitzgerald 
Download Font List (Freeware - 1.1K)


QuickFRX2PDF

 - QuickFRX2PDF, this class will allow you to generate PDF files in a really fast and easy way. New version, will generate real PDF Files in a smaller size and faster. Help file included and sample form updated.
Last updated: 2005-10-10 
Author: Luis Navas 
Download QuickFRX2PDF (Commercial - 1MB) 


QuickVFPPdf

 - Taking advantage of GDI+ usage in Visual FoxPro 9 this class generates a PDF Document that will look exactly as your original report. Limitations: All the content of the report will be exported as an image to the PDF document (this will change in future versions). Works only on Visual FoxPro 9 (this will change in future versions).
Last updated: 2005-06-07 
Author: Luis Navas 
Download QuickVFPPdf (Commercial - 1MB) 


Report Preview/Output Engine

 - Report Preview/Output Engine - Written by AMaximum (Erlikh Maksim, Novorossiysk, Russia)
Last updated: 2005-05-04 
Author: Erlikh Maksim 
Download Report Preview/Output Engine (Freeware - 84K)

2016-06-01

Bo Durban - MoxieData Blog - Insert Images into an RTF control using GDIPlusX

Original post by Bo Durban, replicated here because the original blog http://blog.moxiedata.com is not responding.
Copied from:
http://web.archive.org/web/20090106113318/http://blog.moxiedata.com/PermaLink,guid,00a6d6f7-ca4b-4269-9e2d-1093559b3bbe.aspx

Insert Images into an RTF control using GDIPlusX

The RichText control that ships with VFP is very useful for providing a formatted text edit box. While this control does support the displaying of images, there is nothing built in to the control that allows you to insert an image. I have included a function below that will allow you insert an image into the RichText control at the current cursor position.
Just specify the object reference to the RTF control and the fullpath of the image you want to insert. The image can be in any format supported by the GDIPlus library (BMP, JPEG, GIF, TIFF, EMF, PNG, etc...). You can also optionally specify the Width and Height you would like the image to be rendered.
This function requires the GDIPlusX library which can be downloaded from the VFPX  VFPX Project GDIPlusX project at Github.



***********************************************************
* Function: InsertRTFImage
* Author: Bo Durban
*
* Inserts an image into an RTF control at the current cusor position
*
* Parameters:
*   toRTF - specifies an object reference to the RTF control
*   tcImage - secifies the image to insert into the RTF
*   tnWidth - Optional - Specifies the width to use for the image
*   tnHeight - Optional - Specifies the height to use for the image
***********************************************************
FUNCTION InsertRTFImage(toRTF, tcImage, tnWidth, tnHeight)
   LOCAL lcRTF, lcPict, lqData
   LOCAL loImg AS xfcImage
   LOCAL loGfx AS xfcGraphics
   LOCAL loEMF AS xfcMetaFile
   LOCAL lhDC, lhEMF, lnWMFLen
  
   DECLARE Long GetDC IN WIN32API Long
   DECLARE Long ReleaseDC IN WIN32API Long, Long
   DECLARE Long DeleteEnhMetaFile IN WIN32API Long
   DECLARE Long GdipEmfToWmfBits IN GDIPLUS.DLL ;
         Long hemf, Long cbData16, String @pData16, ;
         Integer iMapMode, Integer eFlags
  
   ** Make sure we have initialized the GDIPlusX library
   ** http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX
   DO System.App
  
   lcPict = ""
   WITH _SCREEN.System.Drawing
      loImg = .Image.FromFile(tcImage)
      IF loImg.GetLastStatus() <> 0
         ERROR "Could not open file: "+tcImage
      ELSE
         ** If we didn't specify a width, use the image's width and height
         IF EMPTY(tnWidth)
            tnWidth = loImg.Width
            tnHeight = loImg.Height
         ENDIF
         ** Get the default screen HDC as a reference
         lhDC = GetDC(0)
         ** Create a new metafile
         loEMF = .Imaging.MetaFile.New(lhDC, ;
            .Rectangle.New(0,0,tnWidth,tnHeight), ;
            .Imaging.MetafileFrameUnit.Pixel, ;
            .Imaging.MetafileType.Emf)
         ** We are done with the HDC reference, release it
         ReleaseDC(lhDC, 0)
         ** Get a graphics context for the metafile so we can draw to it
         loGfx = .Graphics.FromImage(loEMF)
         loGFX.SmoothingMode = .Drawing2D.SmoothingMode.HighQuality
         loGFX.InterpolationMode = .Drawing2D.InterpolationMode.HighQualityBicubic
         ** Draw the image
         loGfx.DrawImage(loImg, 0, 0, tnWidth, tnHeight)
         loGfx = NULL
        
         ** Convert the Metafile to a "Windows Metafile".
         ** This is the best format for the RTF control.
         lhEMF = loEMF.GetHenhmetafile()
         lnWMFLen = GdipEmfToWmfBits(lhEMF, 0, NULL, 2, 0)
         lqData = REPLICATE(0h00,lnWMFLen)
         GdipEmfToWmfBits(lhEMF, lnWMFLen, @lqData, 2, 0)
         DeleteEnhMetaFile(lhemf)
         loImg = NULL
        
         ** This is the RTF tags for the image
         lcPict = [{\pict\wmetafile8]+;
                  [\picwgoal]+ALLTRIM(STR(tnWidth*15))+;
                  [\pichgoal]+ALLTRIM(STR(tnHeight*15))+;
                  CHR(13)+CHR(10)+;
                  STRCONV(lqData, 15)+;
                  CHR(13)+CHR(10)+[}]
      ENDIF
   ENDWITH
  
   ** Stuff the image into the RTF control
   toRTF.SelRTF = [{\rtf1\ansi\ansicpg1252\deff0\deflang1033\uc1 ]+lcPict+[}]

   RETURN
ENDFUNC

Bo Durban - Moxiedata Blog - Blending Two Images Using GDIPlusX

Original post by Bo Durban, replicated here because the original blog http://blog.moxiedata.com is not responding.
Copied from:
http://web.archive.org/web/20101017154139/http://blog.moxiedata.com/PermaLink,guid,7876146a-96e0-47dd-b442-271cad494a5d.aspx



Blending Two Images Using GDIPlusX

After seeing a post on the Micrsoft forums. I set out to try and solve how to blend two images using GDI+. I could find little information on the web on how to solve this particular problem, so I came up with my own technique (with some excellent help from Craig Boyd).
Here is a sample blended image and the VFP / GDIPlusX code that I used to create it.


Paste this code into a PRG and run it. This code requires the GDIPlusX library from VFPX.


Local lcPict1, lcPict2

m.lcPict1 = Getpict()
If File(m.lcPict1)
   m.lcPict2 = Getpict()
   If File(m.lcPict2)
      ImageAlphaBlend(m.lcPict1, m.lcPict2)
   Endif
Endif

**********************************************************
Function ImageAlphaBlend(tcPictLeft, tcPictRight)
**********************************************************
* Author: Bo Durban *

   Local loColorMatrix As xfcCOlorMatrix
   Local loImageLeft As xfcImage
   Local loImageRight As xfcImage
   Local loBitmapPart As xfcBitmap
   Local loBitmapLeft As xfcBitmap
   Local laImageAttribs[1]
   Local loGfxLeft As xfcGraphics
   Local loGfxPart As xfcGraphics
   Local loGfxScreen As xfcGraphics
   Local lnAlphaSteps, lnBlendPercentage, lnWidthOpaque, lnStep, lnHeightImage, lnLeftStart

** Sets the number of Alpha blend steps used to render the blend.
** The max is 256. lower steps equals lower quality, but higher speed
   m.lnAlphaSteps = 128
** Sets the percentage of the image that is blended
   m.lnPercentageBlend = .75

   Dimension laImageAttribs[m.lnAlphaSteps]

** Requires the GDIPlusX library (version 1.20 beta)
** http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15083
   Do (Locfile("SYSTEM.APP"))
   With _Screen.System.Drawing

      m.loImageRight = .Image.FromFile(m.tcPictLeft)
      m.loImageLeft = .Image.FromFile(m.tcPictRight)

** Force the left image to be the same size as the right image
      m.loBitmapLeft = .Bitmap.New(m.loImageRight.Width, m.loImageRight.Height)
      m.loGfxLeft=.Graphics.FromImage(m.loBitmapLeft)
      m.loGfxLeft.Clear(.Color.Transparent)
      m.loGfxLeft.DrawImage(m.loImageLeft,0,0,m.loBitmapLeft.Width,m.loBitmapLeft.Height)

      m.lnWidthOpaque = m.loImageRight.Width * (1 - m.lnPercentageBlend) / 2
      m.lnWidthPart = Ceiling((m.loBitmapLeft.Width-m.lnWidthOpaque*2)/m.lnAlphaSteps)
      m.loBitmapPart = .Bitmap.New(m.lnWidthPart, m.loBitmapLeft.Height)
      m.loGfxPart=.Graphics.FromImage(m.loBitmapPart)
      m.loGfxPart.Clear(.Color.Transparent)

** Pre-fill ImageAttributes with Alpha ColorMatrix blend for performance
** The biggest advantage to doing this is if you were processing multiple
** set of images at a time, which we aren't doing here.
      m.loColorMatrix=.Imaging.ColorMatrix.New()

      For m.lnCurrentStep = 1 To m.lnAlphaSteps
         laImageAttribs[m.lnCurrentStep] = .Imaging.ImageAttributes.New()
         m.loColorMatrix.Matrix33 = m.lnCurrentStep/m.lnAlphaSteps
         laImageAttribs[m.lnCurrentStep].SetColorMatrix(m.loColorMatrix)
      Endfor

** Adjust these for preferred image quality vs. speed
*m.loGfxLeft.InterpolationMode = .Drawing2D.InterpolationMode.Default
*m.loGfxLeft.CompositingQuality = .Drawing2D.CompositingQuality.Default
*m.loGfxLeft.SmoothingMode = .Drawing2D.SmoothingMode.Default

** Use integers instead of floats for performance
      m.loGfxLeft.UsePrecision = .F.
** Minor speed increase accessing this property once
      m.lnHeightImage = m.loImageRight.Height

      For m.lnCurrentStep = 1 To m.lnAlphaSteps
         m.lnLeftStart = m.lnCurrentStep*m.lnWidthPart + m.lnWidthOpaque

** Draw partial right image to part
         m.loGfxPart.DrawImage(m.loImageRight, ;
            0,0,m.lnWidthPart,m.lnHeightImage, ;
            m.lnLeftStart,0,m.lnWidthPart,m.lnHeightImage, ;
            .GraphicsUnit.Pixel)

** Draw part to left image with Alpha blend
         m.loGfxLeft.DrawImage(m.loBitmapPart, ;
            m.lnLeftStart,0,m.lnWidthPart,m.lnHeightImage, ;
            0,0,m.lnWidthPart,m.lnHeightImage, ;
            .GraphicsUnit.Pixel, ;
            laImageAttribs[m.lnCurrentStep])

      Endfor

** Draw last opaque part of right image
      m.loGfxLeft.DrawImage(m.loImageRight, ;
         m.loImageRight.Width-m.lnWidthOpaque, 0, m.lnWidthOpaque, m.lnHeightImage, ;
         m.loImageRight.Width-m.lnWidthOpaque, 0, m.lnWidthOpaque, m.lnHeightImage, ;
         .GraphicsUnit.Pixel)

** Render to the screen
      m.loGfxScreen = .Graphics.FromHWnd(_Screen.HWnd)
      m.loGfxScreen.Clear(.Color.White)
      m.loGfxScreen.DrawImage(m.loBitmapLeft,0,0,1024,768)

** Or you can save it to a file
**m.loBitmapLeft.Save("MyBlendedImage.png")

   Endwith

   Return
Endfunc

Bo Durban - Moxiedata Blog - Display the Print Dialog Using PrintDlgEx

Original post by Bo Durban, replicated here because the original blog http://blog.moxiedata.com is not responding.
Copied from:
http://web.archive.org/web/20101017154139/http://blog.moxiedata.com/PermaLink,guid,7876146a-96e0-47dd-b442-271cad494a5d.aspx


Display the Print Dialog Using PrintDlgEx

As I mentioned in my post from 9/29/2008, Microsoft removed the Printer button from the "Page Setup" dialog in Vista. It was reccommneded to use the "Print" dialog to change printer preferences. However, the "Print" dialog option is not always available on the menu, and there is no simple call to activate the dialog.
In my post from 9/29, I provided code for displaying the DocumentProperties dialog. This populates a DEVMODE structure from the Advanced Properties dialog for a specific printer. In today's post, I provide sample code for displaying the Print dialog using the PrintDlgEx API function. This is the dialog Microsoft recommendeds for setting printer options in Vista. This dialog populates a DEVMODE structure also, however, it includes the ability to select a printer and specify a print range too.

Paste this code into a PRG and run it. It will display user chosen options to the screen.
While this dialog is meant to replace missing functionality from SYS(1037) in Vista, this sample does not update your user preferences. You will need to update those based on the user action (see "Action" in the code below).
Note that the PrintDlgEx API function works with Windows 2000 and later.


** Converted from: http://msdn.microsoft.com/en-us/library/ms646829.aspx
** AUTHOR: BO DURBAN** 

#Define SIZEOF_PRINTDLGEX     84
#Define SIZEOF_PRINTPAGERANGE  8

** nFlag options
#Define PD_ALLPAGES                  0x00000000
#Define PD_SELECTION                 0x00000001
#Define PD_PAGENUMS                  0x00000002
#Define PD_NOSELECTION               0x00000004
#Define PD_NOPAGENUMS                0x00000008
#Define PD_COLLATE                   0x00000010
#Define PD_PRINTTOFILE               0x00000020
#Define PD_PRINTSETUP                0x00000040
#Define PD_NOWARNING                 0x00000080
#Define PD_RETURNDC                  0x00000100
#Define PD_RETURNIC                  0x00000200
#Define PD_RETURNDEFAULT             0x00000400
#Define PD_SHOWHELP                  0x00000800
#Define PD_USEDEVMODECOPIES          0x00040000
#Define PD_USEDEVMODECOPIESANDCOLLATE 0x00040000
#Define PD_DISABLEPRINTTOFILE        0x00080000
#Define PD_HIDEPRINTTOFILE           0x00100000
#Define PD_NONETWORKBUTTON           0x00200000
#Define PD_CURRENTPAGE               0x00400000
#Define PD_NOCURRENTPAGE             0x00800000

#Define START_PAGE_GENERAL    Bitlshift(0xffffffff,0)
#Define GMEM_FIXED       0x00
#Define GMEM_ZEROINIT    0x40
#Define GPTR             (GMEM_FIXED+GMEM_ZEROINIT)
#Define DM_OUT_BUFFER  2
#Define DM_IN_PROMPT   4
#Define CCHDEVICENAME 32
#Define CCHFORMNAME   32
#Define PD_RESULT_CANCEL               0
#Define PD_RESULT_PRINT                1
#Define PD_RESULT_APPLY                2

Declare Long GlobalAlloc In WIN32API Long uFlags, Long uBytes
Declare Long GlobalLock In WIN32API Long Hmem
Declare Long GlobalUnlock In WIN32API Long Hmem
Declare Long GlobalFree In WIN32API Long Hmem
Declare Integer PrintDlg In comdlg32.Dll Long lppd
Declare Integer PrintDlgEx In comdlg32.Dll Long lppd
Declare Long DeleteDC In WIN32API Long hdc

Local hPRINTDLG, hPageRanges, hdc, hResult, nFlagsm, hResult
Local hGDevMode, hGDevNames, nPageRange, hPageRange, lnAction
Local lcDeviceName, lcFormName, hDevMode, hDevNames

** Allocate memory for the PRINTDLGEX structure
hPRINTDLG = GlobalAlloc(GPTR,SIZEOF_PRINTDLGEX)
** Allocate memory for 10x PRINTPAGERANGE structures
hPageRanges = GlobalAlloc(GPTR,SIZEOF_PRINTPAGERANGE*10)
hdc = 0
hResult = 0

** Initialize the PRINTPAGERANGE structure
nFlags = Bitor(PD_RETURNDC,PD_ALLPAGES)
Sys(2600,hPageRanges,8,BinToC(1,"4rs")+BinToC(1,"4rs"))

** Initialize the PRINTDLGEX structure
Sys(2600,hPRINTDLG+ 0,4,BinToC(SIZEOF_PRINTDLGEX,"4rs")) && lStructSize
Sys(2600,hPRINTDLG+ 4,4,BinToC(_vfp.HWnd,"4rs"))         && hwndOwner
Sys(2600,hPRINTDLG+20,4,BinToC(nFlags,"4rs"))            && Flags
Sys(2600,hPRINTDLG+32,4,BinToC(0,"4rs"))                 && nPageRanges
Sys(2600,hPRINTDLG+36,4,BinToC(10,"4rs"))                && nMaxPageRanges
Sys(2600,hPRINTDLG+40,4,BinToC(hPageRanges,"4rs"))       && lpPageRanges
Sys(2600,hPRINTDLG+44,4,BinToC(1,"4rs"))                 && nMinPage
Sys(2600,hPRINTDLG+48,4,BinToC(1000,"4rs"))              && nMaxPage
Sys(2600,hPRINTDLG+52,4,BinToC(1,"4rs"))                 && nCopies
Sys(2600,hPRINTDLG+76,4,BinToC(START_PAGE_GENERAL,"4rs")) && nStartPage

** Display the Print dialog
hResult = PrintDlgEx(hPRINTDLG)

** Pull updated values from PRINTDLGEX structure
hGDevMode = CToBin(Sys(2600,hPRINTDLG+8,4),"4rs")
hGDevNames = CToBin(Sys(2600,hPRINTDLG+12,4),"4rs")
hdc = CToBin(Sys(2600,hPRINTDLG+16,4),"4rs")
nFlags = CToBin(Sys(2600,hPRINTDLG+20,4),"4rs")
lnAction = CToBin(Sys(2600,hPRINTDLG+80,4),"4rs")

If hResult = 0
** Lock movable memory
   hDevMode = GlobalLock(hGDevMode)
   hDevNames = GlobalLock(hGDevNames)

** Display Action taken by user
   Do Case
      Case lnAction = PD_RESULT_CANCEL
         ?"Action: CANCEL"
      Case lnAction = PD_RESULT_PRINT
         ?"Action: PRINT"
      Case lnAction = PD_RESULT_APPLY
         ?"Action: APPLY"
   Endcase

** Display print range selection
   Do Case
      Case lnAction != PD_RESULT_PRINT
** No Printing
      Case Bitand(nFlags,PD_SELECTION)=PD_SELECTION
         ?" Selection"
      Case Bitand(nFlags,PD_CURRENTPAGE)=PD_CURRENTPAGE
         ?" Current Page"
      Case Bitand(nFlags,PD_PAGENUMS)=PD_PAGENUMS
         ?" Page Ranges"
         nPageRanges = CToBin(Sys(2600,hPRINTDLG+32,4),"4rs")
         For nPageRange = 0 To nPageRanges-1
            hPageRange = hPageRanges+(nPageRange*SIZEOF_PRINTPAGERANGE)
            nFrom = CToBin(Sys(2600,hPageRange,4),"4rs")
            nTo = CToBin(Sys(2600,hPageRange+4,4),"4rs")
            ?"   From: "+Transform(nFrom)+" To: "+Transform(nTo)
         Endfor
      Otherwise
         ?" All Pages"
   Endcase


** Display the DEVMODE structure, showing printing preferences
   If hDevMode <> 0
      ?"DEVMODE:"
** DEVMODE: http://msdn2.microsoft.com/en-us/library/ms535771.aspx
      lcDeviceName = Sys(2600,hDevMode+0,CCHDEVICENAME)
      lcDeviceName = " "+Left(lcDeviceName, At(0h00,lcDeviceName)-1)
      ?" Device Name: ",   lcDeviceName
      ?" Orientation: ",   CToBin(Sys(2600,hDevMode+44,2),"2rs")
      ?" Paper Size: ",    CToBin(Sys(2600,hDevMode+46,2),"2rs")
      ?" Paper Length: ",  CToBin(Sys(2600,hDevMode+48,2),"2rs")
      ?" Paper Width: ",   CToBin(Sys(2600,hDevMode+50,2),"2rs")
      ?" Paper Scale: ",   CToBin(Sys(2600,hDevMode+52,2),"2rs")
      ?" Paper Copies: ",  CToBin(Sys(2600,hDevMode+54,2),"2rs")
      ?" Default Source: ",CToBin(Sys(2600,hDevMode+56,2),"2rs")
      ?" Print Qualilty: ",CToBin(Sys(2600,hDevMode+58,2),"2rs")
      ?" Color: ",         CToBin(Sys(2600,hDevMode+60,2),"2rs")
      ?" Duplex: ",        CToBin(Sys(2600,hDevMode+62,2),"2rs")
      ?" Y Resolution: ",  CToBin(Sys(2600,hDevMode+64,2),"2rs")
      ?" TT Option: ",     CToBin(Sys(2600,hDevMode+66,2),"2rs")
      ?" Collate: ",       CToBin(Sys(2600,hDevMode+68,2),"2rs")
      lcFormName = Sys(2600,hDevMode+70,CCHFORMNAME)
      lcFormName = " "+Left(lcFormName, At(0h00,lcFormName)-1)
      ?" Form Name: ",      lcFormName
      ?" LogPixels: ",      CToBin(Sys(2600,hDevMode+102,2),"2rs")
      ?" BitsPerPixel: ",   CToBin(Sys(2600,hDevMode+104,2),"2rs")
      ?
   Endif

** Unlock movable memory
   GlobalUnlock(hGDevMode)
   GlobalUnlock(hGDevNames)
Else
   ?"ERROR: "+Transform(hResult,"@0")
Endif

** Clean up allocated memory
If hGDevMode <> 0
   GlobalFree(hGDevMode)
Endif
If hGDevNames <> 0
   GlobalFree(hGDevNames)
Endif
GlobalFree(hPageRanges)
GlobalFree(hPRINTDLG)
If hdc <> 0
   DeleteDC(hdc)
Endif
Return