diff --git a/src/blog/a-little-scanner-app-made-with-the-web.md b/src/blog/a-little-scanner-app-made-with-the-web.md new file mode 100644 index 00000000..16c9b8b7 --- /dev/null +++ b/src/blog/a-little-scanner-app-made-with-the-web.md @@ -0,0 +1,308 @@ +--- +path: "/blog/a-little-scanner-app-made-with-the-web" +date: "2021-01-04" +title: "A Little Scanner App Made With The Web" +description: "I developed a little scanner prototype with the web during Christmas holidays to learn and try new skills." +tags: "#webdev #showdev #javascript #react" +image: "https://cdn-images-1.medium.com/max/1600/1*107_wVVJ8y3BVpo4SQKEkA.png" +canonical: "https://daviddalbusco.medium.com/a-little-scanner-app-made-with-the-web-dc9ebe1f2d4" +--- + +![](https://cdn-images-1.medium.com/max/1600/1*107_wVVJ8y3BVpo4SQKEkA.png) + +***** + +This last Christmas holidays, except visiting my parents for a couple of days, after having forced myself in a sort of auto-lockdown period first, I did not have any big plans. That’s why, I took the opportunity to improve my software development knowledge. + +As I better learn concept by applying them to real application rather than writing examples, I decided to create a little scanner Progressive Web Apps entirely made with the web. + +I called it [Rebel Scan](https://rebelscan.com) because, it is just a little scanner app, you rebel scum! + + +
+ +*A potato demo video of [Rebel Scan](https://rebelscan.com)* + +***** + +### Introduction + +It is important to note that this little scanner does not aim to be the most perfect scanner the world has ever seen. I am not even sure I will use it in the future. The image processing is not the best, there is no text extraction and on mobile it “only” shares PNG (see last chapter about it). It had absolutely no other goal that helping me learn new skills. + +Therefore, before development begins, I defined the following objectives I never had tried before and, which I was eager to test: + +* Give a try to [Next.js](https://nextjs.org/) +* Capture and crop a video stream using the [MediaDevices.getUserMedia()](https://developer.mozilla.org/fr/docs/Web/API/MediaDevices/getUserMedia) API +* Generate [React](https://reactjs.org/) bindings for a Web Component developed with [Stencil](https://stenciljs.com/) +* Share files using strictly only the [Web Share API](https://developer.mozilla.org/fr/docs/Web/API/Navigator/share) + +Without revealing the ending, I can confirm it was a success and, I was able to develop my little application. However, there was a couple of surprises along the way. Let’s tackle these, step by step. + +### Meta + +The Progressive Web App, the result of this post and my experiment, is available online at [rebelscan.com](https://rebelscan.com) and its source code is available on [GitHub](https://github.com/peterpeterparker/rebelscan). + +***** + +### Next.js + +Prior to this experiment and, thus since around a year, my favorite tech stack to implement websites was: [Gatsby](https://gatsbyjs.com/) for the development, [GitHub actions](https://github.com/features/actions) for deployment purpose and [Firebase](https://firebase.google.com/) as hosting. + +Next.js by [Vercel](https://vercel.com), without any surprise, was an excellent experience. I only scratched its surface and, I only used it to deploy a pre-rendered app but, it confirmed all the positive tweets and blogs I read about it. + +It is really well [documented](https://nextjs.org/docs/getting-started) and getting started is straight forward. In comparison to Gatsby, I really liked that it took me absolutely no time to discover how to set up [TypeScript](https://nextjs.org/docs/basic-features/typescript) and, that the configuration seemed closer to a bare-bones dependency setup. + +In addition, Next.js has a built-in support for internationalized ([i18n](https://nextjs.org/docs/advanced-features/i18n-routing)) routing. Needless to say, as a Swiss-French person, living in the Swiss-German part and writing posts in English, I greatly value such a feature 👍. + +On the other side, without having done any research or statistics, I have the impression that the Gatsby’s ecosystem, in terms of plugins notably, is currently “wider”. As for example, with Gatsby there is one to generate automatically both sitemaps.xml and robots.txt where, with Next.js, it would need a bit more coding. + +That being said, I am talking about peanuts. Both stacks are amazing and let me unleash performant websites and applications. I love them both ❤️. + +![](https://cdn-images-1.medium.com/max/1600/1*vSF3L96OuojzBPiExnpevg.gif) + +***** + +### MediaDevices.getUserMedia() + +Oh boy, this one gave me a hard time 😅. + +The API itself is a wonderful piece of software and being able to capture a video stream with the Web is just amazing but, the feature I was looking to develop was a bit challenging regarding its responsiveness across devices. Indeed, my goal was to display the full video behind a cropped section (“two distinct elements”), without breaking points, and this regardless of the screen or camera size. + +![](https://cdn-images-1.medium.com/max/1600/1*Jt8uqpzR_IvqYwWNqdmIVg.png) + +It ain’t probably rocket science for some but, to me, it was a bit challenging for the following reasons: + +1. You cannot use the video without HTTPS (from another device) +2. The video size is unpredictable +3. Finding the proper ratio and method took many iterations + +***** + +#### HTTPS + +It is possible to develop and test the camera stream locally but, as soon as you want to test it with your mobile phone, you need an HTTPS connection. + +Therefore, I had two options. Either generate a certificate and run an HTTPS server on my laptop to which, I would connect from my device, or, use the “commit, push, test, try harder” method. + +I let you check my commit history of the 2nd January 2020 to guess which method I went for 🤣. + +![](https://cdn-images-1.medium.com/max/1600/1*-B8CROTQuPCbhZAR3IjTwg.png) + +***** + +#### The Video Size Is Unpredictable + +> Ask for portrait, gets landscape. Asks for landscape, gets portrait. + +Basically, you Android phone is like one of my best friend: he does what he wants, period. + +```javascript +const stream = await navigator.mediaDevices.getUserMedia({ + audio: false, + video: { + width: {ideal: 1920}, + height: {ideal: 1080}, + facingMode: 'environment', + }, +}); + +const [track] = stream.getVideoTracks(); + +const settings = track.getSettings(); + +videoRef.current.width = settings.width; +videoRef.current.height = settings.height; + +// Android (portrait):