|
|
-
Cropping an image is super simple using GdiPlusX
Prerequisites Visual FoxPro 9 and the GdiPlusX library from VFPX
Please make sure that you have the latest version, because this sample may be using some functions that were added or fixed recently. http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
The cropping is done by the fuction "Clone()" from the Bitmap class. All we need is to pass a Rectangle object containing the X, Y, Width and Height of the desired image to be cropped.
Original Image 
Top Left 
Center 
Bottom Right 
Run the code below, selecting any image, and you will see the image cropped in three ways: the top-left part of the image, the bottom-right part, and the center.
LOCAL lcSource, lnWidth, lnHeight lcSource = GETPICT() IF EMPTY(lcSource) RETURN ENDIF
DO LOCFILE("System.App")
WITH _SCREEN.System.Drawing * Load Image to GdiplusX LOCAL loBmp AS xfcBitmap loBmp = .Bitmap.FromFile(lcSource) lnWidth = loBmp.Width lnHeight = loBmp.Height
* Crop Image LOCAL loCropped AS xfcBitmap
* Crop Top-Left LOCAL loRect as xfcRectangle loRect = .Rectangle.New(0, 0, lnWidth / 2, lnHeight /2) loCropped = loBmp.Clone(loRect) loCropped.Save("c:\Crop-TopLeft.png", .Imaging.ImageFormat.Png) RUN /N explorer.EXE c:\Crop-TopLeft.png * Crop Bottom-Right * Now, the Rectangle region will be created inside the Clone function loCropped = loBmp.Clone(.Rectangle.New(lnWidth / 2, lnHeight /2, lnWidth /2, lnHeight /2)) loCropped.Save("c:\Crop-BottomRight.png", .Imaging.ImageFormat.Png) RUN /N explorer.EXE c:\Crop-bottomright.png
* Crop Center loCropped = loBmp.Clone(.Rectangle.New(lnWidth / 4, lnHeight /4, lnWidth /2, lnHeight /2)) loCropped.Save("c:\Crop-Center.png", .Imaging.ImageFormat.Png) RUN /N explorer.EXE c:\Crop-Center.png
ENDWITH RETURN
|
-
-
I'm happy to announce that FoxCharts has recently been accepted as a VFPX project.
Today I've just uploaded to VFPX at CodePlex a new version of FoxCharts. This is version 0.14 - still ALPHA - NOT FOR PRODUCTION !
Prerequisites: Visual FoxPro 9 and the GdiPlusX library from VFPX
First of all I have to thank you all for your kind comments and feedback you provided in my last post. I had never expected to receive so many comments, in this blog, at the other VFP forums and by email. I really apreciated that. Be sure that your feedback resulted in a superpowered motivation to improve it.
It is also important to tell everybody of the importance that both Bo Durban and Craig Boyd have in this project. They are the menthors and fathers of GdiPlusX. Without GdiPlusX this project would become almost impossible. If I had to use any other of the Gdi+ classes available for VFP, for sure it would have taken much more time - Believe-me, I've tried them all.
Using GdiPlusX I can be indeed much more productive. Once you understand how it works, things become really easy and simple.
At first sight, when I saw one of the first versions that Bo and Craig designed for GdiPlusX I was really amazed, and I said to myself - I have to go deeper into this.
Bo Durban has also provided important help, providing important suggestions, support and testing. Thanks also to EmersonReed, Luis Maria Guayan and Leandro Walfrans for your tips and support.
This version also distributes the two main files from GdiPlusX - System.app and GdiPlusX.vcx. If you are already a GdiPlusX user, you can use your own GdiPlusX version. Just make sure to be using the latest version.
This new release contains lots of enhancements:
Chart Types - Bar charts - Multiple bars - Stacked bars
- Pie - Doughnut
- Lines - Area - Points and Shapes
Color variations: - Basic colors - Custom colors - Gradient colors - Random colors - Monochrome - Gradient or solid colors
Legends in many places: Axys, shapes, side legends
Scales - automatic or customized
Customize: - Titles - Subtitles - Backgrounds (solid or gradient) - Fonts - Colors
The sample form shows most of the features that are available. Run the form "ChartsSample.scx" and play changing the various properties, generating some cool charts like the ones below.

All the relevant codes are in the INIT() event of the sample form. With very few lines of code you can create super cool and beautiful charts.
This sample also includes a report sample. Check the codes in the command button that generates a report to see one of the various ways we have to print our charts.

Important to remember that this is still an ALPHA version, and is not recommended to be used in production although it works nice.
Some important improvements still need to be applied, specially in the class initialization. The codes also need to be optimized. My priority was in obtaining the results, and in many places the performance can be improved.
If you have any tips, or can provide suggestions, or fixes, you are most welcome !
Enjoy !
Download the latest version directly from the FoxCharts page on VFPX:
http://www.codeplex.com/VFPX/Wiki/View.aspx?title=FoxCharts&referringTitle=Home
The page for the latest release 0.14 Alpha:
http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=12847


Here are the properties that are currently provided in FoxCharts, that you can use to improve your charts:
| SourceAlias |
Character, the name of the alias that contains the needed fields that will create the chart |
| FieldValue1 |
Character, the field name of the cursor that contains the numeric values that contain the values that will create the chart. |
| FieldColor |
Character, the field name of the cursor that contains the RGB values of the custom colors for the chart |
| FieldDetachSlice |
Character, the field name of the cursor that contains the logical values that tell if the slice of the Pie or Donut chart will be detached or not |
| FieldHideSlice |
Character, the field name of the cursor that contains the logical values that tell if the slice of the Pie or Donut chart will be hidden or not |
| FieldLegend |
Character, the field name of the cursor that contains the character values that contain the main legends of the Pie or Donut charts |
| FieldLegend2 |
Character, the field name of the cursor that contains the character values that contain the secondary legends of the chart that will be drawn inside the slice, or point or bar. |
| FieldXAxys |
Character, the name of the field that contains the text to be drawn in the X axys |
|
|
| Color1 |
Numeric, the RGB value of the color from the first chart |
| Legend1 |
Character, the Legend text for the first sequence of values |
|
|
| ChartType |
Numeric, type of chart: 1 = Pie ; 2 = Donut ; 3 = Unspecified ; 4 = Point ; 5 = Line ; 6 = Area ; 7 = Simple Bar ; 8 = Multiple Bars ; 9 = Stacked Bars |
| ChartsCount |
Numeric, the number of Value sources |
|
|
| FontName |
Character, the name of the font to be used to display text |
|
|
| TitleFontSize |
Numeric, the font size for the main title |
| TitleCaption |
Character, the title caption |
| TitleForeColor |
Numeric, the title and subtitle forecolor RGB value |
| SubTitleCaption |
Character, the subtitle caption |
| SubTitleFontSize |
Numeric, the subtitle font size |
|
|
| ShowLegend |
Logical, Shows the side legends |
| LegendFontSize |
Numeric, the fontsize for the side legends |
| LegendForeColor |
Numeric, the legend fore color RGB value |
|
|
| ShowValuesonShapes |
Logical, determines if the values will be drawn inside the shapes of the chart |
| LegendOnShapeColor |
Numeric, the RGB value for the shape color |
| LegendOnShapeFontSize |
Numeric, the font size for legends on shape |
|
|
| ShowAxys |
Logical, for Line, Area or Point charts - determines if the X and Y axys will be drawn |
| AxysXCaption |
Character, the main text for the X axys |
| AxysYCaption |
Character, the main text for the Y axys |
| AxysColor |
Numeric, the RGB value for the Axys main color |
|
|
| BackColor |
Numeric, RGB value of the main backcolor |
| BackColor2 |
Numeric, RGB value of the secondary (destination) backcolor. This is used to create gradients, together with "BackColor" |
| BackGradientMode |
Numeric, if gradient background (having BackColor2 specified) - 0 - horizontal; 1 - vertical; 2 - diagonal1 ; 3 - diagonal 2 |
|
|
| ShowScale |
Logical, determines if the scale in the Y axys will be shown |
| Scale |
Numeric, the scale value for the Y axys; 0 = Automatic scale |
| ScaleBackType |
Numeric, the background scale type; 0 = none; 1 = lines; 2 = rectangle |
|
|
| ColorType |
Numeric, the type of colors of the chart: 0 = Basic Colors 1 = Custom (default) 2 = Random 3 = Scale of Gradients |
| BrushType |
Numeric, type of brush used to fill the chart: 1 - Solid Colors; 2 - Gradient Colors; 3 - Monochrome Hatch brush |
| GradientLevel |
Numeric, for gradient brush mode (-10 = destination black; 0 = solid color; +10 destination white) |
| AlphaChannel |
Numeric, 0-255 Determines the level of the transparency level; 255 = Opaque; 0 = transparent |
| _3D |
Numeric, the quantity of pixels that create the 3D effect (0 = plain) |
|
|
| Margin |
Numeric, specifies the margin width created in the text portion of the control. |
| DonutRatio |
Numeric, For Donut chart - the width of the donut related to its size ( 0.01 = full slice ; 0.99 = thin) |
| LineCaps |
Logical, for the case of plain line chart, shows rounded caps in each point. |
| LineShape |
|
| PointsShape |
Numeric, the shape to be used in a points chart: 0 = Round; 1 = Square; 2 = Triangle; 3 = Cross; 4 = Star; 5 = Man; 98 = GDI+X Path object; 99 = Custom Image |
| PointsShapeWidth |
Numeric, for Point chart, determines the width of the pen that will draw the shapes |
| PieDetachPixels |
Numeric, for Pie and Donut charts, the quantity of pixels to detach from center |
| BarsSpaceBetween |
Numeric, for bars chart - the distance in pixels between bars |
| Area3DTop |
Logical, when true, a line will be drawn on the top of the 3D Area chat |
|
|
| MultiChart |
Logical, determines if more than one kind of chart will run at the same time |
|
-
Till now I had seen many samples showing how we can make the Print button invisible from the Report Preview toolbar, but I had never seen the possibility to show it disabled. Here's a sample, totally based in Emerson Reed's, from an old post in his great blog: A sample on how to add features to Report Listener - http://weblogs.foxite.com/emersonreed/archive/2006/09/13/A_sample_on_how_to_add_features_to_Report_Listener.aspx
It brings the possibility to hide completely the Print button or to disable it - just set the properties "PrintButtonVisible" and "PrintButtonEnabled". Apart from this, it also allows to change the tooltips from the buttons. For my case this is really helpful, in order to have the translated tooltips to my native language.
I've only added 7 or 8 lines of code all the sample comes from Emerson. It was tricky to set the "enabled" property of the print button, because there's no property that allows us to set this, differently from the "Visible", that was allowed, using the property "AllowPrintfromPreview". Even setting the property "Enabled" directly in the ExtensionHandler class below, the button still appeared enabled.
.cmdPrint.Enabled = .F. && Did not work
My solution was to use BINDEVENT, in order to control the behavior whenever the report previewer tried to change the "Enabled" property:
BINDEVENT(THIS.PreviewForm.Toolbar.CmdPrint,"Enabled",This,"Disabled",1) Then, I added a custom function "Disabled", that forces the Print button to appear disabled: PROCEDURE Disabled THIS.PreviewForm.Toolbar.cmdPrint.Enabled = .F. ENDPROC
* See "Leveraging the default preview container" topic in HELP for more info * Report Listener based on Emerson Reed's sample from * http://weblogs.foxite.com/emersonreed/archive/2006/09/13/A_sample_on_how_to_add_features_to_Report_Listener.aspx
* Create a Report Listener object Local loReportListener loReportListener = Newobject("MyReportListener") With loReportListener .ListenerType = 1 && Preview .PrintButtonVisible = .T. .PrintButtonEnabled = .F. Endwith * Run a report from the samples of VFP using the new report engine (object-assisted output) REPORT FORM ; HOME() + 'Samples\Solution\Reports\colors.frx' ; OBJECT loReportListener RETURN * Custom Report Listener that adds some features Define Class MyReportListener As FXLISTENER Of Addbs(Home()) + "FFC\_ReportListener.VCX"
* Public properties PrintButtonVisible = .T. PrintButtonEnabled = .T. * Procedure LoadReport DoDefault() With This If .ListenerType==1 And Not Vartype(.PreviewContainer)=="O" .ExtendPreviewContainer() Endif Endwith Endproc * Function ExtendPreviewContainer Local loPreviewContainer loPreviewContainer = Null Do (_ReportPreview) With loPreviewContainer loPreviewContainer.AllowPrintfromPreview = This.PrintButtonVisible
LOCAL loExtHandler loExtHandler = CREATEOBJECT("MyExtensionHandler") loExtHandler.DisablePrintButton = NOT This.PrintButtonEnabled
loPreviewContainer.SetExtensionHandler(loExtHandler) This.PreviewContainer = loPreviewContainer Endfunc Enddefine
* Create a class that will extend Report Preview Define Class MyExtensionHandler As Custom DisablePrintButton = .F.
Procedure Show(iStyle) With This.PreviewForm With .Toolbar * Translate toolbar buttons ToolTips to Brazilian Portuguese language .cboZoom.ToolTipText = "Zoom" .cmdClose.ToolTipText = "Fechar a visualização" .cmdGoToPage.ToolTipText = "Ir para a página" .cmdPrint.ToolTipText = "Imprimir" IF This.DisablePrintButton * BINDEVENT(THIS.PreviewForm.Toolbar.CmdPrint, "Visible", This, "Invisible", 1)
* Here we control the ENABLED property BINDEVENT(THIS.PreviewForm.Toolbar.CmdPrint, "Enabled", This, "Disabled", 1) ENDIF
With .cntNext .cmdBottom.ToolTipText = "Última página" .cmdForward.ToolTipText = "Próxima página" Endwith
With .cntPrev .cmdBack.ToolTipText = "Página anterior" .cmdTop.ToolTipText = "Primeira página" Endwith
With .opgPageCount .opt1.ToolTipText = "Uma página" .opt2.ToolTipText = "Duas páginas" .opt3.ToolTipText = "Quatro páginas" Endwith * Endwith .WindowState = 2 && Maximize report preview Endwith DoDefault(iStyle)
ENDPROC
* Here is the relevant code to disable the button PROCEDURE Disabled THIS.PreviewForm.Toolbar.cmdPrint.Enabled = .F. ENDPROC * Enddefine
|
-
Wanna create some cool charts in VFP ?
With no ActiveX controls, dlls, or 3rd party products ?
What do you think of these ?




Recently, I’ve seen many discussions about people asking for charts components. Since GdiPlusX brings us all these possibilities, I thought it would be worth to start a project regarding this.
FoxCharts is a subclass of the ImageCanvas class from GdiPlusX, that allows us to direct draw in an image object, among many other cool and useful features, that are not in the scope of this post.
Goals of FoxCharts: - Create good looking and modern charts in pure VFP - NO ActiveX components - Easy to setup - Easy to customize. - Easy to save to disk or print - Open Source - Benefit from all the GdiPlusX drawing capabilities, allowing users to modify the charts the way they like. - Save as EMF, resulting in perfect charts when printed in VFP reports
Prerequisites: Visual FoxPro 9 and the GdiPlusX library from VFPX
In the source code you'll find a sample form, “NewChart.Scx” that allows to create different kinds of charts using this class.
Please note that as it is still in Alpha version, the codes that create the charts are still in the sample form. GpCharts.vcx is (at this moment) just a holder that contains the PEMs needed to draw. In development mode, double click the ImageCanvas object to see the source code that generates these charts.
The codes that will instantiate GpCharts reside in the INIT() event of the sample form, only there.
Currently available: Bars, Lines, Area, Pie and Donut charts, in various color variations, using gradients, custom colors, basic and random colors. Titles, subtitles and legends
To do: Enhance the data filling, create a builder, allow different kinds of charts to appear together (eg. Lines and bars). Legends in the Y and X axys.
And obviously: Fix some bugs !
If you are interested in developing and enhancing FoxCharts, feel free to post a comment here. Your suggestions, tips, critics, testing and bugs hunting will be most appreciated !
Download directly from the FoxCharts page in VFPX
http://www.codeplex.com/VFPX/Wiki/View.aspx?title=FoxCharts&referringTitle=Home
|
-
-
Recently MVP Cetin Basoz posted a great script that generates an excellent color picker. This is so good and useful, that I added it to my "Tools" menu during development.
Thanks Cetin !
If you're interested, you can download it from here:
http://www.foxite.com/downloads/default.aspx?id=179
|
-
Below are 4 simple ways to convert a BMP to ICON, using GdiPlusX. Those 2 blog posts were before we updated the library, adding the support for saving Icons with good quality.
This sample uses 4 techniques, and creates 4 versions of ICONS from the same image file. Before the conversion, it resizes the source image to the size of 16x16. This means that with this sample you can convert any image to ICO file.
In the next release, we hope to deliver a complete solution for .ICO files too, with very simplified code, offering great ICO files support, that is not present in the .NET version, thanks to Carlos Alloatti.
IMPORTANT Requires VFP9 and GdiPlusX to run. Please make sure that you have the latest version, because this sample may be using some functions that were added or fixed recently. http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
Do Locfile("system.prg")
With _Screen.System.Drawing As xfcDrawing * Convert the original bitmap to ensure better quality and compatibility loResized = .Bitmap.New(.Bitmap.FromFile(Getpict()), 16,16)
* Create Icon Object Local loIcon As xfcIcon loIcon = .Icon.FromHandle(loResized.GetHicon())
*** LOW QUALITY ICONS
* Save sending FileName loIcon.Save("c:\Icon_Save_FileName_LowQual.ico")
* Save Using Stream Local loStream As xfcMemoryStream loStream = _Screen.System.IO.MemoryStream.New()
loIcon.Save(loStream) Strtofile(loStream.GetBuffer(), "c:\Icon_Save_Stream_LowQual.Ico")
*** HIGH QUALITY ICONS *** Setting the tlQuality flag to .T.
* Save sending FileName loIcon.Save("c:\Icon_Save_FileName_HighQual.ico", .T.)
* Save Using Stream Local loStream2 As xfcMemoryStream loStream2 = _Screen.System.IO.MemoryStream.New()
loIcon.Save(loStream2, .T.) Strtofile(loStream2.GetBuffer(), "c:\Icon_Save_Stream_HighQual.Ico")
Endwith
|
-
UPDATED: Fixed Image Size, Thanks to Christof Wollenhaupt
More than once I've seen people asking to create images containing some text. The sample below is really very simple.
- Creates a font
- Measures the space that the text will need
- Creates an image with the needed size
- Draws the string
- Saves to disk
IMPORTANT Requires VFP9 and GdiPlusX to run. Please make sure that you have the latest version, because this sample may be using some functions that were added or fixed recently. http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
DO LOCFILE ("System.prg")
WITH _SCREEN.System.Drawing LOCAL lcText lcText = "GdiPlusX is Cool !!!"
* Create a Font LOCAL loFont as xfcFont loFont = _screen.system.Drawing.Font.New("Verdana", 32, .FontStyle.BoldItalic)
LOCAL loTmpBmp as xfcBitmap loTmpBmp = .Bitmap.New(1,1)
* Retrieve the graphics object. LOCAL loTmpGfx AS xfcGraphics loTmpGfx = .Graphics.FromImage(loTmpBmp)
* Measure the String * Get the size required for our text LOCAL loSize as xfcSize loSize = loTmpGfx.MeasureString(lcText, loFont)
LOCAL loNewBmp as xfcBitmap loNewBmp = .Bitmap.New(loSize.Ceiling)
LOCAL loNewGfx as xfcGraphics loNewGfx = .Graphics.FromImage(loNewBmp)
* Clear the background to Yellow loNewGfx.Clear(.Color.Yellow)
* Create a solid brush LOCAL loBrush as xfcSolidBrush loBrush = .SolidBrush.New(.Color.FromRGB(255,0,0)) && Red
* Create an StringFormat object in order to draw the sting centered in the image LOCAL loStringFmt as xfcStringFormat loStringFmt = .StringFormat.New() loStringFmt.Alignment = .StringAlignment.Center
* Create a Rectangle with the measures of the Bitmap LOCAL loRect as xfcRectangleF loRect = loNewBmp.GetBounds()
* Draw the String loNewGfx.DrawString(lcText, loFont, loBrush, loRect, loStringFmt)
* Finally save the image loNewBmp.Save("c:\MyText.Png", .Imaging.ImageFormat.Png)
* Show the image RUN /N Explorer.exe c:\Mytext.Png ENDWITH
|
-
UPDATED CODE - FIXED BUG REPORTED BY JEAN PIERRE SENET IN THE GRAPHICS INITIALIZATION. Merci beaucup Jean !
The function below converts any button image to a BMP to be used in VFP forms.
There are lots of cool and free icons available on the web, but the vast majority are in .ICO, GIF or PNG image formats, that are not very familiar and reliable to be used in VFP. For us, the best image format, for a lot of reasons, is the BMP format.
Some transformations are needed to make this BMP to show exactly how we desire, specially when converting source images in a PNG, GIF or ICO formats.
VFP shows the pure white - RGB(255,255,255) as transparent in our buttons and image objects. The code below first converts the original whites to RGB(254,254,254) that is visually the same, but does not become transparent, and eliminates the need to create a mask image (.MSK) and next, converts the background color of the original bitmap to pure white, that will show transparent in VFP forms.
For more details, please check these prior posts:
BMPs with Transparent Backgrounds
How to put one image over another in a form
IMPORTANT Requires VFP9 and GdiPlusX to run. Please make sure that you have the latest version, because this sample may be using some functions that were added or fixed recently. http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
Save the program below as BUTTON2BMP.PRG, and call it this way:
Button2Bmp(GETPICT(), "c:\NewIcon.bmp")
When you compile this program in your executable, please don't dorget to remove the LOCFILE() command, and just use a DO System.prg instead
LPARAMETERS tcSourceFile, tcDestFile
DO LOCFILE("System.prg")
LOCAL loBmp AS xfcBitmap
LOCAL loGfx AS xfcGraphics
LOCAL loBorderClr AS xfcColor
LOCAL loRect AS xfcRectangle
LOCAL loAttr AS xfcImageAttributes
LOCAL loColorMap AS xfcColorMap
WITH _SCREEN.SYSTEM.Drawing
loColorMap = .Imaging.ColorMap.New()
loAttr = .Imaging.ImageAttributes.New() loBmp = .Bitmap.FromFile(tcSourceFile) loGfx = .Graphics.FromImage(loBmp)
loRect = loBmp.GetBounds()
* Get the top left pixel color, presuming this color is the BackGround colro to become transparent
* For our BMP case, this will become PURE WHITE - RGB(255,255,255)
* that becomes transparent when used in VFP objects
loBorderClr = loBmp.GetPixel(0,0)
* Convert original Whites RGB(255,255,255) to OFF WHITE - RGB(254,254,254)
* this way, the whites will remain without the need of a mask
loColorMap.OldColor = .Color.White
loColorMap.NewColor = .Color.FromARGB(255,254,254,254)
loAttr.SetRemapTable(loColorMap)
loGfx.DrawImage(loBmp, loRect, loRect, .GraphicsUnit.Pixel, loAttr)
* Next step, convert the borders to pure White, RGB(255,255,255) that will become transparent in buttons
loColorMap.OldColor = loBorderClr
loColorMap.NewColor = .Color.White
loAttr.SetRemapTable(loColorMap)
loGfx.DrawImage(loBmp, m.loRect, m.loRect, .GraphicsUnit.Pixel, loAttr)
loBmp.Save(tcDestFile, .Imaging.ImageFormat.Bmp)
ENDWITH
|
-
This week Calvin Hsia came with a very interesting post, Extract TreeView or ListView ImageList icons from a DLL .
That Calvin's post is dedicated to Visual Studio developers.
As in the comments there were some people asking the code for VFP, below I'm putting and adapted version for VFP users, using, of course, GdiPlusX to help us extracting the icons from the resource.
There's still more to say about this, but in this first moment, I'm putting just the code to retrieve the embedded bitmap from the Visual Studio DLL that Calvin refers to. Below is the most relevant part of the original code in VB .NET from Calvin, very easilly converted to VFP, using the GdiPlusX library.

Picture 1: Relevant Source code in VB .NET
And here is the VFP code. Very simple, isn't it ?
IMPORTANT
Requires VFP9 and GdiPlusX to run. Please make sure that you have the latest version, because VFPPaint uses some functions that were added recently. http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
* Init GdiPlusX DO LOCFILE("System.prg")
#DEFINE LOAD_LIBRARY_AS_IMAGE_RESOURCE 0X20 #DEFINE LOAD_LIBRARY_AS_DATAFILE 2
DECLARE INTEGER LoadLibraryEx IN kernel32; STRING lpFileName, INTEGER hModule, INTEGER dwFlags DECLARE INTEGER LoadBitmap IN user32; INTEGER hModule, INTEGER hResInfo DECLARE INTEGER FreeLibrary IN Kernel32 LONG hModule DECLARE INTEGER DeleteObject IN WIN32API INTEGER hObject
* Other files that can be used for this test * C:\Windows\System32\shdocvw.dll Resource Pointer 328 * C:\Windows\System32\browseui.dll Resource Pointer 279
LOCAL lhModule, lhRes lhModule = LoadLibraryEx("C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\msenv.dll", ; 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE + LOAD_LIBRARY_AS_DATAFILE) lhRes = LoadBitmap(lhModule, 0x4f4)
LOCAL loBmp AS xfcBitmap WITH _SCREEN.SYSTEM.Drawing loBmp = .BITMAP.FromHbitmap(lhRes) loBmp.Save("c:ResourceImage.Bmp", .Imaging.ImageFormat.Bmp) ENDWITH

Picture 2: The extracted image in the original size

Picture 3: A part of the extracted image expanded 8 times
Cool ! But still not ready to be used in our VFP forms.
As that bitmap contains many icons in the same file, I'll use some GDI+ stuff to separate each of them, saving in a different file. We have to know the dimensions of each image, so I'll take the smallest value between the width and height, and use a loop to crop each icon image separately. The backgrounds also need to be treated, as I'll comment below.
For VS users, Calvin used a totally different technique to separate the images, using the ListView and the TreeView controls from VS. If someone could show me how to chieve this in VFP using his technique... it would be great !
Each image is saved in two different formats:
1 - BMP of 24 bits, with white background, to be used in VFP buttons. The white background is RGB(255,255,255). For safety purposes, I also changed all original whites from the icons to RGB(254,254,254). This way, VFP will not make these parts of the images as transparent.
2 - PNG of 32bits, with the background color set as transparent
There is some more complex code that I used to crop the images that I've never showed before in my blog. It's all full of comments, and I hope, it's easy to understand. Feel free to ask for more info about this, if you need.
************************************************************************************************************ * PROGRAM: ExtractIconsFromResource2.Prg * AUTHOR : Cesar Chalom * * Extracts all 16x16 icons stored in DLLs * Extracts the icons from the big collection pictures obtained from the resource * Aplies effects to the image to keep transparencies * * Sample totally based on Calvin Hsia's article from his blog * "Extract TreeView or ListView ImageList icons from a DLL" * http://blogs.msdn.com/calvin_hsia/archive/2007/11/06/5948486.aspx?CommentPosted=true#commentmessage
* * Prerequisites: * VFP9 and GdiPlusX library - http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home ************************************************************************************************************ DO LOCFILE("System.prg")
#DEFINE LOAD_LIBRARY_AS_IMAGE_RESOURCE 0X20 #DEFINE LOAD_LIBRARY_AS_DATAFILE 2
DECLARE INTEGER LoadLibraryEx IN kernel32; STRING lpFileName,; INTEGER hFile,; INTEGER dwFlags DECLARE LONG FreeLibrary IN Kernel32 LONG hModule DECLARE INTEGER LoadBitmap IN user32; INTEGER hInstance,; INTEGER lpBitmapName DECLARE INTEGER DeleteObject IN WIN32API INTEGER hObject WITH _SCREEN.SYSTEM.Drawing LOCAL lcFile, lcShortName, lcIconFile LOCAL hModule, hRes LOCAL N, lnWidth, lnHeight LOCAL loIcon AS xfcBitmap LOCAL loBmp AS xfcBitmap LOCAL loBorderClr AS xfcColor * These objects will be used only if the output is BMP LOCAL loCloned AS xfcBitmap LOCAL loColorMap AS xfcColorMap loColorMap = .Imaging.ColorMap.New() LOCAL loAttr AS xfcImageAttributes m.loAttr = .Imaging.ImageAttributes.New() lcFile = "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\msenv.dll" + CHR(0) lcShortName = "C:\" + JUSTFNAME(lcFile) hModule = LoadLibraryEx(lcFile, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE + LOAD_LIBRARY_AS_DATAFILE) hRes = LoadBitmap(hModule, 0x4f4)
IF hRes = 0 LOOP ENDIF
loBmp = .BITMAP.FromHbitmap(hRes) loBmp.SAVE(lcShortName + "_AllIcons.Png", .Imaging.ImageFormat.Png) DeleteObject(hRes) lnHeight = loBmp.HEIGHT lnWidth = lnHeight
IF lnHeight > 16 && This is a big image, so it's not the icon we're interested in LOOP ENDIF * Get the quantity of Bits per Pixels of the image. * If we have an indexed format (< 24), we wont create the transparencies manually. LOCAL lnPixFmtSize lnPixFmtSize = loBmp.GetPixelFormatSize(loBmp.PixelFormat)
* Get the top left pixel color, presuming this color will be converted * to transparent loBorderClr = loBmp.GetPixel(0,0)
* Make a copy of the bitmap for further processing as BMP loCloned = loBmp.CLONE() *-* BEGINNING OF THE PNG CROPPING * Save the Icons as PNGs with transparent background IF lnPixFmtSize >= 24 && The background is not White, so loBmp.MakeTransparent(loBorderClr) ENDIF
FOR N = 0 TO (loBmp.WIDTH / lnWidth) - 1 lcIconFile = lcShortName + "_Icon_" + TRANSFORM(N) + ".png" loIcon = loBmp.CLONE(.Rectangle.New(N * lnWidth, 0, lnWidth, lnHeight)) IF VARTYPE(loIcon) = "O" loIcon.SAVE(lcIconFile, .Imaging.ImageFormat.Png) ENDIF ENDFOR
* Restore the original Bitmap object for the BMP transformations loBmp = loCloned.CLONE() *-* END OF PNG CROPPING *-* BEGINNING OF THE BMP CROPPING IF loBorderClr <> .COLOR.White AND ; lnPixFmtSize >= 24 && The background is not White, so && let's make some changes to adapt the icon to have a white && background, that will appear transparent in buttons
* Convert original Whites RGB(255,255,255) to OFF WHITE - RGB(254,254,254) * this way, the whites will remain without the need of a mask loColorMap.OldColor = .COLOR.White loColorMap.NewColor = .COLOR.FromARGB(255,254,254,254) loAttr.SetRemapTable(loColorMap) loGfx = .Graphics.FromImage(loBmp) loRect = loBmp.GetBounds() loGfx.DrawImage(loBmp, m.loRect, m.loRect, .GraphicsUnit.PIXEL, loAttr)
* Next step, convert the borders to pure White, RGB(255,255,255) that will become transparent in buttons loColorMap.OldColor = loBorderClr loColorMap.NewColor = .COLOR.White loAttr.SetRemapTable(loColorMap) loGfx.DrawImage(loBmp, m.loRect, m.loRect, .GraphicsUnit.PIXEL, loAttr) ENDIF * Continue, cropping each icon from the big image FOR N = 0 TO (loBmp.WIDTH / lnWidth) - 1 lcIconFile = lcShortName + "_Icon_" + TRANSFORM(N) + ".bmp" loIcon = loBmp.CLONE(.Rectangle.New(N * lnWidth, 0, lnWidth, lnHeight), .Imaging.PixelFormat.Format24bppRGB) IF VARTYPE(loIcon) = "O" loIcon.SAVE(lcIconFile, .Imaging.ImageFormat.Bmp) ENDIF ENDFOR *-* END OF THE BMP CROPPING
FreeLibrary(hModule) ENDWITH

Picture 4: Thumbnails of some of the images cropped and transformed from the resource file
But there's still one important problem that I wasn't able to solve yet: To list all available resources. So, for the case I wanted to extract the biggest quantity of available icons in all resource files of my computer, the provisory solution I've found was to create a loop, from 0 (zero) to 65535, trying to retrieve the image resource.
I've just based myself in another old post of mine, Extract icons from EXE, DLL and ICO files with GdiPlusX , and created a new script for extracting all available 16x16 icons in all resources from a specific folder, checking also all the subdirectories. The final result is TONS of icons, all stored in just one folder, "C:\Resource Icons", in two versions, one in PNG with the transparent background, and another version stored in the format of BMP of 24 bits, with white background, that is the format best supported by VFP for our command buttons.
When you run this last sample, depending on the folder that you choose, and the remaining subfolders, the resulting process may be really long, so I ask you to be patient, but I ensure you it's worth. When finished, open the folder "C:\Resource Icons". My search in Drive C of my computer, resulted in more than 25000 different icons !
Enjoy !
************************************************************************************************************ * PROGRAM: ExtractIconsFromResource3.Prg * AUTHOR : Cesar Chalom * * Extracts all 16x16 icons stored in DLLs or EXE files * Explores recursively in all the directory and subdirectories selected * Extracts the icons from the big collection pictures obtained from the resource * * Sample totally based on Calvin Hsia's article from his blog * "Extract TreeView or ListView ImageList icons from a DLL" * http://blogs.msdn.com/calvin_hsia/archive/2007/11/06/5948486.aspx?CommentPosted=true#commentmessage * * Prerequisites: * VFP9 and GdiPlusX library - http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home ************************************************************************************************************ DO LOCFILE("System.prg")
#DEFINE LOAD_LIBRARY_AS_IMAGE_RESOURCE 0X20 #DEFINE LOAD_LIBRARY_AS_DATAFILE 2
DECLARE INTEGER LoadLibraryEx IN kernel32; STRING lpFileName,; INTEGER hFile,; INTEGER dwFlags DECLARE LONG FreeLibrary IN Kernel32 LONG hModule DECLARE INTEGER LoadBitmap IN user32; INTEGER hInstance,; INTEGER lpBitmapName DECLARE INTEGER DeleteObject IN WIN32API INTEGER hObject * Create destination directory to receive the extracted icons lcDir = "C:\ResourceIcons" IF NOT DIRECTORY(lcDir) MKDIR (lcDir) ENDIF * Create the cursor that will store the valid file locations CREATE CURSOR Recursive (cFile c(250)) LOCAL lcSelectedDir lcSelectedDir = GETDIR() IF EMPTY(lcSelectedDir) WAIT WINDOW "Invalid Directory" RETURN .F. ENDIF WAIT WINDOW "Retrieving folders information" NOWAIT
* Scan through the selected and the subfolders =Recurse(lcSelectedDir) WITH _SCREEN.SYSTEM.Drawing
LOCAL lcFile, lcShortName, lcIconFile, lnTotRec LOCAL lnOldPercentage, lnPercentage LOCAL hModule, hRes LOCAL N, lnWidth, lnHeight LOCAL loIcon AS xfcBitmap LOCAL loBmp AS xfcBitmap LOCAL loBorderClr AS xfcColor * These objects will be used only if the output is BMP LOCAL loCloned AS xfcBitmap LOCAL loColorMap AS xfcColorMap loColorMap = .Imaging.ColorMap.New() LOCAL loAttr AS xfcImageAttributes m.loAttr = .Imaging.ImageAttributes.New() STORE 0 TO lnPercentage, lnOldPercentage lnTotRec = RECCOUNT()
SCAN lcFile = ALLTRIM(Recursive.cFile) + CHR(0) lcShortName = JUSTFNAME(lcFile) hModule = LoadLibraryEx(lcFile, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE + LOAD_LIBRARY_AS_DATAFILE) FOR x = 0 TO 0xffff hRes = LoadBitmap(hModule, x) && 0x4f4) IF hRes = 0 LOOP ENDIF lcNewFile = ADDBS(lcDir) + lcShortName loBmp = .BITMAP.FromHbitmap(hRes) loBmp.Save(lcNewFile + "_AllIcons_r" + TRANSFORM(x) + ".Png", .Imaging.ImageFormat.Png) DeleteObject(hRes) lnHeight = loBmp.HEIGHT lnWidth = lnHeight IF lnHeight > 16 && This is a big image, so it's not the icon we're interested in LOOP ENDIF * Get the quantity of Bits per Pixels of the image. * If we have an indexed format (< 24), we wont create the transparencies manually. LOCAL lnPixFmtSize lnPixFmtSize = loBmp.GetPixelFormatSize(loBmp.PixelFormat)
* Get the top left pixel color, presuming this color will be converted * to transparent loBorderClr = loBmp.GetPixel(0,0)
* Make a copy of the bitmap for further processing as BMP loCloned = loBmp.Clone() *-* BEGINNING OF THE PNG CROPPING * Save the Icons as PNGs with transparent background IF lnPixFmtSize >= 24 && The background is not White, so loBmp.MakeTransparent(loBorderClr) ENDIF
FOR N = 0 TO (loBmp.WIDTH / lnWidth) - 1 lcIconFile = lcNewFile + TRANSFORM(x) + "_Icon_" + TRANSFORM (N) + ".png" loIcon = loBmp.CLONE(.Rectangle.New(N * lnWidth, 0, lnWidth, lnHeight)) IF VARTYPE(loIcon) = "O" loIcon.SAVE(lcIconFile, .Imaging.ImageFormat.Png) ENDIF ENDFOR * Restore the original Bitmap object for the BMP transformations loBmp = loCloned.Clone() *-* END OF PNG CROPPING
*-* BEGINNING OF THE BMP CROPPING IF loBorderClr <> .Color.White AND ; lnPixFmtSize >= 24 && The background is not White, so && let's make some changes to adapt the icon to have a white && background, that will appear transparent in buttons * Convert original Whites RGB(255,255,255) to OFF WHITE - RGB(254,254,254) * this way, the whites will remain without the need of a mask loColorMap.OldColor = .Color.White loColorMap.NewColor = .Color.FromARGB(255,254,254,254) loAttr.SetRemapTable(loColorMap) loGfx = .Graphics.FromImage(loBmp)
loRect = loBmp.GetBounds() loGfx.DrawImage(loBmp, m.loRect, m.loRect, .GraphicsUnit.Pixel, loAttr)
* Next step, convert the borders to pure White, RGB(255,255,255) that will become transparent in buttons loColorMap.OldColor = loBorderClr loColorMap.NewColor = .Color.White loAttr.SetRemapTable(loColorMap) loGfx.DrawImage(loBmp, m.loRect, m.loRect, .GraphicsUnit.Pixel, loAttr) ENDIF
* Continue, cropping each icon from the big image FOR N = 0 TO (loBmp.WIDTH / lnWidth) - 1 lcIconFile = lcNewFile + TRANSFORM(x) + "_Icon_" + TRANSFORM(N) + ".bmp" loIcon = loBmp.CLONE(.Rectangle.New(N * lnWidth, 0, lnWidth, lnHeight), .Imaging.PixelFormat.Format24bppRGB) IF VARTYPE(loIcon) = "O" loIcon.SAVE(lcIconFile, .Imaging.ImageFormat.Bmp) ENDIF ENDFOR *-* END OF THE BMP CROPPING ENDFOR
FreeLibrary(hModule)
* Show progression lnRec = RECNO() lnPercentage = ROUND((lnRec / lnTotRec),2) IF lnPercentage > lnOldPercentage WAIT WINDOW "Extracting icons from files..." + CHR(13) + ; "Elapsed: " + TRANSFORM(lnPercentage * 100) + " %" NOWAIT lnOldPercentage = lnPercentage ENDIF ENDSCAN ENDWITH RETURN ***************************************************************************************** * FUNCTION : RECURSE * AUTHOR : MICHAEL REYNOLDS * DESCRIPTION : Good for performing file processing throughout an entire directory tree. * The function, RECURSE(), is called with the full path of a directory. * RECURSE() will then read all files and directories in the path. * A function can be called to process files that it finds. * Plus, the function calls itself to process any sub-directories. * http://fox.wikis.com/wc.dll?Wiki~RecursiveDirectoryProcessing~VFP ***************************************************************************************** FUNCTION Recurse(pcDir) LOCAL lnPtr, lnFileCount, laFileList, lcDir, lcFile CHDIR (pcDir) DIMENSION laFileList[1] *--- Read the chosen directory. lnFileCount = ADIR(laFileList, '*.*', 'D') FOR lnPtr = 1 TO lnFileCount
IF 'D' $ laFileList[lnPtr, 5] *--- Get directory name. lcDir = laFileList[lnPtr, 1] *--- Ignore current and parent directory pointers. IF lcDir != '.' AND lcDir != '..' *--- Call this routine again. &nb | |