-
Notifications
You must be signed in to change notification settings - Fork 72
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
Boundless recording surfaces do not currently work with svgs #150
Comments
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Keeping this alive... With Luxor release 2.11.0, we have recording surfaces and snapshots. There's now more motivation to start the groundwork for boundless surfaces in Cairo. I'm dreaming of using Luxor as an engineering sketch tool, where you naturally work along a roll of paper which extends as your argument grows down the page. Or to the side, if you work that way. And with gridded paper, if you're that kind of person. For short stubs, Luxor already works great for this. But if we put in the necessary pull request to Cairo.jl, Luxor can form the core part of such a tool, along with Latexify, Plots, and a zoom / move around viewer like MiniFB. The live viewer could be supported by an async loop. |
Cool! I'll add a label so that this stays open. |
Is there an example for what this is about? For me it's not clear what is meant with "boundless surfaces". What is here to be expected to work, what doesn't work? Any code examples? |
Just to let you know I saw the comment, and will provide an example at first opportunity. I also need a little time to remember the details here. |
I made an example repo with the kind of scripting workflow I'm describing. issue150.jl contains
Paste from ?snap:
Each I'm including the last two here: |
As per oheil's questions: A boundless recording surface is created with If the pull request linked above is merged into Cairo.jl, we won't need to keep track of where we are drawing on the boundless surface. In the example above, we keep track of extents with The linked example works thanks to the amazing thread safety PRs from oheil. |
Thanks for these examples and explanations, I will have a look when I have some spare time... |
I checked and think part of it is a original Cairo problem. For SVG setting a background color is realized as a <rect ...>. It seems that Cairo ignores the cropping box coordinates for the background <rect..>. See:
results in:
The transformation results in an effective <rect ...> of:
In the example Cairo should create a svg <rect ...> of:
Setting width and height to these arbitrary large values is questionable too. Why not just setting them to the size of the viewBox (350,350)? I don't know enough of Cairo to open a good bug report there. |
As setting the background with function
Perhaps there must be a check if current Drawing has no bounding box, I didn't implemented it, so just thinking about. |
That is certainly a solution for some cases. About which, see 2). Potential disadvantages would be felt on the rendering side, hence not necessarily our problem. The svg specification might be called bloated when it comes to scales and coordinate systems, so we shouldn't be surprised if various browsers and applications do their own simplifications. The large values should probably be from I believe we might need a test for the type of drawing as well? This is applicable to svg of course. But what about recording surfaces? Much of the point of recording surfaces is that we can produce bitmaps initially, but output a vector drawing in the end. Would this great big rectangle lead to the bitmap rendererer allocating 16777215² pixels somewhere? Summary: Test to see if it works? |
I did some experiments. Outcome is that there are no huge allocations happening. Even a check for existing or not existing bounding boxes seems to be not needed.
I tried :rec and snapshot, also "file.png" and ".svg". I didn't found any restrictions on the size of a Cairo bitmap (except 32767x32767 but from year 2014), so I would stick with the 16777215, roughly, but there seems to be some issues, I don't understand:
A value of I would do a PR but would like to discuss it further. Anything which needs to be checked deeper? Doubts? Resistance? Fears? Some oversight? |
There is this: PR356 / issue 355, should they choose to accept it, would become rather useless with this change, as it would return our great big rectangle. I think the Luxor community would mostly survive the potential
|
You could try adding tests and bumping that PR - I don't think @lobingera has abandoned Cairo.jl yet. |
Thanks, cormullion! I'll have a look at adding tests for that PR. I did a little bit of testing with the proposed filled rectangle function, and found that the fill color disappears when combined with scaling. I ran out of time to make a minimal example right now, sorry! |
Here's a minimal example, starting with oheil's proposed 'background'. In the 'nonworking' part, the background is transparent. I have no idea why it's not working, and hope there's some obvious easy reason in what I'm doing here? I ran this in vscode, as 'snapshot' in a REPL doesn't directly launch a viewer with my current upset.
|
It often takes a little while for me to get (back) into the right way of thinking about this. Hence, the 'large allocation' comment was not well thought through. A 'boundless recording surface' in Cairo is a stack of internal cairo commands: circle here, line there, etc. Let's call that stack our 'drawing' for now, and we may imagine a 'world' in which we did draw those things. So the 'large rectangle' command is recorded, but the results of that command are not realized until after we have defined a canvas on which to project our drawing. A side note: Cairo can also convert those internal commands to a human readable text file, but the only purpose would be debugging. There is no way to parse such a text file back into Cairo's internal language. Potentially large allocations would stem from us defining a very large 'canvas' to project on, and storing the projection as a bitmap. Typically, the canvas would be 640x480 pixels and stored in a png file. In the case of svg vector drawings, the problems would occur when displaying the text file. The svg is just a well defined instruction for how to project our drawing on a canvas. Luxor docs use other meanings of 'Drawing' and 'Canvas': Here, the manifestation as an end result IS the Drawing. That's a less boring, and a good way to think about computer graphics. |
With a zooming scalefactor, which is probably applied to the bg_max value of the rect call, it is overflowing. It's the same if you choose bg_max 10x larger, it doesn't work.
But than the user can call rect() instead of background on his own. |
I agree: some kind of overflow issue inside of the Cairo binary is stopping the proposed fix. Thank you for the insight! But the core of this issue lies in the part that writes the svg; it doesn't cover viewports with negative coordinates. Assuming we don't want to change long-established code like Cairo and its "svg factory", a quick fix would be to open the output svg file, replace and save:
Is that fix something we ought to do automatically in Luxor? The code would need to reside in My vote is actually for closing this issue as a NOFIX. If there is a suitable place for dirty tricks like this in the documentation: fine! If not, at least this issue is searchable. As for Cairo itself, I'd say it is what it is. I'll continue being grateful for it, and not post any issue there. |
Fixing the svg output in finish() should be easy enough, except for the decision, what and when exactly. I will do some research on it and create a working proposal. It should be no problem to remember the color for calls to background(). Do not close this issue yet, creating a workaround is better than NOFIX. You (and others) may provide some special graphic examples for testing, e.g. clipping regions, which have to be considered carefully, when manipulating the result svg string. All kind of more or less complex examples which may affect the result of a call to background(). Perhaps you already have something in your collections. |
It's very nice if you would implement a fix that enables my kind of workflow with Luxor: I very much like to develop a drawing, zooming in and out etc. I'm always using Luxor through a 'personal package' suiting my own habits, quirks and interest. That includes storing the background and main foreground colour - other colours are often mixes of those. So for a scripting working style, to have Luxor able to e.g. The A reasonable test is the first image from the previously linked repo. It would be easy to drop the fancy overlay, which requires threads, while keeping the cropping boxes and the first image: ... |
Neither setting background-color nor viewport-fill is a solution.
I think the best way (the only way) is to tweak the resulting svg rect commands which are produced when calling background. Opening the svg with Inkscape shows also a problem with the high value of 16777215 in
the viewBox (0,0,300,300) is ignored and the value is used as is, causing a bit performance issues. This is also an inkscape problem but perhaps it is something not defined in the svg specifications. I didn't check, but exporting it as png from inkscape clips fine. Therefor the route I follow now is to adjust the
after it is produced by the cairo library and before it is written to file. |
Yes, another issue. I don't think that the background color is part of the state in cairo_save(). My understanding is that cairo doesn't have the concept of a background color at all. Perhaps that's the underlying reason of this issue. But I will have this in mind when I implement the solution (if I can do it, not clear yet). Saving some internals seems to be necessary for the workaround. |
The proposed PR does basically this:
to tweaked version:
Any questions? |
@hustf can you test current master? More tests are better... Actually I still expect some cases, where it isn't working, but I hope, that it just fails silently without crashing and without doing anything to the problematic output. This was my goal with this implementation: solve the issue where it is safe and do nothing where something unexpected happens. But this is difficult to test. |
Will do |
Hello, and sorry for the delay! I just had too much fun to stop early! I believe it may be time to close this issue, as the fix itself works absolutely flawlessly. Some halfway related problems floated in the way for straight sailing, though. See 4) and 5) As a byproduct of this, I believe pursuing 'adaptive scaling' workflow with Luxor.jl may actually be worthwhile. In order to not increase the initial treshold to using Luxor, I propose putting such functionality in a submodule, to be 'unlocked' by: I had a lot of fun giving this a whirl! The fix works brilliantly! It is not strictly limited to 'background' per se. In the drawings below, we can see how blends, too, can be used as a background - the fix applies! Although svg and png blends render differently: Lots of other tests and examples sits here. If anybody would look into this immediately:
From 'adaptive_scaling.jl': 115, linked above:
With the fix above, we can work with extremely large svg files. I believe a similar fix applies to 'Luxor/images/_readsvgfile(fname). There's also a problem painting large svgs onto png surfaces. During 'adaptive_scaling.jl':351
I'm linking this svg drawing where the above warning was issued. I was not able to |
Maybe closing this is premature. While trying to narrow down 4), now #254, I triggered a regexp error. It would be nice to see if this occurs on my system only:
If this is indeed reproducible, pfitzseb found a fix here. |
@hustf great finding. No, it's not only you, I didn't check for now but I got those errors during development too. I already did some fine tuning but you found another one, nice! These type of errors are really a problem with RegExs, as they can't easily be forced. |
Done: #255 |
Great, but I just found another one, while you were working. I'll try to reproduce with the fix in #255. If you inspect Malformed_output.svg, you'll find that
So I assume we use a more lenient parser version when reading from a string rather than a file. Inspecting the file, we see the difference, which is not acceptable to
Similarly produced, but smaller files, did not have 'class="luxor_adjusted`. Is the class supposed to be a temporary insertion? I'm not sure. I'm now going to try and reproduce with #255! |
I can work with it:
no errors and test.svg opens well.
Not for me.
Yes, this is another issue. You did a fork so I do nothing here. I think you can change the code savely as you proposed by first reading the file into a String and provide this String to
I have added this to put a stamp on the changes which are done by the patch for this issue here to be sure that we can recognize and find the changed lines in the svg. It should not be a problem as it is valid SVG syntax. |
Hm, a mystery! I'll try this on a mac tomorrow. It's not cool if this is a windows/ mac thing, because we have enough of those already. It may also be related to the Pango version I'm forced to use on Windows for text rendering. Meanwhile, with the new PR #255, the file produced is a little different, but still crashes my Windows rsvg. Here is the new file: I also updated 'adaptive_scaling.jl' so that it now crashes if I run 'snowblind - whirl.jl', while producing file 106.svg. |
Still working fine for me, no error. |
I downloaded your repository... it's a bit complex. Trying 'snowblind - whirl.jl' I get:
Not sure if this has something to do with this issue. |
EDIT: Please disregard the response below. I started up the macintosh computer now, and the error message indicates you hit some temporary debug code. You already figured out that you had to "Pkg.free Pango". I hit some errors, too, and will look further into making this work on macos tonight. _That's a helpful error message from reading one of our 'finished' svgs! I believe the parser on your system may not be SVG 2 compliant. And the svg parser on my system config is not either, though it failed to show this good an error message. Would it be easy to retain the XML namespace tags during finish? There could be other solutions as well, by changing the headers. SVG used to be more clearly a self-defining format, hence the namespace requirements. Later, css was implemented since no one really went to the trouble of also providing the XML schemas with namespace definitions. I don't know much about it, but when inserting |
Resolved in master. Issue should be closed. If anything happens it's better to create new issues. The existing issues are getting cluttered a bit. |
This is included as a comment in /test/test-snapshot.jl
If somehow Cairo.jl could be provided with the size reference it seems to need for svg drawings, a boundless recording surface could be provided by default. This could be quite useful for scripting if combined with get-extents. Scripting users could get instant results displayed without boilerplate.
The text was updated successfully, but these errors were encountered: