I did some testing for storing photos in a MySQL database a few days ago starting with an MBS Example and then modified code to get scaling with Antialiasing to work and was happy with the result using the method below:
Public Function ScalePicture(p As Picture, maxWidth As Integer, maxHeight As Integer) as Picture
// Scales a Picture while keeping the correct aspect ratio
If p <> Nil Then
// Calculate the scale ratio
Dim ratio As Double = min(maxHeight / p.height, maxWidth / p.width)
// Create a new picture to return
Var w As Integer = p.width * ratio
Var h As Integer = p.height * ratio
Dim newPic As New Picture(w, h, 32)
// Scale the Picture using Graphics.AntiAliasMode
newPic.Graphics.AntiAlias = True
newPic.Graphics.AntiAliasMode = Global.Graphics.AntiAliasModes.HighQuality
// Draw the picture in the new size
newPic.graphics.DrawPicture(p, 0, 0, w, h, 0, 0, p.width, p.height)
Return newPic
End If
End Function
The result from scaling two images one that was 4032 x 3024 and another 3024 x 4032 to Thumnail images with a max dimension of 180 pixels were smooth and retained detail.
However, using the exact same function in a web application the scaling is jagged and horrible.
I’ve been searching for an alternate and reading through as many forum posts as I can find on scaling with antialiasing but I haven’t found any solution that gave me equivalent quality comparable to the Thumbnails generated with the Desktop Graphics.AntiAliasMode.
Potentially there appears to be something called D2D1 from a post with an exchange by Norman Palardy and William Yu about a replacement for GDI+ but there wasn’t actually any syntax for a D2D1 Soft Declare.
So far I’ve had no better results with all the MBS options I’ve tried and I’m assuming that Graphics.AntiAliasMode is broken in Web 1.0, but if someone knows why it isn’t working and has a fix I’d sure like to hear about that, otherwise if anyone has a better option for scaling down high res images to quality thumbnails I’d sure like to to get your recommendation or sample code.
Quite a while I did an implementation of native rescaling. Let me search my old code.
Edit: found the code. I don’t know if this works for web or not.
Private Function BilinearInterpolation(OriginalPicture as Picture, newWidth as Integer, newHeight as Integer, constrainProportion as Boolean) As Picture
dim w as Integer = OriginalPicture.Width
dim h as Integer = OriginalPicture.Height
dim x_ratio as Double = (w - 1)/newWidth
dim y_ratio as Double = (h - 1)/newHeight
if constrainProportion then
if x_ratio >= y_ratio then
newHeight = h/x_ratio
else
newWidth = w/y_ratio
end if
x_ratio = max(x_ratio, y_ratio)
y_ratio = max(x_ratio, y_ratio)
end if
dim oldSurf as RGBSurface = OriginalPicture.RGBSurface
dim oldMask as Picture = OriginalPicture.CopyMask
dim oldMaskSurf as RGBSurface
if oldMask <> nil then oldMaskSurf = OriginalPicture.mask.RGBSurface
dim InterpolatedPicture as new Picture(newWidth, newHeight, 32)
dim InterpolatedSurf as RGBSurface = InterpolatedPicture.RGBSurface
dim InterpolatedMaskSurf as RGBSurface = InterpolatedPicture.mask.RGBSurface
dim x, y as Integer
dim x_diff, y_diff, blue, red, green, gray as Double
dim a, b, c, d as Color
for i as Integer = 0 to (newHeight - 1)
for j as Integer = 0 to (newWidth - 1)
x = x_ratio * j
y = y_ratio * i
x_diff = (x_ratio * j) -x
y_diff = (y_ratio * i) - y
'calculations for red, green and blue
a = oldSurf.Pixel(x, y)
b = oldSurf.Pixel(x + 1, y)
c = oldSurf.Pixel(x, y + 1)
d = oldSurf.Pixel(x + 1, y + 1)
blue = (a.Blue * (1 - x_diff) * (1 - y_diff)) + (b.Blue * x_diff * (1 - y_diff)) + (c.Blue * y_diff * (1 - x_diff)) + (d.Blue * x_diff * y_diff)
green = (a.green * (1 - x_diff) * (1 - y_diff)) + (b.green * x_diff * (1 - y_diff)) + (c.green * y_diff * (1 - x_diff)) + (d.green * x_diff * y_diff)
red = (a.red * (1 - x_diff) * (1 - y_diff)) + (b.red * x_diff * (1 - y_diff)) + (c.red * y_diff * (1 - x_diff)) + (d.red * x_diff * y_diff)
InterpolatedSurf.Pixel(j, i) = Color.RGB(red, green, blue)
if oldMaskSurf <> Nil then
'now the mask
a = oldMaskSurf.Pixel(x, y)
b = oldMaskSurf.Pixel(x + 1, y)
c = oldMaskSurf.Pixel(x, y + 1)
d = oldMaskSurf.Pixel(x + 1, y + 1)
gray = (a.Blue * (1 - x_diff) * (1 - y_diff)) + (b.Blue * x_diff * (1 - y_diff)) + (c.Blue * y_diff * (1 - x_diff)) + (d.Blue * x_diff * y_diff)
InterpolatedMaskSurf.Pixel(j, i) = Color.RGB(gray, gray, gray)
end if
next
next
Return InterpolatedPicture
End Function
Thanks for the code snippet. Your code is now the second version of bilinear interpretation with RGBSurface I’ve tried with no success in quality change. I think there must be something fundamentally broken in Web 1.0 Picture manipulation especially since Greg O’Lone confirmed that AntiAlias only works in desktop apps. My guess is that the complier doesn’t reject using the desktop commands for Picture, but they somehow are ignored in execution. I get equally bad results using various plugins that worked on a desktop app so the logic is Web app pictures can’t be effectively manipulated. In any case the quality with your code looks like the result I get trying to use plugins and Graphics.AntiAliasMode in the Web 1.0 app.
And the goal is to achieve this:
I did a test late yesterday where I created a console app with 2021R2.1 that processes an Image using the Graphics.AntiAliasMode and I get the desired quality. I’m working on shelling out to that app in my web app to process the thumbnails and resizing large uploaded photos to the medium res storage limit I have set at 2048 x 2048. Once stored, using the ScalePicture code in my original post to display a photo in a dynamically sized palette window looks good enough for the purposes of the App.
It used to be documented somewhere that the graphics system in Console apps is different from that of Desktop. Try drawing text, the positioning is wildly different.
Windows has just always been terrible at resizing images. Are plugins a solution for this project? MBS may be worth a shot.
Admittedly that was wrong due to a copy paste error but it makes no difference and the Compiler didn’t complain about a syntax error. I just tested it and the result is the same in Web 1.0 as before changing it.
Very odd indeed, I have it working here and I initially though it was that causing the issue. I guess this web stuff is more buggy that I thought, I only ever use Web when I’m checking bugs and I’ve think I’ve found two just helping you here.
This is what I see with it working:
and this is with it not working
this is altered simply by commenting out line 14 in your code from above.
If you breakpoint on line 19 (the Return) of ScalePicture and view newPic in the debugger does it look smooth or jaggy?
If its jaggy are you able to dropbox/host the image you’re testing and PM me the link?
Are you testing using 2019R3.2 to build your test Web app or are you testing in Web 2.0 2020R1 or higher?
When I view it in the debugger it is Jaggy. If you can confirm that you definitely are using 2019R3.2 and testing in a web app I’d be happy send you a link to the image.
That is mighty kind of you if you have an idea better than my current approach, which is I have created a console app with 2021R2.1 that processes an Image using the Graphics.AntiAliasMode where I get the desired quality. I’m presently working on shelling out to that app in my web app to process the thumbnails and resizing large uploaded photos to the medium res storage limit I have set at 2048 x 2048. I suspect it won’t be much slower than if Graphics.AntiAliasMode was working in Web 1.0, since the user of this app is limited to 4 picture uploads at a time.
I had a little play with this after dinner and couldn’t find an easy way around it so your method is probably the simplest method. I did find the bug report regarding this issue and it was fixed in the very next version after the one you’re using <https://xojo.com/issue/20033>. In web everything uses libgd but there’s no documentation on which version xojo is using, I can get a handle to the image with ConsoleGDImage but without re-wrapping libgd and including it with your project it doesn’t seem that there’s a way around the bug.
I’m not really sure why MBS options produce the same result, maybe Christian can shed some light on that if you contact him directly.