Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

GDIPlusX library seems not respecting Image Control Stretch setting!

Rajesh Karunakaran

Programmer
Sep 29, 2016
545
MU
Dear all,

I am using the GDIPlusX library downloaded from here. I have a form and added the ImageCanvas control from the above library in it. At run time, I am making the form maximised to entire screen and the size of ImageCanvas control also.

In native Vfp image control, when we set the Stretch property to 1-Isometric, the image will try to occupy the full area of the Image control but will not disturb the Height - Width ratio. However, with the above ImageCanvas control, even after setting Stretch property to 1-Isometric, it just stretches the image to fill the complete area and thereby disturbing the overall Height - Width ratio.

I have used GDIPlusX earlier also for some other purposes. But, now I am stuck up on this problem. I am not sure which setting I am missing.

Anyone has experience with this library? Any idea?

This is the original Image:
original.png

This is when it is shown in ImageCanvas control (see the ratio is disturbed)
gdiplus-imagecanvas.png
 
Last edited:
No idea what you mean by ImageCanvas control. Is it a class part of GdiPlusX?

I assume you mean the VFP image control and either set it's picture or pictureval property to the picture to display. If you display an image file or PictureVal (there are methods of GdiPlusX providing that, too), the VFP image control dimensions determine how the image is shown and strecthing is determined by it stretch property. No matter if the image resolution is respecting the aspect ratio when shrinking a picture with GdiPlusX or not, the image control stretching can very simply make a stretch that breaks the aspect ratio. The image file or pictureval value that GdiPlusX provides will not force anything upon image displaying controls, neither VFP nor third party, in the end how the image displaying controls display an image is more important than what the image file or value contains.

The VFP image control has two settings that will display an image with the an aspect ratio1:1, the default image.stretch=0 will not stretch it and display it 1:1, therefore no stretching that breaks the aspect ratio, the only thing that hinders full display is when the image control size is too small and the image is therefore clipped. The visible part is still 1:1 and anchored at the top left corner of the image control. If you use the isomatric stretch with image.stretch=1 VFP will fit the picture into the dimensions of the image control (width/height) so that it's maximum size and still in the same aspect ratio. Causing white or black margins either left and right or at top and bottom. The option stretch=2 does what you show, it simply stretches the image to the full image control dimensions, no matter whether that distorts the image aspect ratio or not, the aspect ratio simply becomes that of the image control.
 
I wonder if you'd want a mode VFPs imge control doesn't offer: An isometric stretch that stretches the image as far as is necessary to not have margins and instead clips it left AND right or at top AND bottom, not only right or at the bottom, as the default clip mode does.

And it would help if you post what you do in GdiPlusX, of course, before anything esle.
 
Last edited:
Chriss,

I have a form. I have the ImgCanvas class from the GDIPlusX library in it
(ImgCanvas is a class from the library. Sorry, I had misspelled it in my first message)

My goal was to show an image, whether portrait, landscape, larger or smaller, in full screen without disturbing dimension ratio.
I got it working with recalculated dimensions for the image and the imgCanvas control.

But new problem: In Windows 10 it works great, but in Windows 11, it is able to recalculate dimensions but not showing the image!
When the program runs I can see the imgCanvas has new size correctly applied. Can see imgCanvas with border and diagonal cross lines.

Basically, below is the basic and essential code that I use:

Code:
*/ In form Load method
Do system.app    && this is a part of library and we need to do this.

*/ In form Init method
limg = "myPic.jpg"

*/ This is as suggested by the library
WITH _Screen.System.Drawing
    loSrc = .Bitmap.FromFile(limg)
ENDWITH

*/ Here from the image dimension aspect ratio and screen dimension aspect ration, I calculate the new size of image.
*/ I resize the ImgCanvas to the new size.
*/ I calculate the position of ImgCanvas left-top corner, considering need for centering Horizontally or Vertically.

*/ Then create a bitmap with the new dimensions
WITH _Screen.System.Drawing
    * Create a new bitmap with the calculated dimensions
    loBmp = .Bitmap.New(loSrc, lnScaledWidth, lnScaledHeight)
ENDWITH

* Assign the bitmap to the form's ImgCanvas control
Thisform.oBitmap = loBmp   && the library's internal code uses the oBitmap property of the form.
Thisform.img.Draw()
 
It would help to see how you calculate left top vorner, dimensions of the ImgCanvas control and lnScaledWidth, lnScaledHeight to see whether you make false assumptions or other errors in that.

Meanwhile I need to look into how the ImgCanvas class is implementing to draw the image. If it's based on VFPs image control the stretch property is still able to butcher all your adjustments by stetching the image differently than you resized the jpg or cut out the part of the jpg you display.

Besides that, even if it would, it would respect the aspect ratio of your scaled version of the jpg, and thus only respect the jpg aspect ratio, if your scdaling also did.
 
Last edited:
I looked at the code of ImgCanvas. It's unclear how you make it know it has to render the image you store in Thisform.oBitmap. You must hae some code somewhere that does make it the source for the imgCanvas.Draw() call.

And then in the Draw call there is indeed nothing that makes use of the Stretch property value. So the stretch property only ever plays a role when using the standard way t display an image by seteting picture toa file or pictureval to a file read into memory or blob. Then stretch is applied to that, otherwise not.

Draw not provided with parameters for height and width would always draw an image in the diemsnions of the control, which is ignoring the loBMP aspect ratio, it's simple the image resized to the 'ImgCanvas control width and height.

Your code does actually do the same as not using gdiplusx at all, setting a normal image controls picture to the "mypic.jpg" and stretch to 2, using the imgCanvas control instead you get the stretch=2 behavior, no matter if you set it to 0 or 1 or 2, draw by default draws in the image control size and when necessary resizes the given image to that size.
 
In very short. Yes, the GdiPlusX ImgCanvas control is not respecting the Stretch property when used without setting the Picture or PictureVal property. The ImgCanvas control inherits the property from the native VFP image control, but the Draw method isn't respecting it.

Draw is actually also not the method you should call to display an image, it's there to react to draw events that happen, for example, when another form in front of the control is moved out of the way and there is a refresh of the control. The Draw method code in part prevents draws to happen more often than necessary.

Draw needs to redraw what already has initially been drawn from Picture/PictureVal, and that already respected the Stretch setting, so that's, I think, why it's done that way. Draw is also a method of the normal image control and also rather is an event than a method, reasons its declared as a method are a topic in itself. Anyway, you're supposed to still mainly use the Picture or PictureVal properties to provide the image to be displayed and with them the Stretch setting is applied as inherited, there's no change in that behavior, there's no GdiPlusX specialization of Stretching added to the features.

Edit: I looked into some samples and deoms in blogs and see the intention of BeforeDraw and AfterDraw is to provide a means to make use of GciPlus features in populating the canvas with something else but the Picture or PictureVal, but then that's where you'd, for example, create a grafix object that is a text along the path in the currrent size of the canvas and would be able to have a scaling text. Usage for images is still best done using the Picture ofr PictureVal without using that new mechanisms.

What you can do, because you initially load and resize the image into an oBmp object is to take the PictureVal of that and set it to the ImgCanvas.PictureVal with imgcanvas.pictureval = loBmop.GetPictureVal().

The only thing I then wonder about is when you already create a resized bitmap object, why don't you make the necessary resizing and clipping to make it 1:1 the image needed for the Imagecanvas control dimensions in a way that doesn't distort the aspect ratio. Which means, as the image canvas in your screnshot is about double as wide as the image itself, you can't keep the image aspect ratio without either having margins left and right and a smaller version of the image displayed centered or cut off top and bottom so that the aspect ratio of that is the same as the image canvas.
 
Last edited:
Chriss,

I have not studied deeper the methods, properties or other features of the library and its controls. I am just following the ways shown in their demos (and obviously made some modification to match my needs).

If you download the library, you will see a form "Transition_TestPerformance" in their 'Samples' folder. I referred to the following methods:
"Init"
"CreateEffect" (I was only interested in the Case where effect chosen as "Transparency Effect"

I took only those code parts related to my needs, modified and used.
In Windows 10, it works perfect. But not in Windows 11. That's my problem.

What you can do, because you initially load and resize the image into an oBmp object is to take the PictureVal of that and set it to the ImgCanvas.PictureVal with imgcanvas.pictureval = loBmop.GetPictureVal().
Here you have a point I think. Let me try this.

The only thing I then wonder about is when you already create a resized bitmap object, why don't you make the necessary resizing and clipping to make it 1:1 the image needed for the Imagecanvas control dimensions in a way that doesn't distort the aspect ratio. Which means, as the image canvas in your screnshot is about double as wide as the image itself, you can't keep the image aspect ratio without either having margins left and right and a smaller version of the image displayed centered or cut off top and bottom so that the aspect ratio of that is the same as the image canvas.
As normal, the screen is landscape mode and if the image is in portrait mode, yes, there will be blanks at left and right. What I do is, after calculating the max dimenions, I resize both image and the ImgCanvas. Then accordingly, I adjust the Left and Top of the ImgCanvas to centre it Horizontally or Vertically, as the case maybe.
 
I resize both image and the ImgCanvas. Then accordingly, I adjust the Left and Top of the ImgCanvas to centre it Horizontally or Vertically, as the case maybe.
I still don't get what this would do exactly. 'If I understand it roughly you want to cover the whole form with an image, then it's size is completely fixed, it's the form dimensions. For a portrait image to cover a landscape form, either the portrait image is that large, that you can center a part of it and clip it top and bottom, or you even have to blow it up, if the image width is below the form width.

You don't need any image resizing as the image control just needs to be made the image dimensions with the imgCanvas width being the form width and the imgCanvas height accoring to the image aspect ratio, then the image control, be it the VFP native one or the imgCanvas control of gdiplusx will stretch the image and in such cases I expet the top coordinate of the image wil be negative, unless you'd also be satisfied with having a top portion of the image only.

In any case, I don't really see the need for GdiPlusX for that. You must have a logical mistake in your sizing code when you get to an even wider image for this landscape form and rather landscape image.
 
Last edited:
Just another thought, as you still didn't post your calculations and all code necessary to understand what happens why:

If you see the image stretching on the form means a width factor of 2 and counteract that by resizing the image to half width, so after streching by factor 2 it's undistorted, you forget that an image half the witdth of the original will not be stretched by a factor of 2 but 4, so your countermeasure is countercountered by even more stretching, again. That's not how you get to undistorted image display.

I'd only work with the original image and an image control you size according to needs so that both the whole form is covered and the image isn't distorted. That will very likely also lead to either negative top or negative left coordinate of the image control qand VFP supports that, no problem.

Another strategy is to have image control exactly in form size, well, then the image does in general not only need a resizing, you will need to either add margin, which you won't want, so instead you need to cut out the biggest rectangle in form aspect ratio that fits into the original image, it won't ever help you to just resize the image, you have to make cuts as you don't want to only cover part of the form but wnat to cover the whole form. What the image control does with isometirc stretching doesn't help you as that generates margins you don't want.
 
Last edited:
I have not studied deeper the methods, properties or other features of the library and its controls
Well, you also posted code:
Code:
* Assign the bitmap to the form's ImgCanvas control
Thisform.oBitmap = loBmp   && the library's internal code uses the oBitmap property of the form.
Well, that surely isn't true, as the ImgCanvas control is still an image control and there can be multiple images on a form, they should be able to display different images, not just one.

It all boils down to this: If you don't post your full code that's relating to the image, it will stay impossible to tell you what to change to make it work.
 
Last edited:
If it helps, here's my idea in code, no need for GdiPlusX. The library is fine, of course, but unnecessary for this purpose.

backimage class code:
Code:
**************************************************
*-- Class Library:  c:\programming\tek-tips\projects\backimage\specialcontrols.vcx
**************************************************


**************************************************
*-- Class:        backimage (c:\programming\tek-tips\projects\backimage\specialcontrols.vcx)
*-- ParentClass:  image
*-- BaseClass:    image
*-- Time Stamp:   11/17/24 10:45:08 PM
*
DEFINE CLASS backimage AS image
    aspectratio = (16/9)
    Name = "backimage"

    PROCEDURE Init()
        This.Stretch=0 && assure stretch is 0 for image size determination
        BindEvent(Thisform,"resize",this,"adapt")
        This.Picture = This.Picture && sets control size to image size
        This.aspectratio = This.Width/This.Height && fur futere reference in adapt()
        this.ZOrder(1) && send image to back
        This.adapt() && initial adaption to current form size
    ENDPROC

    PROCEDURE adapt()
        thisform.lockscreen=.t.

        this.Stretch = 1 && ensure stretch is 1
        If Thisform.Width/Thisform.Height < this.aspectratio
           * form aspect ratio is slimmer than images aspect ratio
           * => attach  image.top/bottom to form
           * excess left/right is clipped
           This.Top=0
           This.Height = Thisform.Height
           This.Width = This.aspectratio*This.Height
           This.Left = -(This.Width-Thisform.Width)/2
        Else
           * form aspect ratio is wider than images aspect ratio
           * => attach image.left/right to form
           * excess top/bottom is clipped
           This.Left=0
           This.Width = Thisform.Width
           This.Height= This.Width/This.aspectratio
           This.Top = -(This.Height-Thisform.Height)/2
        Endif

        thisform.lockscreen=.f.
    ENDPROC
ENDDEFINE
*
*-- EndDefine: backimage
**************************************************

Don't copy this into a prg, rather create a visual image class and copy over the init and adapt code plus create the property "aspectratio"

Usage: Put the class on a form anywhere, set the Picture to a picture file.
In init the image will adapt to the form and automaitcally adapt to form resizing.

Sample image, royalty free from https://www.pickpik.com/cascade-falls-green-long-exposure-moss-nature-142884
1731880619124.png
Sample form screenshots
1. form slimmer
1731880754698.png
2. form wider
1731880819289.png
 
Last edited:
Rajesh, I don't hear any feedback on this. Makes me wonder if you took in my recommendations or the solution not using GDIPlusX or whether you requirements differ.

If you want the form to keep the aspect ratio of its background image, for example, then do that in the form Resize method and enforce it there. That also won't require anything else but image.stretch=1. for the image itself and the form keeing the aspect ratio will prevent margins to appear. The form then can't be made slimmer or wider than the image is, but you'll need to think of the full screen modes, where the displays can have 4:3 or 16:9 aspect ratios, if not even others.
 

Part and Inventory Search

Sponsor

Back
Top