Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2018-04

A bitmap strange issue

11 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Luca Olivetti
to Giuliano Colla

El 21/04/18 a les 17:18, Giuliano Colla via Lazarus ha escrit:

Show quoted text 6 lines
Here's a snippet of code used to show the issue: > procedure TForm1.Button1Click(Sender: TObject); var Filename: String; > begin if OpenPictureDialog1.Execute then begin // MyBitmap := > Image1.Picture.Bitmap; <-------This causes a sigsev in FreeImage

If you follow the implementation of Image1.Picture.LoadFromFile you'll see that it frees the current bitmap, that's the cause of the sigsev. If you want to save the bitmap for later use, you should probably make a copy instead.

Show quoted text 10 lines
> Filename:= OpenPictureDialog1.FileName; > Image1.Picture.LoadFromFile(Filename); If assigned(MyBitmap) then > begin MyBitmap.FreeImage; FreeAndNil(MyBitmap); end; end; end; > procedure TForm1.Button2Click(Sender: TObject); begin If not > Assigned(MyBitmap) then MyBitmap:= TBitmap.Create; MyBitmap.Width:= > Image1.Width; MyBitmap.Height:= Image1.Height; > MyBitmap.Canvas.Brush.Color:= clNavy; MyBitmap.Canvas.Brush.Style:= > bsSolid; > MyBitmap.Canvas.FillRect(0,0,MyBitmap.Width,MyBitmap.Height); > Image1.Picture.Bitmap := MyBitmap;

And this assignment makes a copy of MyBitmap

> //MyBitmap.FreeImage; Useless FreeAndNil(MyBitmap); end;

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Vojtěch Čihák

Hi,
 
@ MyBitmap := Image1.Picture.Bitmap;
This line only copies pointer, but Image1.Picture.Bitmap belongs to Image1 and it should care itself. If you need copy of the bitmap you shoud use:
MyBitmap.Assign(Image1.Picture.Bitmap);
 
V.
 

Reply by email

Giuliano Colla
to Vojtěch Čihák

Il 21/04/2018 18:07, Vojtěch Čihák via Lazarus ha scritto:

Show quoted text 5 lines
@ MyBitmap := Image1.Picture.Bitmap; This line only copies pointer, but Image1.Picture.Bitmap belongs to Image1 and it should care itself.

That's what I had guessed, but this means that there's a patent inconsistency, as shown in the Button2Click part of my test:

Image1.Picture.Bitmap := MyBitmap; FreeAndNil(MyBitmap);

doesn't generate any error. If I don't free MyBitmap I see a memory leakage in heaptrc.

IOW

Image1.Picture.Bitmap := MyBitmap;

performs an implicit assign, creating a new Bitmap Object for Image1.

The apparently symmetrical

MyBitmap := Image1.Picture.Bitmap;

just copies the pointer. Timage.Picture.GetBitmap and TImage.Picture.SetBitmap do not follow the same logic.

All of this is maybe somewhat Delphi compatible. Actually Delphi (Rad Studio 10.1) doesn't generate a SIGSEV with the same code, but rather just an "Illegal Pointer Operation" warning. However IMO it still remains quite inconsistent.

Giuliano

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20180422/b1c265e3/attachment.html>

Reply by email

Michael Van Canneyt
to Giuliano Colla
Giuliano Colla wrote 25 lines
Il 21/04/2018 18:07, Vojtěch Čihák via Lazarus ha scritto: > @ MyBitmap := Image1.Picture.Bitmap; > > This line only copies pointer, but Image1.Picture.Bitmap belongs to Image1 > and it should care itself. > That's what I had guessed, but this means that there's a patent inconsistency, as shown in the Button2Click part of my test: > Image1.Picture.Bitmap := MyBitmap; FreeAndNil(MyBitmap); doesn't generate any error. If I don't free MyBitmap I see a memory leakage in heaptrc. IOW Image1.Picture.Bitmap := MyBitmap; performs an implicit assign, creating a new Bitmap Object for Image1. The apparently symmetrical MyBitmap := Image1.Picture.Bitmap;

This is how all properties that are TPersistent descendents work, so this behaviour should not come as a surprise.

Michael.

Reply by email

Ondrej Pokorny
to Giuliano Colla: Il 21/04/2018 18:07, Vojtěch Čihák via Lazarus ha scritto: That's what I had guessed,…
Giuliano Colla wrote 23 lines
Il 21/04/2018 18:07, Vojtěch Čihák via Lazarus ha scritto: > @ MyBitmap := Image1.Picture.Bitmap; > > This line only copies pointer, but Image1.Picture.Bitmap belongs to > Image1 and it should care itself. > That's what I had guessed, but this means that there's a patent inconsistency, as shown in the Button2Click part of my test: > Image1.Picture.Bitmap := MyBitmap; FreeAndNil(MyBitmap); doesn't generate any error. If I don't free MyBitmap I see a memory leakage in heaptrc. IOW Image1.Picture.Bitmap := MyBitmap; performs an implicit assign, creating a new Bitmap Object for Image1. The apparently symmetrical MyBitmap := Image1.Picture.Bitmap; just copies the pointer. Timage.Picture.GetBitmap and TImage.Picture.SetBitmap do not follow the same logic.
Do you really mean that
Image1.Picture.Bitmap.SomeProperty := SomeValue;
should apply SomeProperty := SomeValue on a copied object of Bitmap and
produce a memory leak?

And the same, that
Image1.Picture.Bitmap := Image2.Picture.Bitmap;
should produce a memory leak because of the temporary bitmap object?

...and taking it into detail because Picture is a property of TImage as well:
Image1.Picture.Bitmap := Image2.Picture.Bitmap;
would actually produce 3 memory leaks: 2x TPicture and 1x TBitmap.

Ondrej
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20180422/030e0b46/attachment.html>

Reply by email

Giuliano Colla
to Ondrej Pokorny

Il 22/04/2018 13:49, Ondrej Pokorny via Lazarus ha scritto:

Do you really mean that Image1.Picture.Bitmap.SomeProperty := SomeValue; should apply SomeProperty := SomeValue on a copied object of Bitmap and produce a memory leak?

No, I mean that like

Image1.Picture.Bitmap := SomeBitmap;

actually executes a

Image1.Picture.Bitmap.assign(SomeBitmap);

(see TPicture.SetGraphic called by TPicture.SetBitmap in picture.inc), so

SomeBitmap := Image1.Picture.BItmap;

should execute (with proper checks)

SomeBitmap.assign(Image1.Picture.Bitmap);

I speak about manipulating the Tpicture.Bitmap property itself, not the TBitmap properties, which would not be affected.

Giuliano

Reply by email

Giuliano Colla
to Michael Van Canneyt: This is how all properties that are TPersistent descendents work, so this behaviour…

Il 22/04/2018 13:22, Michael Van Canneyt via Lazarus ha scritto:

This is how all properties that are  TPersistent descendents work, so this behaviour should not come as a surprise.

I wouldn't say so.

E.g. TCanvas is a TPersistent descendent, but the Canvas property of a TCustomControl is declared like that:

    property Canvas: TCanvas read FCanvas write FCanvas;

This means that after a

SomeControl.Canvas := MyCanvas;

or

MyCanvas := SomeControl.Canvas;

SomeControl.Canvas and MyCanvas will be the same object. Only a pointer is copied.

On the contrary, the property Bitmap of a TPicture is declare like that:

    property Bitmap: TBitmap read GetBitmap write SetBitmap;

where GetBitmap actually returns the TPicture.Bitmap Object, while SetBitmap creates a different Bitmap Object, and assigns it the content of the supplied bitmap (see TPicture.SetGraphic, called by TPicture.SetBitmap).

This means that after a

MyBitmap := SomePicture.Bitmap;

MyBitmap and SomePicture.Bitmap will represent the same Object, while after a

SomePicture.Bitmap := MyBitmap;

MyBitmap and SomePicture.Bitmap will represent different Objects.

This is IMHO a TPicture specific inconsistency.

Giuliano

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20180422/3ce63141/attachment.html>

Reply by email

Giuliano Colla
to Mattias Gaertner

Il 22/04/2018 17:39, Mattias Gaertner via Lazarus ha scritto:

And what to do with W := Image1.Picture.BItmap.Width?

You're right, there's no easy way out.

The original sin has been maybe to call Bitmap a TPicture property which isn't really a TBitmap, as the GetBitmap and SetBitmap methods show. This makes it easy to put any image into a picture, but creates unavoidable inconsistencies.

Giuliano

Reply by email

Ondrej Pokorny
to Giuliano Colla: Il 22/04/2018 13:49, Ondrej Pokorny via Lazarus ha scritto: No, I mean that like…
Giuliano Colla wrote 22 lines
Il 22/04/2018 13:49, Ondrej Pokorny via Lazarus ha scritto: > Do you really mean that > Image1.Picture.Bitmap.SomeProperty := SomeValue; > should apply SomeProperty := SomeValue on a copied object of Bitmap > and produce a memory leak? No, I mean that like Image1.Picture.Bitmap := SomeBitmap; actually executes a Image1.Picture.Bitmap.assign(SomeBitmap); (see TPicture.SetGraphic called by TPicture.SetBitmap in picture.inc), so SomeBitmap := Image1.Picture.BItmap; should execute (with proper checks) SomeBitmap.assign(Image1.Picture.Bitmap);

You can definitely do this - but not on on the Image1.Picture side and on the other side - SomeBitmap:

property SomeBitmap: TBitmap read GetSomeBitmap write SetSomeBitmap;

-> implement SetSomeBitmap to execute .Assign() and you are good.

Ondrej

Reply by email