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 TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to make edges of picture rounded? 5

Status
Not open for further replies.

Mandy_crw

Programmer
Jul 23, 2020
578
PH
Hi experts... I have an image put in my form, which is square... I want to have its corner rounded... Can you do rounded corner for images on the form? if so, please teach me how... Thanks and God bless....
 
The image control always is a rectangle, so the only way would be to edit the image to have rounded corners which should be transparent and saved as PNG format.

Chriss
 
You can do this easily in a photo-editing program. My choice would be Paint.Net, which is a bit like PhotoShop, but simpler to use and with the advantage of being free. This isn't the place to give a tutorial on using that sort of program, but a a very quick guide:

1. Use the program's Selection tool to select a rounded rectangle around the edge of the image (a bit like selecting text in Word).

2. Invert the selection - so that the area that was previously outside the selected area is now selected, and vice versa.

3. Delete the selected area. So the area outside the rounded rectangle will now be transparent.

4. Save the image as a PNG (not a JPEG, which does not support transparency).

5. Drop the image onto your VFP form.

The details will vary according to which photo-editing program you use, but the principle will be the same.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I don't know how many images you want to show with rounded corners, if it's a large batch like any product image for a POS system, it can be an advantage that Gimp (n alternative to Paintnet graphics software) offers batch processing, I don't know but also don't think Paint.net does offer that.

Well, but in any case, the most preferred solution would be to not need to modify the images at all. You can put objects on top of objects it would work to have the inverse, an image with a transparent rounded rectangle and grey or whatever background color you need in the corners, which could be put in front of any other image and only show the portion of the image below that is in the transparent rounded rectangle area. So in short like using a passe-partout.

A disadvantage of that is, that the corners then are in the color of the passe-partout image and if your form color changes or you have a gradient of colors, that passe-partout has to be adjusted.

There's the capability to paint or compute images with the help of GDIplusX, too, but I doubt it makes things easier, though it could take in the normal rectangular images and round the corners off on the fly, storing that as PNG for the current session of the application to use it. Which would make it easier to introduce more images as they can stay as they are and the rounding is always done on the fly.

Chriss
 
Mandy, just an afterthought to my earlier post ...

Instead of a PNG, if you can save the image as a BMP, you could select the area outside the rounded rectangle, and then fill it with white. With BMPs, white areas become transparent when placed on a VFP form. I'm not sure, but you might be able to do that in the Paint program that comes with Windows.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
It's a shame FoxPro controls don't have an hWnd - there's a neat little trick with Windows Regions that would solve this
 
You're thinking of the good old news2news implementation of irregular shaped forms. It's still there, moved to VFPX as Win32API repository.


You could do it and create any shape you want, then add the function SetParent to embed this form into another, which would also move when the parent form is moved, so it looks like being part of the parent form, still its THISFORM isn't the parent form. For display of an image that idea would work.

But then I think using GDI+ for image processing would be simpler. PNG transparency can create nicer shaprer/rounder edges, as the alpha transparency can go from 0 to 255 per pixel, whereas the form regions are shaped on basis of pixels being fully transparent or opaque.

I remember the VFP9 version without any SP had issues with some PNG formats, but that was fixed in SP1.

Chriss
 
>You're thinking of the good old news2news

Is that comment for me? If so, then no I am certainly not. If the FoxPro image control was an actual window with an hWnd, then my solution involves adding about 2 lines of code. Sadly the Fox developers decided to do their own implementation of the various controls rather than simply wrapping the ones provided by the OS.
 
Strongm, yes, I meant you. I thought you know it from there as that sample was how the whole VFP community got introduced to the possibility of transparency of forms. It works with regions, too, specifically by using the SetWindowRgn Windows API function.

Well, I don't see how it's just a two liner, even not taking into account the DECLARE DLL call, you also have to define a region, which needs a struct and further API calls. And then you have a rectangle region, not yet a rounded rectangle.

Chriss
 
I couldn't resist searching, I see there is CreateRoundRectRgn to create a rounded rectangle region. But looking for usage of it I see it does not support anti aliasing the rounded edges.

PNG still is the most straight forward solution also supporting alpha levels per pixel for very smooth antialiased rounded corners.

Chriss
 
Oh… hmmmm… I see… thanks Mike and Chriss… i would try the PNG format… God bless…
 
>I thought you know it from there as that sample was how the whole VFP community got introduced to the possibility of transparency of forms

Nah. We were playing with SetLayeredWindowAttributes and SetWindowRegion about 20 years ago in the VB6 forum

>CreateRoundRectRgn

Bingo!

>does not support anti aliasing the rounded edges

Yep, definitely a drawback of the old Region methods - but on the other hand the OP didn't originally mention an antialias requirement :)


 
the OP didn't originally mention an antialias requirement

I'm a bit annoyed about this stance to only exactly deliver what is asked for.

If you want rounded corners, you surely don't have a white form layout and product pictures with white background, as rounded corners make no difference, then. And as rounded corners are very obviously an esthetic design goal, it makes sense to give a solution that satisfies that the best, too, and so to think about it even though it wasn't even asked for.

With the Gimp rounded rectangle tool you get antialiased edges that won't look jiggy without even thinking about it, it's a standard, and it's annoying me how little Microsoft pays attention to such design details, it's no wonder they lost so many market shares to Apple. Even though they follow design trends or even try to set them first with Aero, then with flat bicolor designs and also complex though still very subtle and therefore also unnecessary animations.

It's very telling that there is a setting for turning animations off, though:
3use-computer-without-display_xpgbce.png


Okay, I'll stop my rant here, but I won't follow this idea of not adding things to the answer that go beyond what was asked.

As said, I'm just a bit annoyed.

Chriss
 
The other solution I proposed was using a passe-partout image that has a transparent round rectanlge region. To not need a different image per size you can split this up into the 4 corners and here I created 4 rounded corners as PNG images you can put into 4 image controls and position them at the corners of any image, which could then be any format, also formats not supporting transparency. Because the clipping and the round edge is done by these images, which are PNG and have an antialiased (smooth) round edge.


top left ... top right:
topleft_pdgoji.png
[tt] ... [/tt]
topright_psdv4d.png


bottom left ... bottom right:
bottomleft_czzbzc.png
[tt] ... [/tt]
bottomright_bawqpo.png


The form surrounding this just needs the grey tone of these edges, and you could adjust that color, but also, as I said, need to adjust this color, if you want the corners to blend in to the rest of the form. It also won't work if the form background is set to an image itself, to let that shine through at the corners you need a PNG image with transparency at the corners.

Chriss
 
Last not least, here's code using the VFPX project GDIPlusX to create an image with rounded corners. I post this, as it means you can use it on the fly on any image you use in your EXE already as is, as it computes a rounded corner variant of any image at runtime. You then won't need to manually prepare images.

Before you start
The GDIPlusX project is located at The simplest way to download it is to click on the green "Code" button/dropdown and pick "Download ZIP". That way you get all of this GitHub repository. What you finally need is a file System.app. See the paragraph Distribution files.

You find further info and Doug Henning, who owns the repository also has written some article about the usage of it at I got the idea from his papers example to draw an image on a circle in his code sample on page 11 of the PDF (result image on page 12). He uses a method called FillEllipse and I found out there's also FillPath, which uses the concept of describing an area by a closed path - the border of an area, a rectangle with rounded corners, for example, as you need it.

Then I found out how to define and use such a path and some pitfalls of it.

Once you have System.App unzipped from the download you can put it in your project directory and later install it together with the EXE. It remains a separate file and isn't embedded into your EXE when you build it. You can also take the full source code and embed it into your project, but for easier usage just DO System.App and it will generate an environment necessary to make usage of many graphical functionalities all under the roof of the GDIPlus.dll which is part of the VFP runtimes and at the same time is a Windows system resource for drawing besides Direct2D or even Direct3D, which are more powerful but also more complicated to use.

Take a look around, this package also is usable for graphics in reports and more. The homepage and also Doug's paper mention an image control class imgCanvas that can replace the VFP image control and is well integrated with the gdiplusx library and it would be an idea to subclass this as imgRoundedCanvas, for example, with Cornersize as property and automatic processing of whatever you set as its Picture. But I decided against that, as it makes it more complex to integrate this in your project.

What you can do with the following function saved as ROUNDEDEDIMAGE.PRG is create a version of image files with rounded corners. Minimally you need to pass in the original file name of the image and the cornersize you want (in pixelsize). The function then saves the result as filename with "rounded" added to the end of the name. The PNG format is used, to support transparency. Whatever the original image format is doesn't matter, as long as it's BMP,GIF,JPEG,JPG, anything VFP can support, so any format your images will already have.

To use that new image you then, of course, need to set an image.Picture to the result file of this code. Another way of using that would be to once process all the images you want to have with rounded corners and use them in your project. That way you wouldn't need to integrate it into your project but only use it from VFP to prepare your image. It's easy to process a whole list of files using ADIR() to get an array of file names and then call this PRG for each image file.

Code:
Lparameters tcSourceImage, tnCornerSize, tnImageWidth, tnImageHeight, tcSaveImageAs

#Define RESIZED 1
#Define ROUNDED 2

tcSourceImage = Evl(tcSourceImage, Home()+'fox.bmp')
tcSaveImageAs = Evl(tcSaveImageAs, Forceext(tcSourceImage,"png"))
If Upper(tcSaveImageAs)==Upper(tcSourceImage)
   tcSaveImageAs = Forceext(Justpath(tcSaveImageAs)+"\"+Juststem(tcSaveImageAs)+"rounded","png")
Endif

tnCornerSize = 2*Evl(tnCornerSize, 0)
* Double what you ask for, because the rounded rectange
* will be constructed from four arcs, each being a quarter circle
* at the corner of a square positioned at the corners of the image.
* A quarter circle only cuts off a quarter of the corner square,
* so the square needs to have double width and height.
* The arcs transition into the straight border edge at the offset
* you pass in as original tnCornerSize by using this original value
* as radius of the arc. That results in the corner size you want.

tnImageWidth = Evl(tnImageWidth, 0)
tnImageHeight = Evl(tnImageHeight, 0)

* ensure gdiplusx system.app is loaded already or will be started here
Local loGdiPlusXSystem
Try
   loGdiPlusXSystem = _Screen.System
Catch
   * you might want to use a configured path to system.app here or
   * put it into the same directory as your EXE and use Justpath(Sys(16,0))
   * for starters simply once DO SYSTEM.APP to not get here
   * or (just once) manually locat the VFPX gdiplusx system.app
   Do (Locfile("System.App"))
   loGdiPlusXSystem = _Screen.System
Endtry

With loGdiPlusXSystem.Drawing

   Local originalImg, resizedPNG, roundedPNG, loGfx, bgBrush, fgBrush, lnWdith, lnHeight, lnProcessed
   originalImg = .Bitmap.New(tcSourceImage)
   lnProcessed = 0

   If tnImageWidth>0 And tnImageHeight>0
      * Resizing to passed in size
      lnWdith = tnImageWidth
      lnHeight = tnImageHeight
   Else
      * keep original size
      lnWdith = originalImg.Width
      lnHeight = originalImg.Height
   Endif

   If Not (lnWdith == originalImg.Width And lnHeight == originalImg.Height)
      * resizing (for example to fit image control width/height
      * create a new bitmap with new size for that purpose
      resizedPNG = .Bitmap.New(w,h,w*4, .Imaging.PixelFormat.Format32bppARGB)
      loGfx = .Graphics.FromImage(resizedPNG)
      * draw the original image in that new size
      loGfx.DrawImage(originalImg, 0, 0, lnWdith, lnHeight)
      loGfx.Dispose()

      * This signals a resized image was created and is available as resizedPNG object
      lnProcessed = RESIZED
   Endif

   If tnCornerSize>0
      * rouding the corners with the help of a rounded rectangle path
      * yet another new bitmap "roundedPNG"
      roundedPNG = .Bitmap.New(lnWdith, lnHeight, lnWdith*4, .Imaging.PixelFormat.Format32bppARGB)
      loGfx = .Graphics.FromImage(roundedPNG)
      canvasRect = .Rectangle.New(0, 0, lnWdith, lnHeight)

      bgColor = .Color.New(0) && RGBA=0 means alpha=0, which is fully transparent
      bgBrush = .SolidBrush.New(bgColor)
      loGfx.FillRectangle(bgBrush, canvasRect) && fill roundedPNG with transparency
      bgBrush.Dispose()

      * Coordinates of Corner squares
      Local xr, yb, tl, tr, bl, br
      xr = lnWdith - tnCornerSize-1
      yb = lnHeight - tnCornerSize-1
      tl = .Rectangle.New( 0, 0, tnCornerSize, tnCornerSize)
      tr = .Rectangle.New(xr, 0, tnCornerSize, tnCornerSize)
      br = .Rectangle.New(xr,yb, tnCornerSize, tnCornerSize)
      bl = .Rectangle.New( 0,yb, tnCornerSize, tnCornerSize)

      * try .Drawing2D.SmoothingMode.None to see the difference
      loGfx.SmoothingMode = .Drawing2D.SmoothingMode.AntiAlias
      * smoothing mode is used for smoothing the path and the fill,
      * so the rounded edges are smooth

      * create a rounded rectangle path
      Local rectPath
      rectPath = .Drawing2D.GraphicsPath.New()
      * quarter circle arcs, each sweeping 90 degrees clockwise of a cornersquare (tl,tr,br,bl)
      rectPath.AddArc(tl, 180, 90)
      rectPath.AddArc(tr, 270, 90)
      rectPath.AddArc(br,   0, 90)
      rectPath.AddArc(bl,  90, 90)
      rectPath.CloseAllFigures()

      If lnProcessed = RESIZED
         * when the original image was resized, resizedPNG will be used as brush
         fgBrush = .TextureBrush.New(resizedPNG)
      Else
         * otherwise originalImg will be used as brush for filling the rounded rectangle path
         fgBrush = .TextureBrush.New(originalImg)
      Endif

      * fill the path with the (resized) image
      loGfx.FillPath(fgBrush,rectPath)
      fgBrush.Dispose()
      loGfx.Dispose()

      * This signals a rounded corner image was created and is available to save it
      lnProcessed = lnProcessed + ROUNDED
   Endif

   Do Case
      Case lnProcessed = 0 && neither resized nor rounded
         * save the loaded image in PNG format. This just converts the image format
         originalImg.Save(tcSaveImageAs, .Imaging.ImageFormat.Png)
      Case lnProcessed = RESIZED  && ONLY resized, not rounded
         * save the resized image in PNG format
         resizedPNG.Save(tcSaveImageAs, .Imaging.ImageFormat.Png)
      Otherwise && rounded (no matter wether resized or not)
         * save roundedPNG
         roundedPNG.Save(tcSaveImageAs, .Imaging.ImageFormat.Png)
   Endcase
Endwith

Minimal usage is by calling

Code:
ROUNDEDEDIMAGE("yourimage.jpg",50) && 50 pixel sized rounded corners.
The result of that is an image file "yourimagerounded.png" in the same directory as "yourimage.jpg".

The parameters offer more control than just the corner size. In prospect of the image control on a form not being the size of the original image but smaller, you can also use further parameters to shrink the image before rounding the corners, using the imagecontrol.width and height as the basis.

So for example "yourimage.jpg" may be a desktop-sized image and your form image control is only perhaps 30% of that size. If you cut off 50 pixel rounded corners from the desktop size image and the image control then stretches or better shrinks it down, the corners will also get smaller. If you instead first resize the whole image and then cut off the corners, you get the corner size you want to see on your form.

Code:
ROUNDEDEDIMAGE("yourimage.jpg",50,800,450) && 50 pixel sized corners cut off the image first resized to 800x450
Of course, any other size than 800x450, just as you need. That could be the size form.image1.width, form.image1.height, for example. This could be called in image.Init() and also adjust the image.Picture to be the new file. Again, the result image file is "yourimagerounded.png" in the same directory as "yourimage.jpg".

Caution! The function overwrites existing files. To cause no harm to your original files I built in to check whether the save file name differs from the original file name, also when you explicitly specify the same save file name. And that is another usage of the PRG in this syntax with full parameterization:

Code:
ROUNDEDEDIMAGE("yourimage.jpg",50,800,450,GETENV("TEMP")+"\yourimage.png") && as before, just explicitly using yourimage.png as result file name.
This way you can also specify another path of the result file. You can store it anywhere else, as this example does by saving it into the %TEMP% system directory.

And, of course, the first parameter ideally also has file names including their paths. Otherwise, the GDI+ library may not find the file. I'm not sure it's even aware of VFPs default path. I mean the systems gdiplus.dll, not the VFP code in system.app You can try and then thank the System.app developers they take the default directory into account, I think.

You either put this PRG into your default path, a path in SET PATH or you SET PROCEDURE to it before using it.

And to round this post off, here's an image and rounded image I created with the function:
foxrounded_mzgtz6.png


Original file public domain from
Chriss
 
It's fun to play around with paths. You could also get round edges, as you literally asked for.

foxrounded_il6qwt.png

(The path is not yet ideal, but to give an impression of how you could shape images)

Chriss
 
oH EMMMM Geeeee Chris!!!! You're really amazing.... can i give 50 stars? Thank you so much... I really time to understand it well and able to use and eventually put it in my project.... Thanks and God bless....
 
You have to thank many others that provided GDIPlusX. I think Cesar Chalom started it. Though there also is a gdi+ library in VFP9 FFC classes, _gdiplus.vcx, Cesar Chalom and later other contributors made this whole add-on that enables easier use of the GDI+ features of the Windows API. In the end, it is "just" Windows itself used, but the API functions of GDI+ are very intertwined and it's not easy to start from scratch. And this library makes it easy to get at GDI+ features, use Bitmaps, Graphics, Brushes, Pens, Geometric figures, etc.

You might also like based on GdiPlusX.

Chriss
 
I think advertising ist forbidden Here...

Peace worldwide - it starts here...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top