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
Add functions to get base64 png image from AGGRenderer #14
Conversation
@@ -132,4 +132,8 @@ public class SVGRenderer: Renderer{ | |||
} | |||
} | |||
|
|||
public func base64Png(fileName name : String = "svg_plot") -> String{ | |||
return "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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string displays a message "Use AGG Renderer to get base64 image"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good thing to include as a comment in the code, so that future code readers know what this string is :)
(This is probably irrelevant, because of my suggestion to delete this method.)
@@ -16,5 +16,6 @@ public protocol Renderer: AnyObject{ | |||
func drawSolidRectWithBorder(topLeftPoint p1: Point,topRightPoint p2: Point,bottomRightPoint p3: Point,bottomLeftPoint p4: Point, strokeWidth thickness: Float, fillColor: Color, borderColor: Color) | |||
func getTextWidth(text: String, textSize size: Float) -> Float | |||
func drawOutput(fileName name: String) | |||
func base64Png(fileName name : String) -> String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest not adding this as a function in the protocol, so that you don't have to define implementations in renderers that do not support it, and so that users can statically see (e.g. in the autocomplete suggestions for a renderer) whether it supports it.
Extra thoughts. No need to do any of these in this PR:
Actually, I have the same opinion about drawOutput
-- it shouldn't be in the protocol, so that renderers that don't support saving output to a file don't have to implement it.
Of course, if you do this, then it won't be possible to have methods like LinePlot.drawGraphAndOutput(filename: String, renderer: Renderer)
, because that function won't have access to a renderer.drawOutput
method. I don't think this is a big problem -- for now, the user can just do:
let renderer = ...
let plot = ...
plot.drawGraph(renderer: renderer)
renderer.drawOutput(filename: "abc")
Then later, there are ways to improve the api so that the user doesn't have to make so many calls to draw a graph and save it to a file. One idea: make a protocol for plots
protocol Plot: {
func draw(on renderer: Renderer)
}
Then, it's possible to write functions that "draw and save" plots using renderers. e.g.
// maybe this is a top-level function inside swiftplot
func saveAGGPng(for plot: Plot, to filename: String) {
let renderer = AGGRenderer()
plot.draw(on: renderer)
renderer.save(to: filename)
}
// maybe this is a function inside EnableIPythonDisplay in swift-jupyter
func display(plot: Plot) {
let renderer = AGGRenderer()
plot.draw(on: renderer)
let base64Png = renderer.base64Png()
... logic to show the png on jupyter ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooo even better, those "saveAGGPng" functions could be methods in a protocol extension:
extension Plot {
func saveAGGPng(to filename: String) { ... }
}
extension Plot {
func display() { ... }
}
so that the user can just do
let plot = ...
plot.saveAGGPng(to: "abc")
plot.display()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the drawOutput
function, I don't think the name indicates that the renderer need to save the image. So maybe if we have OpenGL the code inside this method can draw the output to a window on the screen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument indicates that it's a function to save an image though, and what if other renderers need different types of arguments to draw their output (e.g. something that draws to a screen needs a screen position)?
Stepping back a bit, I think that the concepts of passing configuration to the renderer (e.g. the filename to save to) and deciding how to receive the image (e.g. as a saved file or as a returned string), should be part of the specific renderer implementation, not part of the abstract renderer interface. This way, renderer implementations have complete freedom to define how exactly they are going to draw their plots, without being constrained by existing methods in the renderer interface.
|
||
// delete[] buffer; | ||
} | ||
|
||
const char* base64Png(const char *file_png){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does agg have an api that gives you data, so that you do not need to save it to disk and then read it to disk?
If you really do have to save it and then read it, could you generate a temporary filename automatically so that the user does not have to specify a filename? Also, would it be possible to do this temporary filename generation, and file reading, and base64 encoding, in Swift? Foundation might have APIs that make it easyish (https://nshipster.com/temporary-files/). Not sure if they're supported on Linux Foundation, but they probably are because most of Foundation works on Linux nowadays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get the base64 we need a properly encoded png file. I'm saving pngs using lodepng, so I do not know what goes on under the hood. So I think we'll need to save a file to the disk.
Regarding doing the base64 encoding in Swift, I'll give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For lodepng, would lodepng_encode_memory()
allow you to do a direct-to-memory encoding, instead of writing to a file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot @BradLarson
This worked! Now we won't have to save it to the disk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we don't need to save it, is it fine if the base64 encoding takes place in cpp itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base64 encoding seems like something that might be used elsewhere (for encoding from other renderers), so I could see an argument for leaving that in Swift. As Marc said, it's relatively simple to do in Swift by leveraging Foundation:
https://stackoverflow.com/a/35360697/19679
and I'm pretty sure that all works on Linux and other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay that we don't have to save it to disk! I do still think that doing the encoding in Swift would be the best. It'll be less code, which is usually a very good thing, because it's easier to maintain less code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shifted it to Swift and updated PR.
This worked: https://stackoverflow.com/a/11251478/9126612
@@ -132,4 +132,8 @@ public class SVGRenderer: Renderer{ | |||
} | |||
} | |||
|
|||
public func base64Png(fileName name : String = "svg_plot") -> String{ | |||
return "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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good thing to include as a comment in the code, so that future code readers know what this string is :)
(This is probably irrelevant, because of my suggestion to delete this method.)
The last commit actually introduced a bug. I'll correct it. |
I've updated the AGG Renderer code to support SubPlots. |
Also I'd like to test the current work in Jupyter notebook and also add an example for the same, for which I'll have to add a tag. So, can I do that? If so, what should I use, because obviously this isn't an actual release. |
@marcrasi @BradLarson could you please review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the slow review, it's a holiday here in the U.S., and the weather has been particularly nice this weekend.
In general, I'm fine with the additions here. However, I'd suggest a reworking of the package arrangement in a future pull request. Rather than having LinePlot, etc. as separate modules, they really should be under one SwiftPlot module for the entire framework. That SwiftPlot module can have the renderers, etc. be dependencies of it, and then all the examples should just need the SwiftPlot module as a single dependency.
Alternatively, the SwiftPlot module could have everything but the specific Renderers, with each Renderer (and all C or C++ submodules) being an individual module that you import separately in addition to SwiftPlot. That might allow for more modularity, with people being able to define their own Renderers that are outside of the framework, yet that comply with the Renderer protocol.
That's alright. Do you mean Memorial Day? Thanks for the review. I too have been thinking it would be nice to have to just import SwiftPlot. I'll make the changes in the next PR. |
@KarthikRIyer - My thinking is that the generic Renderer interface would be part of the SwiftPlot module. Specific instances of Renderers (AGGRenderer, SVGRenderer) could potentially be modules outside of SwiftPlot, and they would depend on SwiftPlot to build (and use import SwiftPlot within them). Whether or not to have external renderers as separate modules or as part of SwiftPlot is something I go back and forth on. It may depend on how Renderers are selected by the end user. Do we want them to manually We're going to need to have conditional inclusion of Renderers based on platform, because on iOS we may not want the weight of an AGGRenderer, and if we create a CGRenderer (for Core Graphics) it wouldn't be supported on non-Apple platforms. This could be done, even if these were part of the framework, by using conditional compilation ( |
I think if having separate modules for each renderer does give us the modularity to implement renderers not included in the package, we should go for that. In the end, the user will have to write something like |
#13