Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PNG Library #817

Open
wants to merge 195 commits into
base: master
Choose a base branch
from
Open

PNG Library #817

wants to merge 195 commits into from

Conversation

HubertHuckevoll
Copy link
Collaborator

@HubertHuckevoll HubertHuckevoll commented Jan 26, 2025

This PR adds a simple, mostly AI generated PNG (Import) Library to the PC/GEOS system, therefore partly resolving issue #184 . The most commonly used format specifications are supported. Creating this lib was only possible due to the fact that @rabe-soft ported the zlib library long ago.

Not supported are PNG "background"- and "transparency"-chunks as well as interlaced PNGs. Image width is currently limited to some ~1600 pixels. This may change with the upcoming protected mode support.

At the moment, the PNG support is limited to importing images in the "Graphics Viewer" app and the ImpGraph library (Browser).

@HubertHuckevoll HubertHuckevoll changed the title Pngtst6 PNG Library Jan 26, 2025
Copy link
Collaborator

@mgroeber9110 mgroeber9110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First batch of comments to look at... still for me to look at:

  • Core PNG library code
  • Progressive loading vs. loading from file: how can we make sure that the PNG import always gets the fully downloaded file, rather than a streaming interface?

s->windowReadOffs = ((word) s->read) - ((word) s->window); \
s->windowWriteOffs = ((word) s->write) - ((word) s->window); \
MemUnlock(s->windowHan); \
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it makes sense to add some EC code here that e.g. sets the window ptr to NULL when it is unlocked, and asserts that it is null when locking (just so there is some checking that we don't have code paths that use them incorrectly)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have never written asserts and EC Checks, can you give an example please....?

}

#define IF_GEOS_UNLOCK_SLIDING_WINDOW(s) { \
s->windowEndOffs = ((word) s->window) + ((word) s->windowSize); \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be s->windowEndOffs = ((word) s->end) - ((word) s->window);?
Alternatively, something like PtrToOffset(s->end) should also work, as the offset of s->window should always be zero.

Copy link
Collaborator Author

@HubertHuckevoll HubertHuckevoll Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, and while I understand what you mean, your suggestion doesn't work - the original code however, does...

@@ -159,134 +165,167 @@ int stream_size;
#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, this macro also contains a return statement that would need to call IF_GEOS_UNLOCK_SLIDING_WINDOW (even if it is just an error condition for corrupt data...). Perhaps it is easier to move the IF_GEOS_LOCK_SLIDING_WINDOW into the case statement, so the locking only happens for cases the really need to access the dictionary. This would require some more locks, but less unlocks, I think.

Copy link
Collaborator Author

@HubertHuckevoll HubertHuckevoll Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good find. While you are probably right, I will for now just add IF_GEOS_UNLOCK_SLIDING_WINDOW to the macro... is that correct?

IF_GEOS_LOCK_SLIDING_WINDOW(s);
inflate_blocks_reset(s, z, Z_NULL);
IF_GEOS_UNLOCK_SLIDING_WINDOW(s);
s->windowEndOffs = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not needed, the block will be immediately freed anyway...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right! But "inflate_block_reset" sets
s->read = s->write = s->window;
That's why I did it. Will it be safe to set these pointers before deleting the window?

@mgroeber9110
Copy link
Collaborator

One more observation: I find that the image in the test case I put on http://www.mgroeber.de/person.html does not load, probably because import starts too early, while the file is still being streamed. By contrast, http://www.w3.org/Graphics/PNG/Alphatest.html loads fine (and imports progressively).

Copy link
Collaborator

@mgroeber9110 mgroeber9110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's all I can think of for now... I did not really check the PNG implementation line-by-line, but this is probably best tested by actually using it. :-)

unfilterRow(state->currentRow, state->previousRow, state->bytesPerPixel, rowBytes);

// Move the pixel data in the row buffer to skip the filter byte
memmove(state->currentRow, state->currentRow + 1, rowBytes);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we save one copy by combining this move with the next memcpy, i.e. directly copy currentRow + 1 to previousRow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, we probably could, but I spent so many hours getting this right that I'm really afraid of touching this code ;-)

@HubertHuckevoll
Copy link
Collaborator Author

One more observation: I find that the image in the test case I put on http://www.mgroeber.de/person.html does not load, probably because import starts too early, while the file is still being streamed. By contrast, http://www.w3.org/Graphics/PNG/Alphatest.html loads fine (and imports progressively).

After reverting some of the changes in the browser, this page loads for me with the image (even if it takes a while....)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants