Ha, I also needed this a week ago (for an otherwise all-Julia poster…)
The advantage of returning something that will
show as an image is that interfaces like IJulia or Juno, will know what to do automatically:
That actually is a very good point. Is there a way to define some sort of
show function that would output an image without changing the structure? I guess I’d have to make it a
Having those as
.eps would also be great such that those can be used in LaTeX during a build process.
That’s the idea - wrap it in a struct and override
Base.show. Though there’s an attractive simplicity in just returning a
If you do want to go with a wrapper type you might use
QRCode though you’d have to rename your package to QRCodes.jl (module name pluralization is an ecosystem convention to deal with this, eg
Rotations.Rotation etc etc)
If you made a wrapper, what interface would you want it to conform to other than having a nice default
show method? Eg, is it a graphical object, an
AbstractMatrix or something else entirely? Perhaps best to keep it simple:
struct QRCode data::BitMatrix # Add more things here, eg the code version, # original source data string, etc end function Base.show(io::IO, code::QRCode) # You can include the original text in a header line too if it's part of QRCode # Minimal ANSI color text representation: for i=1:size(code.data,1) println(io, join([code.data[i,j] ? "\e[30m██" : "\e[97m██" for j=1:size(code.data,2)])) end end # possibly also `show(io::IO, ::MIME"text/html", qrc::QRCode)` for IJulia and the like?
Looking at your API I think it would be useful to make the export list more minimal. Having a small export list means you introduce few concepts (types - nouns; functions - verbs) for users to learn about. A minimal set of exported names is also less likely to clash with other packages. Here’s some things to try:
- Avoid exporting really generic names like
getversionif possible. The question to ask is: do I have a similarly generic meaning to go with each generically named function I export? If not, either make the names more specific, resist exporting them, or find a generic function from a different package which has the correct semantics and extend that.
- It’s possible to model
ErrCorrLevelwith types like you’ve done but modelling it with values would be simpler. I’d be inclined to just pass symbol values
:highfor the error correction levels, then you can remove those extra types. Similarly for
Modeand its subtypes.
- With a type
QRCodeto model your data, you may get away with exporting only
QRCodeas the public API:
qrcodewould become the constructor
getmodemight be handled several ways depending on your intent:
- renamed as exported functions
- accessible as public fields of
- documented as public non-exported functions
- renamed as exported functions
https://github.com/rafaqz/UnicodeGraphics.jl can also convert arrays to braile and block chars. Pretty much the same thing but fast (for showing live simulations over ssh hahah)
Thank you very much for all the advice. It all looks like fun things to do with Julia, especially as a learning exercise. I think I’m leaning towards leaving it as simple as possible, add a few options for exporting graphics (png, eps, pdf, svg…) and let people go nuts if they want something more. But I’ll think about it more.
I’m surprised you tell me to export less things, I thought I was being minimalistic already ^^
But thank you, I’ll consider your advice.
Mode, I love type programming too much to give them up (I’m a Haskell kind of guy). I really enjoyed combining multiple dispatch and types to define the different encoding functions.
Thanks again for your feedback!
The problem with the block chars approach (used by UnicodeGraphics and ImageInTerminal) is that the line spacing can introduce thin white lines through the image. Not much of a problem for plots, but it makes QR-codes unscannable. For example, on my (MacOS default) terminal it looks like this:
Yeah it will in atom. It doesnt in a lot of linux terminal fonts which is the real use case. Its probably not usefull for this problem, I was just pointing out there are easier ways than unicodeplots to print arrays and in the repl as people were suggesting that
Great! Programming with multiple dispatch can be very satisfying. There are some circumstances where dispatching on types like this does make a lot sense (from an API standpoint). For example, if the user needs to be able to define their own type and expect the internals of the package to dispatch back to a user-defined function. I don’t know much about QR codes, but I guess they’re defined by a standard and not really extensible in this way. Another case would be when you’ve got tight code in an inner loop and you can’t afford the cost of dispatching on the value. Using types in that case could get a speedup because the compiler will generate type-specialized code for each “selector type”.