19th Oct 2010.
For those keeping track of progress, our full list of classes now runs as follows (c/c++ counterparts are in brackets)
- BitmapData (BitmapData)
- EncoderParameters (EncoderParameter and EncoderParameters)
- Brush (Font)
- Font (Font)
- FontCollection (FontCollection, InstalledFontCollection and PrivateFontCollection)
- FontFamily (FontFamily)
- HatchBrush (HatchBrush)
- Image (Bitmap and Image)
- LinearGradientBrush (LinearGradientBrush)
- Matrix (Matrix)
- PointF (PointF)
- PointI (Point)
- PropertyItem (PropertyItem)
- RectF (RectF)
- RectI (Rect)
Each class comes with demos (all tested with x86 and x64) and some documentation. None of the demos currently render to screen etc. as that requires the 'Graphics' class which I have yet to do.
Progress will now slow down somewhat as the classes are getting bigger and bigger now. I am of course studying every facet of each function we import and so it will take a bit of time to complete this wrapper. A few weeks yet I reckon. In terms of functions imported from the GDI+ library, we are just under 25% of the way through.
More to follow. Download
===============================14th Oct 2010.
Have added the following classes (together with documentation and demos) :
These mimic the c/c++ wrapper classes, Font
Our full list of classes now runs as follows (c/c++ counterparts are in brackets)
More to follow. Download
in my concerted efforts to learn everything there is to learn about GDI+, and being a graduate of the 'diving in head first and learning by getting stuck in' university, I have started creating a class-based OOP wrapper around GDI+ (version 1.0) to basically mimic the MS c/c++ class wrapper (http://msdn.microsoft.com/en-us/library/ms533958(v=VS.85).aspx
Basically, GDI+ exports a flat-based c-style API. The class-based c/c++ wrapper is one of convenience and simplicity, breaking the 600+ functions exported by the flat API into a set of convenient classes. Most of the example code you will find scaterred about the web make use of this class-based wrapper (or the .Net equivalent) and so it is hoped that my wrapper will make code conversion somewhat simpler (no guarantees though!)
I intend adding as many classes as required for my own needs, but of course anticipate that this wrapper will grow with time.
So far I have wrapped the Bitmap and Image classes and a few sundry classes (e.g. encoder parameters). I make no real attempt to simplify access to GDI+ in any way, intending this to be no more than a Purebasic equivalent of the aforementioned c/c++ class wrapper. However, the differences between c++ and Purebasic have led me to simplify certain aspects of the GDI+ APIs. For example, I have added a CatchImage() type constructor as well as the ability to save an image directly to memory etc. I have also simplified access to encoder parameters which are always a pain in the a*se!
Each class I add comes with 101 or so demos since this is the best way for me to learn. There are also help documents for each class, though I have to say that they are very brief since you can simply turn to the relevant MSDN pages and MS has done a good job of documenting the c++ class methods.
I anticipate moving very fast now and will simply keep going until I have enough done to cater for my own immediate needs.
I am releasing a version now for two reasons. First, there may be a few people also wishing to delve head first into GDI+ and can use my work thus far to kick-start proceedings. God knows it has taken me long enough to get around to this.
Secondly, I would be very keen to have others help out with this, perhaps adding a class or two or some additional demos etc.
Anyone interested is asked to send me a pm so that we can ensure no duplication of work etc.
Every demo has been tested with both 32-bit and 64-bit versions of Purebasic (running under Vista).
Please read the "gdiPlus" help document before starting. You will find .doc and .pdf versions of this document within the download.
My thanks to Flype and SFSxOI for their various gdiPlus includes which I have used as reference material.DownloadNotes regarding GDI+.
I'll add to this as I proceed.
- Support for icons seems poor, very poor in fact. GDI+ seems unable to deal with icons which exhibit an alpha-channel. The advice seems to be to bypass the icon decoder and load them up through other means.
- Loading an image from a file locks the file whilst the resulting image is in use. This is because GDI+ sometimes discards the image memory when not in use and of course may subsequently have to reload the image data etc. This means that we can not overwrite an existing image file whilst the underlying image is in use. Work-around, use our gdiPlus_CatchImage() which, internally, stuffs the image data within a Stream object built upon a moveable hGlobal memory object.
- Take care with retrieving font metrics when obtained through GDI+ as the process differs markedly from GDI in this regard. Take the business of retrieving a cell's 'ascent' when a font is in use with a particular device. With GDI we simply select the font into the HDC representing the device in question and issue the GetTextMetrics_() api function in order to retrieve a whole bunch of info, amongst which is the required ascent value.
With GDI+ the situation seems, at first glance, somewhat backward. A quick glance at the 'Font' class (or the GDI+ flat API Font functions) and we see that there is no means of obtaining this metric without backtracking to GDI. Instead, we have to turn to the appropriate FontFamily class (or API) and issue the \GetCellAscent() method. With GDI+, we create a FontFamily object (which contains information on the font face etc.) before creating a font object housed 'within' this font family.
The problem with this \GetCellAscent() method, however, is that our call to this method does not refer to any particular device! Instead, the metric returned is in what are termed 'font design units' (not pixels or points for example) and are meaningless outside of the font file itself! Such values cannot even be used to compare like for like quantities between two different fonts! Thus, in terms of our ascent metric for example, we are left with a value which is to all intents useless!
Here's what we have to do. We must calculate the ratio of the actual line-height of our font when applied to a given device to the line spacing of the font-family when given the underlying font style. This ratio can then be used to adjust the font-family metrics when the associated font is to be rendered on the appropriate device. The ratio is calculated as font\GetHeightFromGraphics(...) / fontFamily\GetLineSpacing() etc.
So, to get the actual ascent (in the underlying units of the graphics object) we simply multiply the ascent value obtained from the appropriate FontFamily object by this ratio.
Seems backwards, but it is actually quite efficient really and, I have to say, that I like this better than the GDI method. Having a single ascent for the entire font-family kind of makes it 'cleaner' in a way.
- GDI+ has Matrix transformations all backwards, forcing mathematicians (like myself) to switch their modes of thinking! Mathematics students the world over (as far as I know) are taught to represent linear transformations via matrices in a certain way in which the 'points' to be transformed are represented in column vector form. This is not the case with GDI+ in which such points are represented in row form and consequently lead to matrix representations of affine transformations which are essentially the 'transpose' of that which we might otherwise expect. Even Wikipedia details such transforms in the more traditional way, leading me to wonder why MS decided on this representation? Not that it makes any real practical difference of course, except that I have to reverse my thought processes.