Author Topic: Chasing a paint bug  (Read 1067 times)

sinsi

  • Member
  • *****
  • Posts: 1156
Re: Chasing a paint bug
« Reply #30 on: June 08, 2019, 05:26:28 PM »
Not sure how it's supposed to be but
 - animation only shows after mouseover.
 - dragging left/up puts it behind the existing pic, dragging down/right puts it in front.

I can walk on water but stagger on beer bourbon.

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #31 on: June 08, 2019, 06:15:09 PM »
Version 5 - one more bug fixed, which was triggered by the tooltip that appears when hovering over the map, or clicking into a country.  The culprit, btw, was a non-initialised local variable.

It works fine now on my Win7 and Win10 machines. Working memory is stable, no leaks. In the XP VM, the Chinese text is not displayed, otherwise it works even there. There is a bit of flicker when resizing the entire window, but that is unavoidable, it seems.

Hitting H activates the animated GIF. You may have to resize the window to see it. On WinXP only, if you size it to a very small width and the GIF is active, it will complain about a ValueOverflow. No such problem on Win7 and Win10.

Grateful for feedback.

Hi jj2007,

now everything works as it should  :azn: :thup:, looks very solid, but I have three little things ...

1. in the bottom right, on both sides the last digits go beyond the window (Image 1)
2. when resizing the window holding the lower right corner, the yellow sphere breaks its shape (despite the fact that the effect is temporary, but until the next drawing it remains to hang so - Image 2 )
3. If you change the size to the minimum square, then the window size handler is broken, it is expressed in the fact that if you try to grab the right side of the window, then the window will assume that you are holding the left side of the window, in this case, change the window to its original state is impossible (An example of a testing window can be seen in the picture - Image 3)

Except for the above, everything works just super!  :thumbsup: :eusa_dance:

PS - Did you use GDI+?

jj2007

  • Member
  • *****
  • Posts: 9518
  • Assembler is fun ;-)
    • MasmBasic
Re: Chasing a paint bug
« Reply #32 on: June 08, 2019, 07:04:14 PM »
now everything works as it should  :azn: :thup:, looks very solid, but I have three little things ...

1. in the bottom right, on both sides the last digits go beyond the window (Image 1)

Right. Can be fixed manually (there is a "margins" argument), or I will have to check somehow how long the last number will be. But that would be an overkill :sad:

Quote
2. when resizing the window holding the lower right corner, the yellow sphere breaks its shape (despite the fact that the effect is temporary, but until the next drawing it remains to hang so - Image 2 )

Yes indeed. Funny, but it happens only when you reduce the width to an extent that the graph itself becomes useless. Will see if a check is worth the effort.

Quote
3. If you change the size to the minimum square, then the window size handler is broken, it is expressed in the fact that if you try to grab the right side of the window, then the window will assume that you are holding the left side of the window, in this case, change the window to its original state is impossible (An example of a testing window can be seen in the picture - Image 3)

That is because a control seems to have no minimum size, and the WS_THICKFRAME borders start overlapping in some sense. You can see only because I use the thickframe style here for testing, in a normal program one wouldn't use that style for a tiny control. The main window does not allow shrinking it so much.

Quote
Except for the above, everything works just super!  :thumbsup: :eusa_dance:

PS - Did you use GDI+?

Thanks :smiley:

And yes, that is Gdi+ for the plot lines and the sphere (the circle). The quality is so much better than the ragged lines of plain GDI. Transparency is a by-product, rarely useful, but with the beach background it looks quite ok.

Again, thanks to everybody - I will soon release a new version showing how to produce such a plot. For example:

  GuiControl Emissions, "canvas", x333, w333, WS_THICKFRAME, h500   ; x333 means "x at 33.3% of width"
  GuiControl TheMap, "canvas", x666, w333, h500, WS_THICKFRAME
 .... code to load other controls ....
Event CanvasPaint
  Switch_ ecx                           ; ID returned in ecx
  Case_ Emissions
        ArrayPlot RgbCol(100, 255, 100)                 ; init & set background
        SetAxisX "Year", s 1880, d 5/10, grid 1, format "%i"    ; s=start value, d=difference betw. gridlines, grid pen
        SetAxisY "CO2 emissions", s 0.0, d 1000/2, grid 1, format "%i", peng hPenGrid
        ArrayPlot gem(XY), RgbCol(255, 0, 0), lines=2, 00050401h        ; plot the data, set line colour & size, margins xtrb
        ArrayPlot exit, "CO2 emissions"                         ; finish with a title
  Case_ TheMap
        ArrayPlot RgbCol(204, 222, 255)                 ; init and set background colour
        PaintMap RgbCol(127, 127, 127), lines=2         ; map with grey borders 2px thick
        ArrayPlot exit, "Europe"
  Endsw_


The gem(XY) that gets plotted is a REAL4 array read from a text file embedded in the resources with ID 110 via
Code: [Select]
StringToArray 110, gem() As REAL4, staHasText
The text file looks basically like this:
Code: [Select]
Year CO2 https://datahub.io/core/co2-fossil-global#resource-global
1880 236 Million metric tons of C
1881 243 http://cdiac.ess-dive.lbl.gov/ftp/ndp030/CSV-FILES/global.1751_2014.csv
1882 256
...
2008 8783
2009 8740
2010 9167 vv interpolated using EDGAR vv
2011 9437
2012 9556
2013 9722
2014 9845
2015 9843
2016 9879
2017 9994

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #33 on: June 08, 2019, 08:37:41 PM »
Quote
And yes, that is Gdi+ for the plot lines and the sphere (the circle).

You can try to use InterpolationMode, under the links below you can find an example and the algorithms of rendering, the example in CSharp language can also be applied to c++ ...

Custom AntiAliasing with GDI+ https://www.codeproject.com/Articles/9184/Custom-AntiAliasing-with-GDI
Using Interpolation Mode to Control Image Quality During Scaling - https://docs.microsoft.com/en-us/windows/desktop/gdiplus/-gdiplus-using-interpolation-mode-to-control-image-quality-during-scaling-use
PixelBox: A PictureBox with configurable InterpolationMode - https://www.codeproject.com/Articles/717312/PixelBox-A-PictureBox-with-configurable-Interpolat

Examples can be taken here - https://www.solidfiles.com/v/nGWzmr77QRy73

The Custom Antialiasing Algorithm

To produce a higher quality image than native GDI+ antialiasing, I use the following algorithm.
Code: [Select]
// Make a 4X offscreen bitmap, power of 2's are important because
// interpolating other size images takes significantly longer.
Bitmap offscreen = new Bitmap(bounds.Width*4, bounds.Height*4);
Graphics ofg = Graphics.FromImage(offscreen);
                       
//Update transform for additional pixels
Matrix t = m.Clone();
t.Translate(-bounds.Left, -bounds.Top, MatrixOrder.Append);
t.Scale(4.0f, 4.0f, MatrixOrder.Append);
                       
//Do Paint
Paint(ofg, t);                   
                       
//Stretch blit the rendered image to the actual image
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(offscreen, bounds, 0, 0, offscreen.Width, offscreen.Height,
    GraphicsUnit.Pixel);


1. Construct an off-screen bitmap that is 2, 4 or 8 times larger that the image I intend to output. It is important to use a power of 2 for the offscreen bitmap.
2. Draw the vector images scaled appropriately for the larger offscreen bitmap.
3. Use Graphics.DrawImage with InterpolationMode set to HighQualityBicubic when stretch bliting the image to the smaller value.


Code: [Select]
;--------------------------------------------------------------------------
; Interpolation modes
;--------------------------------------------------------------------------

InterpolationMode TYPEDEF DWORD ;enum

;InterpolationMode UNION DEFALIGNMASM
InterpolationModeInvalid EQU <QualityModeInvalid >
InterpolationModeDefault EQU <QualityModeDefault >
InterpolationModeLowQuality EQU <QualityModeLow >
InterpolationModeHighQuality EQU <QualityModeHigh >
InterpolationModeBilinear EQU <0H>
InterpolationModeBicubic EQU <01H>
InterpolationModeNearestNeighbor EQU <02H>
InterpolationModeHighQualityBilinear EQU <03H>
InterpolationModeHighQualityBicubic EQU <04H>
;InterpolationMode ENDS

;API
GdipSetInterpolationMode PROTO graphics:XMASM ,interpolationMode:DWORD
;API
GdipGetInterpolationMode PROTO graphics:XMASM ,interpolationMode:XMASM
;API

Another similar topic ... http://www.asmcommunity.net/forums/topic/?id=20654 with invoke GdipSetInterpolationMode,grafico,InterpolationModeHighQualityBilinear ; equ 6
I am working on a program that loads jpeg's pictures and display then in a static control which works fine, but I need to create a resized second picture so you can view it a control and the control doesn't have to resize to the full size of the picture. I found acouple of samples but they are all in .NET, C++ which I don't know how to use, so here is the code i have!
Code: [Select]
; Create VB Picture box to draw imagen later On
INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,addr StaticClass, NULL,SS_BITMAP or WS_CHILD or WS_VISIBLE,\
10, 50, 350,350, hWnd, NULL, hInstance, NULL
; Save Control handle for later use
mov hImageTestL,eax
; Convert Image Filename to Wide character other wise it will return error
invoke MultiByteToWideChar,CP_OEMCP,MB_PRECOMPOSED,addr NombreArchivo,-1,addr NombreW,255
; Load image from file and save bitmap to imagen1
invoke GdipLoadImageFromFile,ADDR NombreW,ADDR imagen1
; Get original image pixel format (usually 32 Bit color) and save it to lFormat
invoke GdipGetImagePixelFormat,imagen1,addr lFormat
; Get original image Width and save it to sngWidth
invoke GdipGetImageWidth,imagen1,addr sngWidth
; Get original image Height and save it to sngHeight
invoke GdipGetImageHeight,imagen1,addr sngHeight
; Set W variable to 400 (pixels) this would be new picture width
mov W,400
; Set H variable to 400 (pixels) this would be new picture height
mov H,400
; C++ Bitmap::Bitmap(width, height, format) Create new bitmap with widht and height just set and same pixel format as the original image and save it to imagen2
invoke GdipCreateBitmapFromScan0,W,H,0,lFormat,0,addr imagen2
; Set graphic interpolation mode to high quality output
; Shrink the image using low-quality interpolation.(InterpolationModeNearestNeighbor)
; Shrink the image using medium-quality interpolation. (InterpolationModeHighQualityBilinear)
; Shrink the image using high-quality interpolation. (InterpolationModeHighQualityBicubic)
invoke GdipSetInterpolationMode,grafico,InterpolationModeHighQualityBilinear ; equ 6
; Get original image Horizontal resolution and save it to HorRes variable
invoke GdipGetImageHorizontalResolution,imagen1,addr HorRes
; Get original image Vertical resolution and save it to VerRes variable
invoke GdipGetImageVerticalResolution,imagen1,addr VerRes
; Set new image vertical and horizontal resolution to match orignal image resolution
invoke GdipBitmapSetResolution,imagen2,HorRes,VerRes
; Create new graphics object from new image
invoke GdipGetImageGraphicsContext,imagen2,addr grafico
; RGB 0,0,0
; Set image background to Black color
invoke GdipGraphicsClear,grafico,0
; Draw resized original image to graphic object of new bitmap
invoke GdipDrawImageRectI,grafico,imagen1,0,0,W,H
; Destroy orignal image
invoke GdipDisposeImage,imagen1
; Delete new image graphic object
invoke GdipDeleteGraphics,grafico
; Create standard GDI Bitmap from Gdi+ Bitmap and save bitmap handle in hBitmap variable
; If you want to rotate image use:
;invoke GdipImageRotateFlip,imagen2,Rotate90FlipNone
invoke GdipCreateHBITMAPFromBitmap,imagen2,addr hBitmap,0
; Set VB Picture box control image to our new resized image
invoke SendMessage,hImageTestL,STM_SETIMAGE,IMAGE_BITMAP,hBitmap

InterpolationMode takes graphics to a new level  :thup:
« Last Edit: June 09, 2019, 01:12:34 AM by LiaoMi »

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #34 on: June 08, 2019, 09:18:45 PM »
 :eusa_boohoo: to test the interpolation method, I suggest using the example below, you can even try variations of the interpolation mapping, as it is done in the example with CSharp, the display quality of the custom algorithm will be many times better. Simple lines should look better as in the examples above. It remains to add interpolation methods ...

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #35 on: June 08, 2019, 11:26:19 PM »
jj2007

last note, when I maximize the window, the yellow circle disappears (program start -> maximize window -> circle disappeared)

PS
fascinating example  :rolleyes:
gdiplus_doublebuffer.zip

jj2007

  • Member
  • *****
  • Posts: 9518
  • Assembler is fun ;-)
    • MasmBasic
Re: Chasing a paint bug
« Reply #36 on: June 08, 2019, 11:33:36 PM »
Hi LiaoMi,

Attached my version of the "gangster" - honestly, I don't see a big difference...

GuiParas equ "Hello jj2007", x680, w680, h740, m0, bnone
include \masm32\MasmBasic\Res\MbGui.asm
GuiControl Shooter, "canvas"
Event CanvasPaint
  invoke GetClientRect, hShooter, addr rc_
  invoke FillRect, PtDC, addr rc_, rv(GetStockObject, BLACK_BRUSH)
  GuiImage 100, fit
GuiEnd



LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #37 on: June 08, 2019, 11:53:55 PM »
 :biggrin: I also dont see, because the example has not yet been modified by the technique - The Custom Antialiasing Algorithm, but this example can be taken as a basis for testing ... "gangster" - This is not a ready-made example!

The difference will be noticeable  :azn:

Picture example ...
InterpolationMode.Low


InterpolationMode.HighQualityBilinear


InterpolationMode.HighQualityBicubic


Vector graphics example

GDI+NoAntiAlias   -   GDI+AntiAlias  -  GDI+CustomAntiAlias


the result is obvious, the custom algorithm is perfect, almost like maсOS graphics  :biggrin:

jj2007

  • Member
  • *****
  • Posts: 9518
  • Assembler is fun ;-)
    • MasmBasic
Re: Chasing a paint bug
« Reply #38 on: June 10, 2019, 09:58:02 AM »
It definitely looks good :thumbsup:

Attached is one more version of my plot program, with a handful of minor changes. Inter alia, I added a statusbar which shows the name of the country when you click into the map. Source of the handler:

Event Message
  If_ uMsg_==WM_MAPCLICKED && MapRegion>=0 Then SetWin$ hSBar="You clicked on "+MapRegion$


With the GSL interface, it can handle also plots of Bessel lines:


Source:
Code: [Select]
gsl double gsl_sf_bessel_J0(double x)
gsl double gsl_sf_bessel_Jn (int n, double x)
gsl_INIT
Dim Bessel0() As REAL8
Dim Bessel1() As REAL8
Dim Bessel2() As REAL8
xor ecx, ecx                          ; array index
SetGlobals fct:REAL8
For_ fct=-10.0 To 40.0 Step 0.02
      SetFloat Bessel0(ecx)=gsl_sf_bessel_J0(fct)
      SetFloat Bessel1(ecx)=gsl_sf_bessel_Jn(1, fct)
      SetFloat Bessel2(ecx)=gsl_sf_bessel_Jn(-3, fct)
      inc ecx
Next
GuiControl Bessel, "canvas"
Code: [Select]
Event CanvasPaint
  ArrayPlot RgbCol(240, 240, 240)        ; init with window (or control) handle and background colour
  ArrayPlot Bessel0(), RgbCol(255, 255, 222, 222), bars=1, 02020202h     ; red; transparency!
  ArrayPlot Bessel0(), RgbCol(100, 255, 0, 0), lines=2 ; red lines
  ArrayPlot Bessel1(), RgbCol(255, 0, 255, 0), lines=2 ; green opaque lines
  ArrayPlot Bessel2(), RgbCol(100, 0, 0, 255), 0 ; blue dots
  ArrayPlot exit, 0300000032#T "GSL: Regular cylindrical Bessel functions"       ; finish with a title

An example of the anti-aliasing taken from the Bessel plot - it works much better for lines than for a line of dots:


Here is what the attached proggie should show. If it doesn't, let me know :badgrin:
« Last Edit: June 10, 2019, 08:33:04 PM by jj2007 »

Biterider

  • Member
  • ***
  • Posts: 349
  • ObjAsm32 + ObjAsm64 = ObjAsm
    • ObjAsm
Re: Chasing a paint bug
« Reply #39 on: June 10, 2019, 03:59:23 PM »
Hi JJ
There are still some problems. When opening the application. it complains about a missing "clouds.jpg" file. When stretching the plots horizontally, the last tick of the X-axis falls too far away from the axis.

Biterider

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #40 on: June 10, 2019, 08:14:21 PM »
Hi jj2007,

1. Image 1 - the bottom text is moved to the middle when the window is maximized.
2. Image 2 - the yellow circle disappears when the window is maximized.
3. Image 3 - picture not found + oddities when opening the first chart.
4. Image 3 - the second graph shows the dates, after some time they disappear.
5. Image 5 + Image 7 - Something strange is happening with the background image in two cases, when hovering the mouse and maximizing the window size.
6. Image 6 - old oval shift effect.

Quote
An example of the anti-aliasing taken from the Bessel plot - it works much better for lines than for a line of dots:
What kind of anti-aliasing was used?

On the comparison above was used - Custom Antialiasing Algorithm

The Custom Antialiasing Algorithm
1. Construct an off-screen bitmap that is 2, 4 or 8 times larger that the image I intend to output. It is important to use a power of 2 for the offscreen bitmap.
2. Draw the vector images scaled appropriately for the larger offscreen bitmap.
3. Use Graphics.DrawImage with InterpolationMode set to HighQualityBicubic when stretch bliting the image to the smaller value.

The technique Custom Antialiasing above should process points, lines, pictures with equally high quality.

Left Std - Right Custom (You can see soft geometric smoothing in the picture)  :thup:



jj2007

  • Member
  • *****
  • Posts: 9518
  • Assembler is fun ;-)
    • MasmBasic
Re: Chasing a paint bug
« Reply #41 on: June 10, 2019, 08:47:58 PM »
When opening the application. it complains about a missing "clouds.jpg" file. When stretching the plots horizontally, the last tick of the X-axis falls too far away from the axis.

Oops, I forgot that Clouds.jpg was a local file. It's now embedded in the rc section, see new attachment above. Re stretching, yes, there may be glitches, but usually such graphs are optimised for one size anyway. The margins can be adjusted manually if needed.

1. Image 1 - the bottom text is moved to the middle when the window is maximized.
2. Image 2 - the yellow circle disappears when the window is maximized.
3. Image 3 - picture not found + oddities when opening the first chart.
4. Image 3 - the second graph shows the dates, after some time they disappear.
5. Image 5 + Image 7 - Something strange is happening with the background image in two cases, when hovering the mouse and maximizing the window size.
6. Image 6 - old oval shift effect.
1: yes, it's at a fixed offset; normally not a problem because it should be on top, and centered by default.
2: I noticed that on Win10, too. Very odd.
3: see new attachment above
4: you mean the date in the statusbar? That is by design
5: this is indeed odd, thanks for pointing it out; it looks ok when sizing the entire window, though.
6: works on Win7, but I'll what I can do.

Thanks again  :thup:


Quote
Quote
An example of the anti-aliasing taken from the Bessel plot - it works much better for lines than for a line of dots:
What kind of anti-aliasing was used?

gdi+ GdipSetSmoothingMode, GraphObj, SmoothingModeHighQuality

I am not against better anti-aliasing techniques, but I don't want third party libraries. Also, reserving a fat bitmap for StretchBlt'ing it down is not my favourite approach, I like to keep it small and light. However, if you have a magic procedure that smoothes a Gdi+ bitmap and can be added easily, it would be interesting.

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #42 on: June 10, 2019, 10:00:44 PM »
gdi+ GdipSetSmoothingMode, GraphObj, SmoothingModeHighQuality

I am not against better anti-aliasing techniques, but I don't want third party libraries. Also, reserving a fat bitmap for StretchBlt'ing it down is not my favourite approach, I like to keep it small and light. However, if you have a magic procedure that smoothes a Gdi+ bitmap and can be added easily, it would be interesting.

 :thumbsup:

GdipSetSmoothingMode great technique, have you tried other options - SmoothingModeAntiAlias8x8?  Instead SmoothingModeHighQuality ...
GdipSetSmoothingMode hGraphics, SmoothingModeAntiAlias8x8

Code: [Select]
typedef enum SmoothingMode {
  SmoothingModeInvalid,
  SmoothingModeDefault,
  SmoothingModeHighSpeed,
  SmoothingModeHighQuality,
  SmoothingModeNone,
  SmoothingModeAntiAlias,
  SmoothingModeAntiAlias8x4,
  SmoothingModeAntiAlias8x8
} ;

SmoothingMode Enumeration https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusenums/ne-gdiplusenums-smoothingmode

I understand you very well, but for graceful graphics you can lose a bit in speed  :azn:, this is done in mobile phone applications.

GDI+AntiAlias - 0.021s
GDI+CustomAntiAlias - 0.151s (average speed 7 times slower - considering that the displayed number of points is more than 10,000, on small sizes it may even be imperceptible)

In any case, this option can be simply discussed ... what kind of additional libraries do you mean? All functions are related to GDI plus standard .. no third party libraries should be used or did i miss something?

Quote
However, if you have a magic procedure that smoothes a Gdi+ bitmap and can be added easily, it would be interesting.
Does not fit to the role of a magical procedure, but I found this example (pure assembler source code) ... The example produces the same logic with a simple picture, where the picture is large and should be reduced in size, using interpolation technique.
In the vector example, we create an enlarged image, and then compress it in this way. At the same time receiving very high quality!

If you use two methods (SmoothingModeAntiAlias8x8 + interpolation) at once, it may be cool at all, usually both methods are used simultaneously
   GdipCreateFromHDC(Tmp.DC, Context);
   GdipSetSmoothingMode(Context, SmoothingModeAntiAlias8x8);
   GdipSetCompositingMode(Context, CompositingModeSourceCopy);
   GdipSetInterpolationMode(Context, InterpolationModeHighQualityBicubic); 

LiaoMi

  • Member
  • ****
  • Posts: 513
Re: Chasing a paint bug
« Reply #43 on: June 10, 2019, 10:45:01 PM »
This property is still active  :arrow_down:
Quote
3. If you change the size to the minimum square, then the window size handler is broken, it is expressed in the fact that if you try to grab the right side of the window, then the window will assume that you are holding the left side of the window, in this case, change the window to its original state is impossible

If you change the size of the first chart window, then when you hover the mouse on the third window, the picture changes to the same size as in the first window  :skrewy: (image 1 + image 2)

jj2007

  • Member
  • *****
  • Posts: 9518
  • Assembler is fun ;-)
    • MasmBasic
Re: Chasing a paint bug
« Reply #44 on: June 10, 2019, 11:59:44 PM »
Both problems should be solved now, please try again :thup:

SmoothingModeAntiAlias8x8 sounds nice, but I never saw a difference. Perhaps in Gdi+ 1.1, but how to get it to work?