What can cause a pie chart to come out "squished"? - delphi

I have a pie chart, created with TeeChart, that looks just fine on the system I develop on, but when I run it on a different machine, the "pie" comes out all squished into an oval shape instead of being circular.
I've ensured that the Circled property (which should ensure that what's drawn is always a circle, not an ellipse,) on the TPieSeries is set True and does not get changed anywhere.
I checked to make sure that this isn't an artifact of different screen resolutions. It's not; the other system is on the same resolution as my dev box.
The other system had Aero turned off. I tested things by turning Aero off on my dev box, and the charts did not come out squished.
At this point I'm basically out of ideas. Does anyone know what can cause a pie chart that's set Circled = true to draw as an oval rather than a circle?
Good:
Bad:
This is the exact same program, working off the exact same data, at the exact same screen resolution, on two different computers.
EDIT: As discussed in comments, I tested this and found that both systems have not only the same resolution, but also the same DPI.

After a bunch of debugging and digging into the issue, it turns out this is happening because the TeeChart code is calling GetDeviceCaps with the HORIZSIZE and VERTSIZE parameters, to determine the physical size of the pixels on screen and adjust the circle's bounding rect accordingly. Unfortunately, this call is only valid on a printer, and not on a display device, and it has known issues on Windows 7, which both of the systems in question are using. I've reported the issue to Steema. Hopefully they can get it fixed.
UPDATE: Got a response from Steema, in which they acknowledged the problem and provided a workaround. Copying it here in case anyone else runs into the problem:
An alternative that allows you workaround the problem is to customize the Pie Radius using, perhaps, the height of the Chart rectangle to govern the dimension you need.
Eg:
procedure TForm9.Button1Click(Sender: TObject);
var cHeight : Integer;
begin
cHeight := Round((Chart1.ClientRect.Bottom - Chart1.ClientRect.Top) * 0.80); //80%
series1.CustomXRadius := cHeight div 2;
series1.CustomYRadius := series1.CustomXRadius;
end;

Related

Odd artifacts writing to FMX bitmap with TBitmapData on Windows 10

I have an odd bug in FMX that has all the hallmarks of a pointer overrun or a hardware-specific bug, which I haven't been able to track down. Small apps to reproduce it, don't (yet.) I have code snippets below, but since I haven't managed to reproduce this in a small application they are only snippets.
The app loads some PNG files, and then creates in-memory bitmaps based on colour-coding in the PNG files - that is, it will create an in-memory bitmap which is big enough to bound all red areas of the original, and is initially blank. There is a byte array the same size as the in-memory bitmap which is a mask (zero, non-zero) indicating if that pixel corresponds to a red (say) area in the original or not. The user can paint in the app, painting on a temporary display bitmap, and then when they let go the mouse button that bitmap is scanned against the byte array to write on the in-memory bitmap.
With me so far? Basically, colour-coded subsets of an original, masks created for the colour areas, painting on the subset is masked. Here's a diagram:
This works fine on XP (GDI+ canvas) and Win7 (D2D canvas) and Win8.1 and most Win10 machines. However, on two Win10 machines, one with an Intel HD 4600 and another with an Intel Iris 5000, a client gets odd artifacts on the bitmap after doing the step of masking and setting pixels.
The artifacts are rectangles scattered apparently randomly over the bitmap, either large (100x20px, say) or small (10x8, say). I've also seen screenshots where parts of the rest of the UI, like button glyphs, are also present on the bitmap. Here are some example screenshots:
Here the user has already painted the dark red area, and painted the lighter colour somewhere else. These small flecked rectangles appear.
Here the user has painted the broad stripe down the middle. The dark red and lighter red rectangles are examples of the artifacts after masking and drawing to the bitmap.
To me that sounds like I'm writing pixels at the wrong stride or something. I've rigorously code-inspected for off-by-one errors in array or bitmap data access, and I'm using the following code to get or set pixels in bitmap data:
function GetBitmapColor(const M : PBitmapData; const X, Y : Integer) : TAlphaColor;
begin
Result := PixelToAlphaColor(
#PAlphaColorArray(M.Data)[Y * (M.Pitch div PixelFormatBytes[M.PixelFormat]) + X],
M.PixelFormat);
end;
procedure SetBitmapColor(const M : PBitmapData; const X, Y : Integer; const C : TAlphaColor);
begin
AlphaColorToPixel(C,
#PAlphaColorArray(M.Data)[Y * (M.Pitch div PixelFormatBytes[M.PixelFormat]) + X],
M.PixelFormat);
end;
These are based on the example code for accessing bitmap data in the Seattle documentation. Assertions that X and Y are in a valid range (in the bitmap size) are all ok. While this happens on the OS & hardware given above, it does not happen for the same OS (Win10) with other cards - another Intel HD, a Nvidia, etc; on a Win10 tablet; on a Win10 VM I tried; on my Win7 development machine; etc. As far as buffer overruns etc are concerned, compiling with range checks on does not give any errors, nor have any asserts of my own checking valid X/Y coordinates against bitmap size.
The error occurs with both XE6 and Seattle on the same machines.
I can't reproduce this. They're in the process of setting up remote access to this machine but it's still going to be tricky to figure out what's going on, so I wonder if anyone has seen something like this before, or has concrete suggestions of specific ways to check for bitmap pointer overruns or similar?

Why is object.y not positioning the image in Corona SDK?

displaycontent = display.newImageRect (rawdata[currentpath][3], screenW*1.1, ((screenW*1.1/1654)*rawdata[currentpath][6]))
displaycontent.anchorY = 0
displaycontent.y = screenH*0.78
My program loads an image from a database to be displayed on the mobile phone's screen, everything works correctly apart from being able to position it with the y coordinates.
The only thing that changes its position is the anchor point 0 puts the top of the image in the centre of the screen, and values from 0.1 - 1 all position it higher. Changing the y position via object.y has zero effect regardless of what I set it as.
(the size settings probably look a bit weird in the first line, but this is because the images are different sizes and need to show the correct proportions on different screen types).
Btw I am using a tabbar widget as the UI (in case that is relevant)
Any help would be appreciated.
Edit: I am aware that displaycontent is bad name for a variable because of its similarity to things like display.contentCenterY for example, this will be changed to prevent any confusion when I look over the code in future.
I went through my code and tried disabling sections to find the culprit and a content mask was preventing me from setting the position of the loaded images within it.
I will look over my masking code and fix it (should be straight forward now I know where the problem started).
If anyone else has a similar problem (where an image or object wont position itself on given coordinates) check your content mask as that may be the issue!

all elements in the app are pixelated

screenshot below has been taken from 3.5inch simulator
these are bunch of UIButton, and the border created programmatically like:
btn.layer.cornerRadius = btn.frame.size.width / 2;
i don't know, but now all Fonts and UIButtons in the app get pixelated. mostly everything got pixelated.
I checked every setting in Xcode.
I tried to clean the project, then cleaned DerivedData folder.
I tried building the app in another machine.
I tried the app on real device. same problem.
nothing worked out yet.
An easy way to get pixellation on retina devices is rasterizing layers without setting the right rasterizationScale.
view.layer.shouldRasterize = YES;
view.layer.rasterizationScale = UIScreen.mainScreen.scale;
Without the second line, stuff will look fine for non-retina devices but it'll look awful on retina devices.
...hard to say if that's the problem you're seeing without more of the code, but it's a common enough bug that it merits posting.
Whether or not you should actually be rasterizing is a separate question...there are performance tradeoffs of which to be aware.
It could be that the resulting frame isn't aligned on an even integer. i.e. Moving/changing width is causing the frame to be something like (100.5, 50.0, 50.0, 50.0). When you are drawing on a half-pixel boundary, some of the drawing routines are going to make things look blurry to try and make it appear in the correct place. I would print out the frame after the animation and check:
NSLog(#"%#", NSStringFromCGRect(yourButton.frame));
If you see any non-integer values, use one of the floor() functions to modify the resulting frame in order to snap it to a boundary.
I had same problem with my UILabel(when i changed frame),
Before using floor() method:
And after:

Firemonkey drawing on bitmap without interpolation

I am using the canvas draw functions drawrect and filltext to draw onto a Tbitmap but I don't want the results antialiased. Anyone know how to do that ?
Working with OSX and Delphi XE3 (but have XE4 and XE5 if needed)
Is the problem:
the bitmap you create seems to have anti-aliasing present in the data?
or have you got a good bitmap and want to disable anti-aliasing in the viewer/display?
If it is the former, have you checked that the anti-aliasing is actually present in the bitmap, and not introduced by your viewer?
In the past I've found it useful to draw a black-on-white test pattern, and display the image at 1:1 scale. Irfanview is a nice tool for viewing at 'true' scale. Then use a loupe/peak/lens to get a close-up of the actual pixels.
Black-on-white test patterns are particularly good since you should be able to see (hopefully) that the R,G and B sub-pixels are all equally illuminated when there is no anti-aliassing present. If you draw a black-on white pattern and you get solitary bright sub-pixels then you've definitely got anti-aliassing (or some other form of corruption!).
My experience has been that image viewers often do interpolation for you, and it can be tricky to see what is going on unless you look at the actual bitmap data or have a close-up look at the unscaled image...
Hi in the drawBitmap method you need to set HighSpeed parameter to "True", in the sample below:
NewBitmap.Canvas.DrawBitmap(SmallBmp, RectF(0, 0, SmallBmp.Width, SmallBmp.Height), RectF(0, 0, NewBitmap.Width, NewBitmap.Height), 1,**True**);
rgds
Ivan

Timage Transparencies on laptops in Delphi 7

WHAT I AM TRYING TO DO
I am trying to draw multiple graphics to a Timage, These graphics that i Draw consist of ordered layers with Foodfills and lines.
I use multiple buffers to ensure ordering and double buffering.
WHAT I AM DOING
procedure DrawScene();
var
ObjLength,LineLength,Filllength,Obj,lin,angle,i:integer;
Npoints : array[0..1] of Tpoint;
Objmap:TBitmap;
wholemap:TBitmap;
begin
wholemap := TBitmap.Create;
wholemap.Width:=area;
wholemap.height:=area;
ObjLength:=length(Objects);
for Obj:=0 to (ObjLength-1) do
if objects[Obj].Visible then
begin
// create object bitmap
if Objects[obj].Tag='FBOX' then
begin
Objmap := TBitmap.Create;
Objmap.Width:=area;
Objmap.height:=area;
Objmap.Transparent:=true;
Objmap.Canvas.Rectangle((objects[obj].Boundleft-4)+objects[obj].Position.x,area-((objects[obj].boundtop+4)+objects[obj].Position.y),(objects[obj].boundright+4)+objects[obj].Position.x,area-((objects[obj].boundbottom-4)+objects[obj].Position.y));
end;
//draw object
LineLength:=length(objects[Obj].Lines)-1;
angle:=objects[Obj].Rotation;
for lin:=0 to (LineLength) do
begin
for i:=0 to 1 do
begin
Npoints[i] := PointAddition(RotatePoint(objects[obj].Lines[lin].Point[i],angle),objects[obj].Position,false);
end;
Objmap:=DrawLine(Npoints[0].x,Npoints[0].y,Npoints[1].x,Npoints[1].y,objects[obj].Lines[lin].Color,Objmap);
end;
Filllength:=length(objects[Obj].Fills)-1;
for i:=0 to Filllength do
begin
Npoints[0]:=PointAddition(RotatePoint(objects[Obj].Fills[i].Point,objects[Obj].Rotation),objects[Obj].Position,false);
Objmap:=fillpoint( Npoints[0].x, Npoints[0].y,objects[Obj].Fills[i].color,Objmap);
end;
//write object to step frame
wholemap.Canvas.Draw(0,0,Objmap);
Objmap.Free;
end;
// write step frame to Visible Canvas
mainwindow.bufferim.Canvas.Draw(0,0,wholemap);
mainwindow.RobotArea.Picture.Graphic:=mainwindow.bufferim.Picture.Graphic;
wholemap.Free;
end;
WHAT I EXPECT
I expect to see each image object layered on top of one another with each image layer being the complete image for that layer.
im my example it is a robot with a flag behind it.
the flag is drawn first and then the robot.
WHAT I GET(on a pc)
on a pc i get what i expect and all appears to be correct.
WHAT I GET(on a laptop)
On a nearly every laptop and some pc's i only see the robot.
i put in some statments to see if it is drawing the flag and it does. the game can even interact with the flag in the correct manner.
further investigation showed me that it was only showing the last image drawn my "drawscene", and when images were drawn directly to the wholecanvas everthing apeared(this cannot be done for overlapping fill layers reasons)
WHAT I THINK IS HAPPENING
so what i deduced is that the Timage.transparent property of the Timage is not working or is being computed differently on some machines..
i did a test to prove this and made a canvas red. then to that canvas i drew at 0,0 i Timage with property transparent=true with just one dot in the middle to the red canvas. the resuly was a white canvas with a dot in the middle.
I am assuming and findings indicate that machines with very basic graphics drivers seem to treat null or transparent as white where as more powerful machines seem to treat null or transparent as transparent.
this seems to be a bit of a failure due to the fact that the Timage.Transparent property was true.
EDIT:
UPDATE!!!
It would appear to be that on ATI graphics cards if a colour is "null" then it is interpreted in the format of PF24bit and therefore no alpha channel and no transparency.
on Nvidia cards it takes it as PF32bit and treats null as transparent.
the obvious way to get around that woulf be to set the bitmaptype to PF32bit, but that does still not work.
I then assumed that maybe that is not enough and I should make sure that the background is SET to transparent rather than being left as null.. but there are no tools ( that I can see) inside the Timage to set colour with alpha. all canvas drawing functions require a Tcolor that is RGB 24 bit and ony a TcolorRef with RGBA 32 bit would do....
is there a way of drawing with alpha 0?
WHAT I THINK I NEED TO KNOW
How to force the Transparent property to work on all machines
or a way to make laptops not paste in transparent as white
Or a way to achieve the same result.
Anyone have any solutions or ideas?
I have been using an Graphics library (AggPas) to help with drawing graphics and one of the things I've noticed is that I always need a line Bitmap.PixelFormat = pf32bit to get it to draw transparancies.
Having said that I use TransformImage from the AggPas library to copy the Image with a transparent background to another one and AggPas only accepts pf24bit or pf32bits as Pixel formats (otherwise it doesn't attach to the bitmap)
I've seen similar behaviour on different machines in the past (a few years back).
They were caused by different video cards and drivers.
Either the NVideo or the ATI ones were getting the wrong results, but I forgot which ones.
It could be reproduced on both laptops and regular PC's.
So: what video cards and drivers do you use?
--jeroen
I would explicitly set the bitmap format to pf32bit for each bitmap you create to ensure the problem isnt converting colors from 32 to 16 bit (if thats the native video resolution of the bitmaps getting created), which might interfere with how the transparency works. Also, I've had better luck specifically setting the transparency color in the past.
Another option - perhaps a better one in the long run, is to instead set the Alpha Channel on the images (ie, use PNG files), and use the GDI function AlphaBlend() to draw the graphics.

Resources