Sign in Join

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

Mailing lists / lazarus / 2008-02

fpimage use of Lazarus

19 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

Marco van de Voort

I post this msg because I see fpimage units used in Lazarus' graphics unit. I plan to enhance tmemoryimage with scanline support, and adapt the readers and writers.

The consequences are:
- standard fpimage readers and writers might get extra methods for tmemoryimages. There might be an extra inheritance level involved. (if img is TMemory then)
- tmemoryimage internal representation changes (and won't be always 4 bytes per pixel), lowering mem usage somewhat for lower bpp pictures.

For now I'm only playing ad exploring, and even if I start to get serious, it will be a no panic and running for the door please :-)

Does sb know on what fpimage properties lazarus exactly depends?

I now have the feeling the readers, writers and canvas are used but not the core image classes itself (tfpcustomimage)?

Are there hidden assumptions on internal format (mostly being it always 32bpp?)

Reply by email

Mattias Gaertner
to Marco van de Voort
Show quoted text 11 lines
I post this msg because I see fpimage units used in Lazarus' graphics unit. I plan to enhance tmemoryimage with scanline support, and adapt the readers and writers. The consequences are: - standard fpimage readers and writers might get extra methods for tmemoryimages. There might be an extra inheritance level involved. (if img is TMemory then) - tmemoryimage internal representation changes (and won't be always 4 bytes per pixel), lowering mem usage somewhat for lower bpp pictures.

Sounds like what TLazIntfImage is doing. It maps Get/SetColor to a memory image pixel format. See graphtype.pp TRawImageDescription for supported formats.

Show quoted text 5 lines
For now I'm only playing ad exploring, and even if I start to get serious, it will be a no panic and running for the door please :-) Does sb know on what fpimage properties lazarus exactly depends?

If you mean TFPCustomImage: Almost every property. The Extra* properties are used only by some readers/writers that are used by the LCL. So this is an indirect dependency.

I now have the feeling the readers, writers and canvas are used but not the core image classes itself (tfpcustomimage)?

TLazIntfImage = class(TFPCustomImage)

Are there hidden assumptions on internal format (mostly being it always 32bpp?)

I didn't even know that fpimage has an internal format.

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner
Mattias Gaertner wrote 8 lines
> tmemoryimages. There might be an extra inheritance level involved. > (if img is TMemory then) > - tmemoryimage internal representation changes (and won't be always 4 > bytes per pixel), lowering mem usage somewhat for lower bpp pictures. Sounds like what TLazIntfImage is doing. It maps Get/SetColor to a memory image pixel format. See graphtype.pp TRawImageDescription for supported formats.

Ok, will check it out.

Show quoted text 16 lines
> For now I'm only playing ad exploring, and even if I start to get > serious, it will be a no panic and running for > the door please :-) > > Does sb know on what fpimage properties lazarus exactly depends? If you mean TFPCustomImage: Almost every property. The Extra* properties are used only by some readers/writers that are used by the LCL. So this is an indirect dependency. TLazIntfImage = class(TFPCustomImage) > Are there hidden assumptions on internal format (mostly being it > always 32bpp?) I didn't even know that fpimage has an internal format.

Depends on what you see as fpimage. TFPCustomImage is the abstract ancestor, TFPMemoryImage the one with actual storage.

In this context one should also see my "which properties" question. If I expand TFPMemoryImage with scanline (because it has storage), I couldn't use it in the readers or writers, because then they wouldn't work anymore with tlazintfimage. So more or less you confirmed my doubts, Lazarus is not using TFPMemoryImage.

So probably the ancestor class should get a scanline property with some abstract methods, and TLazIntfImage needs to override that too.

Reply by email

Mattias Gaertner
to Marco van de Voort
Show quoted text 20 lines
[...] > > For now I'm only playing ad exploring, and even if I start to get > > serious, it will be a no panic and running for > > the door please :-) > > > > Does sb know on what fpimage properties lazarus exactly depends? > > If you mean TFPCustomImage: Almost every property. The Extra* > properties are used only by some readers/writers that are used by > the LCL. So this is an indirect dependency. > TLazIntfImage = class(TFPCustomImage) > > > Are there hidden assumptions on internal format (mostly being it > > always 32bpp?) > > I didn't even know that fpimage has an internal format. Depends on what you see as fpimage. TFPCustomImage is the abstract ancestor, TFPMemoryImage the one with actual storage.

I see.

Show quoted text 5 lines
In this context one should also see my "which properties" question. If I expand TFPMemoryImage with scanline (because it has storage), I couldn't use it in the readers or writers, because then they wouldn't work anymore with tlazintfimage. So more or less you confirmed my doubts, Lazarus is not using TFPMemoryImage.

Correct. TFPMemoryImage knows only one format. The LCL needs a flexible one, that supports at least all memory formats of all widgetsets - which afaik excludes only compressed and floating point memory formats.

So probably the ancestor class should get a scanline property with some abstract methods, and TLazIntfImage needs to override that too.

TLazIntfImage.GetDataLineStart?

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner
Mattias Gaertner wrote 15 lines
Marco van de Voort wrote: > In this context one should also see my "which properties" question. > If I expand TFPMemoryImage with scanline (because it has storage), I > couldn't use it in the readers or writers, because then they wouldn't > work anymore with tlazintfimage. So more or less you confirmed my > doubts, Lazarus is not using TFPMemoryImage. Correct. TFPMemoryImage knows only one format. The LCL needs a flexible one, that supports at least all memory formats of all widgetsets - which afaik excludes only compressed and floating point memory formats. > So probably the ancestor class should get a scanline property with > some abstract methods, and TLazIntfImage needs to override that too. TLazIntfImage.GetDataLineStart?
Exactly. Maybe a scanline property:
  property scanline[row:integer]:pointer  read getdatalinestart;

This is how I got so far:

- TFPCustomImage gets an scanline /getdatalinestart pointer that can get the address of the first pixel per scanline. The Lazarus derivative already has something like that, so I propose to use that function name.
- When reading, a reader must determine the bitcount per pixel (bpp), and pass it to an abstract virtual TFPCustomImage method which returns the actual bpp to be used. (the increment needed to get from (0,row) to (n,row). This allows one and the same reader/writer with different internal representations and supported bpp counts. Working title for this function is supportbpp.
- The above supportbpp call (which must happen before the definitive setsize) is the only thing that changes for existing pixel property based reader to be compatible with also newer customimages.
- The old situation (using existing readers/writers with existing tfpcustomimages remains the same.
- Since this is possible, I also leave TMemoryImage alone for compat, and make a new class for more efficient purposes. It only gets the scanline support added, but always returns 32bpp as bitcount.
- Anyone accessing scanline must check the bpp property to determine the granularity.
- I'm still thinking about a property that signals scanline support. This would allow readers/writers to fall back to pixels for special customimages that don't support scanline.

So in short, scanline support is added with as only compat limitation that a reader must pass on the bitcount before the main setsize. This avoids the current situation that the image must allocate for the worst case situation. Other changes only need fixing in existing fpimage usage if you really want to use newer features.

This also allows me to fiddle around without hurting Lazarus too much, and confirm that the scheme works with the existing supported formats.

In general it allows to speed up relative basic readers and writers a magnitude (from pixel to row based) at the expense of more code in reader/writer, but that is not forced. E.g. one could only optimize certain many used cases of a graph format like this, and leave the oddball options to the existing reader. It also allows image formats to not allocate the worst case amount of mem (maxbpp*rowsize*height).

Reply by email

Marco van de Voort
to Marco van de Voort

On Sat, Feb 16, 2008 at 05:35:13PM +0100, Marco van de Voort wrote:

Addition to self:

I've studied intfgraphics some more and my scheme means that maybe some lazarus specific tricks need less lazarus specific implementation

The lazarus fpcustomimage derivative can communicate with the reader via the supportbmp the results of bpp for getDescriptionFromDevice(0).

It seems the description is mainly about

function BytesPerLine: PtrUInt;
function BitsPerLine: PtrUInt;
function MaskBytesPerLine: PtrUInt;
function MaskBitsPerLine: PtrUInt;

mask support is not needed in bpp. Bytesperline is probably a similar crucial param as bpp, so I propose to pull this into fpimage too. (supports (var bpp, var bytesperline));

Long term, maybe the lazarus specific part gets a bit thinner then, and properly refactored between general usable and not. Maybe a precursor of the laz xpm/bmp readers (with custom "tree" pallete) could go into fpimage, and keep descendants with the more lazarus specific bits in lcl.

Reply by email

Mattias Gaertner
to Marco van de Voort: Exactly. Maybe a scanline property: property scanline[row:integer]:pointer read…
Show quoted text 66 lines
On Sat, Feb 16, 2008 at 02:32:24PM +0100, Mattias Gaertner wrote: > Marco van de Voort wrote: > > In this context one should also see my "which properties" > > question. If I expand TFPMemoryImage with scanline (because it > > has storage), I couldn't use it in the readers or writers, > > because then they wouldn't work anymore with tlazintfimage. So > > more or less you confirmed my doubts, Lazarus is not using > > TFPMemoryImage. > > Correct. TFPMemoryImage knows only one format. The LCL needs a > flexible one, that supports at least all memory formats of all > widgetsets - which afaik excludes only compressed and floating > point memory formats. > > So probably the ancestor class should get a scanline property with > > some abstract methods, and TLazIntfImage needs to override that > > too. > > TLazIntfImage.GetDataLineStart? Exactly. Maybe a scanline property: property scanline[row:integer]:pointer read getdatalinestart; This is how I got so far: - TFPCustomImage gets an scanline /getdatalinestart pointer that can get the address of the first pixel per scanline. The Lazarus derivative already has something like that, so I propose to use that function name. - When reading, a reader must determine the bitcount per pixel (bpp), and pass it to an abstract virtual TFPCustomImage method which returns the actual bpp to be used. (the increment needed to get from (0,row) to (n,row). This allows one and the same reader/writer with different internal representations and supported bpp counts. Working title for this function is supportbpp. - The above supportbpp call (which must happen before the definitive setsize) is the only thing that changes for existing pixel property based reader to be compatible with also newer customimages. - The old situation (using existing readers/writers with existing tfpcustomimages remains the same. - Since this is possible, I also leave TMemoryImage alone for compat, and make a new class for more efficient purposes. It only gets the scanline support added, but always returns 32bpp as bitcount. - Anyone accessing scanline must check the bpp property to determine the granularity. - I'm still thinking about a property that signals scanline support. This would allow readers/writers to fall back to pixels for special customimages that don't support scanline. So in short, scanline support is added with as only compat limitation that a reader must pass on the bitcount before the main setsize. This avoids the current situation that the image must allocate for the worst case situation. Other changes only need fixing in existing fpimage usage if you really want to use newer features. This also allows me to fiddle around without hurting Lazarus too much, and confirm that the scheme works with the existing supported formats. In general it allows to speed up relative basic readers and writers a magnitude (from pixel to row based) at the expense of more code in reader/writer, but that is not forced. E.g. one could only optimize certain many used cases of a graph format like this, and leave the oddball options to the existing reader. It also allows image formats to not allocate the worst case amount of mem (maxbpp*rowsize*height).

You only mention bpp. What about the other 14 properties to describe a row?

Mattias

Reply by email

Mattias Gaertner
to Marco van de Voort: Addition to self: I've studied intfgraphics some more and my scheme means that maybe some…
Show quoted text 6 lines
On Sat, Feb 16, 2008 at 05:35:13PM +0100, Marco van de Voort wrote: Addition to self: I've studied intfgraphics some more and my scheme means that maybe some lazarus specific tricks need less lazarus specific implementation

Great.
What tricks?
Keep in mind that the goal of TLazIntfImage is to eventually access directly the widgetset images instead of copies. Of course this can only work on some widgetsets.

Show quoted text 13 lines
The lazarus fpcustomimage derivative can communicate with the reader via the supportbmp the results of bpp for getDescriptionFromDevice(0). It seems the description is mainly about function BytesPerLine: PtrUInt; function BitsPerLine: PtrUInt; function MaskBytesPerLine: PtrUInt; function MaskBitsPerLine: PtrUInt; mask support is not needed in bpp. Bytesperline is probably a similar crucial param as bpp, so I propose to pull this into fpimage too. (supports (var bpp, var bytesperline));

I still wonder what happen to the other properties, like depth, bit order, rgb order, alpha depth, etc.

Show quoted text 5 lines
Long term, maybe the lazarus specific part gets a bit thinner then, and properly refactored between general usable and not. Maybe a precursor of the laz xpm/bmp readers (with custom "tree" pallete) could go into fpimage, and keep descendants with the more lazarus specific bits in lcl.

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner: On Sat, 16 Feb 2008 17:35:13 +0100 You only mention bpp. What about the other 14…
Mattias Gaertner wrote 6 lines
> certain many used cases of a graph format like this, and leave the > oddball options to the existing reader. It also allows image formats > to not allocate the worst case amount of mem (maxbpp*rowsize*height). You only mention bpp. What about the other 14 properties to describe a row?

They don't affect allocation and iteration over them. Thus not needed for scanline access.

Reply by email

Marco van de Voort
to Mattias Gaertner: On Sat, 16 Feb 2008 18:33:43 +0100 Great. What tricks? Keep in mind that the goal of…
Mattias Gaertner wrote 12 lines
> On Sat, Feb 16, 2008 at 05:35:13PM +0100, Marco van de Voort wrote: > > Addition to self: > > I've studied intfgraphics some more and my scheme means that maybe > some lazarus specific tricks need less lazarus specific implementation Great. What tricks? Keep in mind that the goal of TLazIntfImage is to eventually access directly the widgetset images instead of copies. Of course this can only work on some widgetsets.

Well, it is partially exactly like that. It just pulls the defining parameters (width, height, bpp, rowpitch (aka bytes per row) of the storage requirements into the abstract class. Not the storage itself.

If the storage of a native type can be descibed like that, a laz specific image can still store in the native struc, but use the normal readers and writers.

So to summon up, the storage properties and assumptions are:

1. width + height in pixels
2. size of a pixel in bits. If pixels are non packed (24-bits stored as 32-bit), this is about the _actual_ storage value, so 32-bit.
3. size per row in bytes or pixels. (alignment reasons) I'm used to pixels, but maybe bytes is better.
4. If one has the address of the first pixel of a row, the address of the next pixel can be calculated by adding the amount of bits. (bitpacking into account)
5. a property that signals if 1..4 hold true. If not the reader/write must revert to the current (pixel based) behaviour.

The 4th condition goes wrong if e.g. byte arrays are stored as integer arrays on little endian systems, then you get

b3 b2 b1 b0 b7 b6 b5 b4 ... etc.

I don't know if there are fileformats who do this (hope not), but if they do, it is the readers responsibility to revert to "per pixel" addressing via the pixels property.

I'm thinking about adding a property that signals if you can jump between rows by adding a fixed amount of bytes (usually bytesperrow, but maybe negative). But I'm not doing that until I at least have implemented the above.

Show quoted text 6 lines
> mask support is not needed in bpp. Bytesperline is probably a similar > crucial param as bpp, so I propose to pull this into fpimage too. > (supports (var bpp, var bytesperline)); I still wonder what happen to the other properties, like depth, bit order, rgb order, alpha depth, etc.

Those are all to interpret pixel data (depending on what you mean by depth). Not to extract or allocate storage.

Note that this is all still just about the pixel data.

One of the reasons that laz has own readers and writers seem to be palettes. I'm still investigating that. This is all just in the "sparring and brainstorming" stage.

Reply by email

Mattias Gaertner
to Marco van de Voort: They don't affect allocation and iteration over them. Thus not needed for scanline access.
Show quoted text 11 lines
On Sat, Feb 16, 2008 at 06:54:58PM +0100, Mattias Gaertner wrote: > > certain many used cases of a graph format like this, and leave the > > oddball options to the existing reader. It also allows image > > formats to not allocate the worst case amount of mem > > (maxbpp*rowsize*height). > > You only mention bpp. What about the other 14 properties to > describe a row? They don't affect allocation and iteration over them. Thus not needed for scanline access.

Does that mean, the readers/writers must implement the access themselves for all possible formats?

Mattias

Reply by email

Mattias Gaertner
to Marco van de Voort: Well, it is partially exactly like that. It just pulls the defining parameters (width,…
Show quoted text 60 lines
On Sat, Feb 16, 2008 at 07:15:05PM +0100, Mattias Gaertner wrote: > > On Sat, Feb 16, 2008 at 05:35:13PM +0100, Marco van de Voort > > wrote: > > > > Addition to self: > > > > I've studied intfgraphics some more and my scheme means that maybe > > some lazarus specific tricks need less lazarus specific > > implementation > > Great. > What tricks? > Keep in mind that the goal of TLazIntfImage is to eventually access > directly the widgetset images instead of copies. Of course this can > only work on some widgetsets. Well, it is partially exactly like that. It just pulls the defining parameters (width, height, bpp, rowpitch (aka bytes per row) of the storage requirements into the abstract class. Not the storage itself. If the storage of a native type can be descibed like that, a laz specific image can still store in the native struc, but use the normal readers and writers. So to summon up, the storage properties and assumptions are: 1. width + height in pixels 2. size of a pixel in bits. If pixels are non packed (24-bits stored as 32-bit), this is about the _actual_ storage value, so 32-bit. 3. size per row in bytes or pixels. (alignment reasons) I'm used to pixels, but maybe bytes is better. 4. If one has the address of the first pixel of a row, the address of the next pixel can be calculated by adding the amount of bits. (bitpacking into account) 5. a property that signals if 1..4 hold true. If not the reader/write must revert to the current (pixel based) behaviour. The 4th condition goes wrong if e.g. byte arrays are stored as integer arrays on little endian systems, then you get b3 b2 b1 b0 b7 b6 b5 b4 ... etc. I don't know if there are fileformats who do this (hope not), but if they do, it is the readers responsibility to revert to "per pixel" addressing via the pixels property. I'm thinking about adding a property that signals if you can jump between rows by adding a fixed amount of bytes (usually bytesperrow, but maybe negative). But I'm not doing that until I at least have implemented the above. > > mask support is not needed in bpp. Bytesperline is probably a > > similar crucial param as bpp, so I propose to pull this into > > fpimage too. (supports (var bpp, var bytesperline)); > > I still wonder what happen to the other properties, like depth, bit > order, rgb order, alpha depth, etc. Those are all to interpret pixel data (depending on what you mean by depth). Not to extract or allocate storage.

Does this mean every function that uses scanline must support all these things? OR it allocates an image in a 32bit format and later the whole image is converted to the needed format.

Show quoted text 5 lines
Note that this is all still just about the pixel data. One of the reasons that laz has own readers and writers seem to be palettes. I'm still investigating that. This is all just in the "sparring and brainstorming" stage.

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner: On Sat, 16 Feb 2008 20:07:51 +0100 Does that mean, the readers/writers must implement the…
Mattias Gaertner wrote 15 lines
> On Sat, Feb 16, 2008 at 06:54:58PM +0100, Mattias Gaertner wrote: > > > certain many used cases of a graph format like this, and leave the > > > oddball options to the existing reader. It also allows image > > > formats to not allocate the worst case amount of mem > > > (maxbpp*rowsize*height). > > > > You only mention bpp. What about the other 14 properties to > > describe a row? > > They don't affect allocation and iteration over them. Thus not needed > for scanline access. Does that mean, the readers/writers must implement the access themselves for all possible formats?

Don't they already ? pixels property is only an integer.

Reply by email

Marco van de Voort
to Mattias Gaertner: On Sat, 16 Feb 2008 20:49:57 +0100 Does this mean every function that uses scanline must…
Mattias Gaertner wrote 6 lines
> > Those are all to interpret pixel data (depending on what you mean by > depth). Not to extract or allocate storage. Does this mean every function that uses scanline must support all these things?

Yes, of course. But it is already the same now for the pixel format. But keep in mind that readers can decrease the number of formats by converting lesser used ones to more typical ones.

Note that a similar scheme as what I suggest for the storage requirements can be applied to pixel encoding too, in e.g. a TFPCustomImage descendant. The reader says "I have found CMY pixels" and the image says "I only support RGB" so the reader has to convert. And the image can be called TRGBImage.

OR it allocates an image in a 32bit format and later the whole image is converted to the needed format.

That is possible. In that case the img always returns "32" if the reader says he found "16". That's the reason the supports(bpp,bytesperline) has var parameters. It is more or less the reader saying what it finds in the file, and the image saying what storage form matches, without only forcing one size fits all.

Keep in mind that while 32-bit pixels have been a realistic max for a long time, but it won't last forever, and afaik the first 10 en 12 bits per color displays are starting to appear (but still very expensive). It is only a matter of time before OSes start to support it.

Reply by email

Mattias Gaertner
to Marco van de Voort: Don't they already ? pixels property is only an integer.
Show quoted text 18 lines
On Sat, Feb 16, 2008 at 09:12:16PM +0100, Mattias Gaertner wrote: > > > On Sat, Feb 16, 2008 at 06:54:58PM +0100, Mattias Gaertner wrote: > > > > certain many used cases of a graph format like this, and > > > > leave the oddball options to the existing reader. It also > > > > allows image formats to not allocate the worst case amount of > > > > mem (maxbpp*rowsize*height). > > > > > > You only mention bpp. What about the other 14 properties to > > > describe a row? > > > > They don't affect allocation and iteration over them. Thus not > > needed for scanline access. > > Does that mean, the readers/writers must implement the access > themselves for all possible formats? Don't they already ?
No. The readers/writers just use Colors[x,y]:=someTFPColor.
TLazIntfImage will do the conversion.
pixels property is only an integer.

Pixels is the palette value. The Colors property takes a TFPColor.

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner
Mattias Gaertner wrote 7 lines
> > Does that mean, the readers/writers must implement the access > > themselves for all possible formats? > > Don't they already ? No. The readers/writers just use Colors[x,y]:=someTFPColor. TLazIntfImage will do the conversion.

Assuming it is paletted yes. I still have to investigate the palette stuff, so that is not touched for now.

> pixels property is only an integer. Pixels is the palette value. The Colors property takes a TFPColor.

Yes, colors use 64 bit RGBA. But I'm not touching that yet. Though I'd like to make that a bit more pluggable too, in time.

Reply by email

Mattias Gaertner
to Marco van de Voort
Show quoted text 11 lines
On Sat, Feb 16, 2008 at 11:29:40PM +0100, Mattias Gaertner wrote: > > > Does that mean, the readers/writers must implement the access > > > themselves for all possible formats? > > > > Don't they already ? > > No. The readers/writers just use Colors[x,y]:=someTFPColor. > TLazIntfImage will do the conversion. Assuming it is paletted yes. I still have to investigate the palette stuff, so that is not touched for now.

I can't follow you here. I was talking about the pixel formats, not palette.

Show quoted text 6 lines
> > pixels property is only an integer. > > Pixels is the palette value. The Colors property takes a TFPColor. Yes, colors use 64 bit RGBA. But I'm not touching that yet. Though I'd like to make that a bit more pluggable too, in time.

Ok.

Mattias

Reply by email

Marco van de Voort
to Mattias Gaertner
Mattias Gaertner wrote 13 lines
> > > > Does that mean, the readers/writers must implement the access > > > > themselves for all possible formats? > > > > > > Don't they already ? > > > > No. The readers/writers just use Colors[x,y]:=someTFPColor. > > TLazIntfImage will do the conversion. > > Assuming it is paletted yes. I still have to investigate the palette > stuff, so that is not touched for now. I can't follow you here. I was talking about the pixel formats, not palette.

I'm talking about retrieving a pointer to the pixels, and the readers/writers being able to.

So that lines as

  with PFourBytes(FRawImage.Data+FLineStarts^.Positions[y].Byte+(x shl 2))^ do

are wrapped.

IOW I pull part of the rawimage storage into a descendant of fpimage, (the base, not the more baroque parts) and add the ability for the readers and writers to _optionally_ use this. This all backwards compatible.

> > Pixels is the palette value. The Colors property takes a TFPColor.

Pixels is the information stored per pixel. What I plan is about reading and writing that row based. If I'm going to also handle the conversions, I'll do that in a descendant, to avoid biass for e.g. a RGBA color system in a base class.

Reply by email