|
I found a very cool library for creating QR Codes[^] from text input.
I decided I wanted to create a DotNet Core (3.1) WebAPI so I could see some (or all) of the QRCoder functionality in action.
However, I run Linux (Ubuntu) exclusively at home and Win10 at work.
The Premise
I wanted to know if I could create a DotNet Core project (using Visual Studio Code) that I could later 1) clone from GitHub (to my Linux box), 2) build and 3) run.
Visual Studio Code
Since it runs on both Win10 and Linux I knew I needed to use Visual Studio Code (instead of plain old Visual Studio). Of course, that also meant I'd need to run dotnet core command line.
I gen'd up a Web API project on the command line following this tutorial[^].
Basically just :
/> dotnet new webapi -o <PROJECT-NAME>
/> cd <PROJECT-NAME>
Then I was able to add the QRCode library from nuget via:
/> dotnet add package QRCoder --version 1.3.6
There was bit of a problem when I went to build, because even though I have dotnet 3.1 installed the qrcoder had a dependency on a newer system.drawing.common. Luckily at Nuget you can click the dependencies tab and see how to get that newer library like:
/> dotnet add package System.Drawing.Common --version 4.7.0
After that, everything built and worked. I added some URLs that allows the user to generate QRCodes as JPGs or as Ascii Text (see below).
Ok, ok, but what about Linux!?!
Building and Running On Linux
I went home, pulled my GitHub repo for the project[^] made sure my dotnet core installation was up to 3.1 and ran:
/> git clone href="https://github.com/raddevus/QRCodeGen"
/> cd QRCodeGen
/> dotnet restore -- restores all required libraries for project
/> dotnet build
/> dotnet run
The web api app started running on localhost:5001 and I made calls into the QRCoder API.
This is where the cross-platform part gets interesting.
Cross-Platform Gets Interesting
Now, think about this. The entire base Web API (built on top of MS libraries) runs and works properly even running on Linux.
The Catch
However, if you attempt to make a call to the QRCoder API that generates the QR Code as a JPG () it has a dependency upon a graphics library which is only compiled for Windows. That causes the QRCoder API to fail when running on Linux.
The error looks like this:
The type initializer for 'Gdip' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'libgdiplus' or one of its dependencies.
However, since the QRCoder API call that generates the QR Code as ascii (see generated QR Code below - which is all ASCII chars) has no dependency upon Windows methods it succeeds with no problems, even on Linux.
Here's a snapshot of a call to the GetAsciiQR[^] via Linux command-line (curl) with the returned ascii QR code in the command-line window.
You can generate a QR Code with any message you like at my site, just change the value sent in to the API by changing inText in the following URL:
https://newlibre.com/QRCodeGen/QREncoder/GetAsciiQR?inText=try this
You can see the README which will lead you to sample links for all by going to :
https://newlibre.com/QRCodeGen/readme.htm[^]
PS - There's a secret message (all text based) in the QR Code.
██████████████ ████ ████ ██ ██████████████
██ ██ ████ ██ ██████ ██ ██ ██
██ ██████ ██ ██ ██ ██ ██ ██ ██████ ██
██ ██████ ██ ████ ████████████ ██ ██ ██ ██████ ██
██ ██████ ██ ██ ████ ██████ ████████████ ██ ██████ ██
██ ██ ████████████ ████ ████ ██ ██
██████████████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████████████
██ ████ ████ ██ ██
██ ██████ ██ ██ ████████████ ██ ██ ██
██ ██ ████ ██████ ██████████ ██ ██ ██ ██
██ ██ ████ ██ ████ ████ ██ ████████████ ████
████████ ██ ██████ ████ ████ ████ ██
██ ██████ ████ ██ ████ ██ ██ ██ ██ ████
██ ██ ████ ██████████ ████ ████████ ██ ██████
██ ██████ ████ ████ ██████ ██████ ██████ ██ ████
████ ████ ██████ ████ ██ ████ ██ ██ ██████████
████ ██ ████████ ████████ ████ ██ ████ ████
████ ██ ████ ████ ████ ██████ ██ ██ ████
████ ██ ██ ████ ████ ██ ██ ██ ██ ██
██ ████ ██ ██████ ████ ████ ██████
████ ██ ██ ████ ████ ████ ██████ ████
██ ██ ████ ████ ██ ██████ ████ ████ ████
████ ██ ██████ ██ ████ ████ ██ ██████ ████
██ ████ ██ ████ ██████████████ ████ ████ ████████
████████ ██ ████ ████ ████████████ ████
████ ██████ ██ ██████ ██ ██
██████████████ ████ ██████ ██ ██ ██ ██████ ██
██ ██ ████ ██████ ██████████ ██ ████ ██
██ ██████ ██ ██ ██ ████ ████ ████████████████████
██ ██████ ██ ██ ██ ██ ████ ██ ██ ██████
██ ██████ ██ ██ ██ ██ ██ ██ ████
██ ██ ████ ██████████ ████ ████ ████ ██
██████████████ ████ ████ ██ ██ ████ ████ ██
modified 30-Dec-19 16:08pm.
|
|
|
|
|
Hard .Core again
|
|
|
|
|
Look here[^]
There’s a library you can install to enable System.Drawing on Linux.
What do you get when you cross a joke with a rhetorical question?
The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism.
Do questions with multiple question marks annoy you???
|
|
|
|
|
Brisingr Aerowing wrote: There’s a library you can install to enable System.Drawing on Linux.
That's cool. Thanks for posting. I browsed it and I'll look at it a lot more closely.
|
|
|
|
|
What idiot wrote goto case default instead of goto default in one of my C# switch statements, causing an infinite loop?
It certainly couldn't have been me.
For future reference: given:
enum Foo { One, Two } then:
switch (foo)
{
case Foo.One: goto default;
default: Console.WriteLine("Default");
} compiles to:
if (foo != 0) { }
Console.WriteLine("Default"); whereas:
switch (foo)
{
case Foo.One: goto case default;
default: Console.WriteLine("Default");
} compiles to:
if (foo == Foo.One)
{
while (true)
{
}
}
Console.WriteLine("Default");
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
A good reason not to use goto.
Social Media - A platform that makes it easier for the crazies to find each other.
Everyone is born right handed. Only the strongest overcome it.
Fight for left-handed rights and hand equality.
|
|
|
|
|
I am seeing an odd performance pattern that does entirely make sense to me. I am not asking for anything to be solved - just a confirmation of my observations, or not.
First, the background : I have tried a few options for a tracing library. Among them were Paul DiLascia's old TraceWin app and library. That worked pretty well and was the last one I used. It had a few drawbacks and the main was performance. I found it took on order of 6mS per message and that is just to slow for me and my app(s). I finally decided to write my own and it is looking really good. I now have overhead of about 3μS per message - yes, microseconds. This is where the weird part comes in.
That is the performance on my main development machine. It is a i9-9900X at 3.5Ghz and it runs W10. My testing machine is a Xeon i7-3820 at 3.6GHz and it runs W7, thank the heavens. The weird part is the Xeon has an overhead of less than 1μS per message, typically right at 0.9 and these numbers are quite repeatable.
My goal was to make this as low-overhead as possible and I think I have succeeded. Each message puts the message's text into a buffer (with sprintf) and then copies the buffer into a piece of shared memory using memcpy. However, first it acquires a mutex that guards access to the shared memory. I would not expect an i7 Xeon to be faster than an i9 Core-series processor at essentially the same clock rate at much of anything and certainly not three times faster. This leads to my main question : has anyone else seen this kind of performance difference accessing kernel-level OS objects between W7 and W10?
As I am writing this, I just thought of a possible explanation : clock throttling. I bet the i9 has its clock throttled back during this test. I will experiment a little and see if that's it.
-edit-
Upon further review, I think that is the explanation. In the task manager it shows the CPU idling at 1.2GHz and this would explain the performance difference. The test doesn't last long enough for the turbo mode to kick in so the CPU stays at its idle clock rate. Oh well.
I guess this means the trace library has a sub 1μ overhead and I am even happier about that. Yee haw.
"They have a consciousness, they have a life, they have a soul! Damn you! Let the rabbits wear glasses! Save our brothers! Can I get an amen?"
modified 18-Dec-19 16:21pm.
|
|
|
|
|
I suppose you speak about c/c++, don't you?
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
The library I made is in c++.
"They have a consciousness, they have a life, they have a soul! Damn you! Let the rabbits wear glasses! Save our brothers! Can I get an amen?"
|
|
|
|
|
Any chance to publish an article about it?
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
I am really not sure. It is so entwined with the rest of my framework it would be difficult to extract and isolate. I have stuff like multiple trace contexts, editable colors on a per-thread basis, and other stuff. I guess I could remove all of that and provide basic functionality without the accessories. I'll finish up a few other things and see what I can do.
"They have a consciousness, they have a life, they have a soul! Damn you! Let the rabbits wear glasses! Save our brothers! Can I get an amen?"
|
|
|
|
|
Rick York wrote: t is so entwined with the rest of my framework it would be difficult to extract and isolate. I have stuff like multiple trace contexts, editable colors on a per-thread basis, and other stuff What about a serie of articles?
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
In my Android app (using Kotlin) I recently had some code running even when the List of items contained 0 items.
I was using a for loop with a range and I expected that if the list(array or whatever) contained zero items then the count() would be zero and the for loop wouldn't run.
Here's a fake example of the code that actually runs. You can try it at the kotlin playground:
Kotlin Playground: Edit, Run, Share Kotlin Code Online[^]
val emptySet = Array<Int>(0){0}
println("There are ${emptySet.count()} items in the array.")
for (i in 0..emptySet.count()){
println("Iniside the loop, one time.")
}
Here's the output:
There are 0 items in the array.
Iniside the loop, one time.
for (i in 0..0){
println("Iniside the loop, one time.")
}
I just didn't expect that would be how a range would work.
This feels different than the way C# would handle a for...loop like this.
But, again, I often stumble upon PEBKAC[^] errors.
I'm just lucky that way.
|
|
|
|
|
That does seem rather odd, but it matches the description in the documentation:
if (i in 1..4) { To iterate a number range which does not include its end element, use the until[^] function
Updating your example[^] to use until produces the expected result.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
The until keyword has nothing to do with ranges, it's just another way to write a classic for loop.
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
I just think in this case, for loops in C# are more intuitive and obvious:
for (int x=0;x<=0;x++){
Console.WriteLine($"x {x}");
}
for (int x=0;x<0;x++){
Console.WriteLine($"x {x}");
}
Is there a more equivalent example (are there ranges in C#?) in C#?
|
|
|
|
|
foreach (var in list) { ... }
In C# 8 you have ranges:
foreach(var item in 1..100)
{
Console.WriteLine(item);
} For other range info see: (especially for arrays) C# 8 Ranges and Recursive Patterns[^]
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
TheGreatAndPowerfulOz wrote: foreach (var in list) { ... }
Right, in C# it looks like this:
List<int> allInts = new List<int>();
Console.WriteLine($"There are {allInts.Count} items in the list");
foreach (var x in allInts){
Console.WriteLine(x);
}
The code inside the foreach never runs. Again, that is more what I was expecting.
|
|
|
|
|
TheGreatAndPowerfulOz wrote: foreach(var item in 1..100)
That code won't work:
CS1579 foreach statement cannot operate on variables of type 'Range' because 'Range' does not contain a public instance definition for 'GetEnumerator'
And if you change it to iterate over a range of an array, the upper-bound is exclusive:
int[] numbers = Enumerable.Range(0, 20).ToArray();
foreach (int i in numbers[1..10])
{
Console.WriteLine(i);
}
The start of the range is inclusive, but the end of the range is exclusive, meaning the start is included in the range but the end isn't included in the range.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks, I guess the article from which I grabbed the code-snippet was from a proposed syntax. Too bad, it's much simpler and more readable than what does work.
I guess this is a little closer:
foreach(var item in Enumerable.Range(1, 10))
{
Console.WriteLine(item);
}
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
Since a range is a set, and you're asking to iterate the set, then it's working exactly as I would have expected.
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
TheGreatAndPowerfulOz wrote: Since a range is a set, and you're asking to iterate the set, then it's working exactly as I would have expected.
When I posted, I guessed that I'd get an answer like this. And, I'm not upset with your post, nor do I think it is incorrect.
I figured it was something I just didn't think entirely correctly about.
To me though, it seems like my original code was saying, iterate over this empty set and so I expected it to not run the code inside the for loop.
Another way to say this is, "I accept that I am incorrect about this, but the functionality of the structure as it is defined by Kotlin seems like it leads to grey understanding where the dev could be initially confused until dev obtains some experience with Kotlin Ranges."
But, again, I blame myself for not fully understanding the construct before using it.
I like to shoot first and ask questions later...after all the code is dead (not working).
Thanks for your input on this.
|
|
|
|
|
But the set from 0 to 0 is not empty, there is one item in it: 0.
If you'd said 0 to -1 (or 0 to count()-1 and assuming positive increment), then that would've been empty.
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|