How to save something from the .NET
MAUI Community Toolkit DrawingView into an image. That is what we're
going to see in this video. Earlier on this channel, I've made a
video on how to get started with .NET MAUI DrawingView which is a control in
the .NET MAUI Community Toolkit which allows you to basically draw anything
on a canvas. So think of maybe, I don't know, some
app there where you can have to do pictionary. That's
the game, right? Where you have to kind of guess what the drawing is
going to be. Or maybe much more practical having a signature pad where your
customer has to sign something in the app. But I've got a couple of
questions under my videos, which I always welcome. So if you have
something in this video or another question, let me know down in
the comments about how to actually save an image from that drawing view. So in
this video, we're going to see how to get all the data from that DrawingView inside of an image as a
PNG and save that to your device or file and then you can process it
further. So let's hop into Visual Studio. Here in Visual Studio, I've
loaded the sample code for the .NET MAUI DrawingView video. You can find the
link down below that will also contain the code that I'm going to write right
now because all my videos have a GitHub sample attached. So go check
that out. In the video description here, you can see it running on Windows. And
this little gray box is the area, the canvas that I can actually draw.
So on Windows I can use my mouse cursor. And I already implemented
whenever you have drawn a line that it will show the image in an
image control in .NET MAUI. So that's how to do that. And from
there it's actually a little step to also save it to a file. So we're going
to implement that here on the on click button that we can see here
I'm going to show you for Windows, Android and iOS. So all the platforms
that are here. So let me close this for a little bit
and we can inspect the code that's already here. We have this
little image that I've implemented in the previous video. I highly recommend
that you check out that one first so that you know all about the drawing view
and what it could do for you. But here we have this image and there
we load the image that is resulting from the DrawingView
that you can see right here, which is a control in the .NET MAUI Community
Toolkit. I'm giving it a background, a width request, a height request on
Windows. It's a little bit small, but it's fine for now. Multiline mode enabled.
We don't allow multiple lines. The line color is green, the line
width, you can have all these configuration options on how your drawing thing is
going to look like. Or you can let the user influence that by setting the
color and let them make a little drawing thing. So that's really
cool. We don't really need this label. So actually let me
just remove this one and this button. Let's name this not click me but save image. And we already have this
clicked event handler wired up here. So OnCounterClicked, I'm
just going to leave the name there. It doesn't really matter, it's all
sample code. Sample code. So let's go to our MainPage.xaml.cs
and you can here see that whenever a line is
completed, which is an event from the DrawingView, we're going to get
the stream, which is kind of important. We're going to get the stream and
we're going to load that into an image source from stream, use that stream
and it's going to be shown in an image. But we can also use that stream to do
all kinds of other stuff. You can send it to a back end if
that's what you want. You can save it to a file and that's exactly
what we're going to do right now. So this OnCounterClicked, let's remove
all the code that's here. Let's remove this redundant count
field because we are not using it. And in here we are going to implement
the code to actually save this to a file. Now file system, we have a FileSystem helper in .NET MAUI directly, which has a couple of things
but it doesn't have the thing that I actually want to do here. This only
gives you some information about the app data directory, the cache directory,
which is very useful, but not for what we're trying to do.
So accessing the file system and saving a file is kind of file specific,
sorry, not file specific, platform specific stuff. So I'm going
to do a couple of compiler directives here. So
I'm going to say #if Windows, Windows is the easiest one, then I'm
going to say else if which is #elif Android and then lastly, whoops... Android and
then lastly #elif iOS. And you can probably add Mac
Catalyst here as well. So that we have
them all and then we do #endif. So this is an easy way, this
is enabled by the .NET MAUI single project approach to write
platform specific code right inside of your code here. You can
definitely do it other ways. Neater ways if this is not what you like to do,
litter your code with these compiler directives. But this is an easy way to
make some sidesteps for different platforms here and
there. So that's really cool. So for Windows, like I already said, it's pretty easy.
We're just going to basically say file, you have System.IO.File and you can save all the bytes, right? But
the first thing we need to do, and this is in our shared code. So if
you don't put it in these compiler directives we can do some
shared code. So I can just do var stream. You've already seen that down
below for the drawing view is await draw view. So that draw view is my name for the drawing view here,
right? If we go back to the example you can see here that I have
this x name of draw view so that's just my reference to
this element right here drawingview getimage stream and you can specify a
width and a height. So this is just 200 by
200. Let's make it a little bit more impressive by making it 1020
4024 and we have our stream, right? It will get
the image stream with all the drawings on top of it and we will have that
another way that you can do this we also have net Maui drawingview
drawing view dot and we don't have the right using here so use community toolkit
Maui views. If we add that we can do drawing views
and we can also do get image stream. So this is the static
instance, the static method but now you have to suddenly provide the lines
so you can also provide a custom set of lines right for this
drawing or you can just get the draw view lines. There we go. So we get this lines
collection. So if you want to maybe use it in a more data binding way you
will just bind those lines of the draw view lines and you can
call this static instance of drawing view and you can
use it in a more MVVM kind of way, right? So we have these lines you
still need to do a size. So new size is 1020 4024, right? So that's the same as what we
see in the line above and then we can say the background, right? So
you can set a background color. Well actually we have to do colors, I
don't know, red something like that, right? So we can set a custom background color because we
don't have the background color from the draw view, right? If you're just calling
this get image stream on the draw view instance. So this control right here
in the example is going to get the background color that we set
here which is in this case light gray. So that's how that all works together.
You can use this get image stream like this as well. But I'm just going
to use that actual instance that we have here. Then what you want to do
is get a using you probably want to do this stream as
a using as well because streams are always you have to clean
them up and if you don't do that then they will keep resources and you
will create a memory leak. So do a using here and we also do a using var memoryStream because if we really
want to get the bytes then a memory stream is the easiest thing,
= new MemoryStream(). So we create a new one and then we're
going to say memory stream. Well no, actually stream copy
two. We're going to copy everything from
our stream to the memory stream. So that we also have it in our memory
stream like this. Then we probably want to set the
stream position because if you're going to read
through a stream, it's going to read to the end and then the position is going to
be the end one. We want to reset the position here also for the
memory stream. So that if we're going to do this again, if we're going to save
these, then the position has to be 0 because it's going to
go through that stream again. The methods that we're going to call here to
actually save all the bytes. So we want to set the positions to zero just to
be sure. Now for Windows it's quite easy. Make
sure that you have this box right here set to Windows so that we are living
in Windows land here. And we're going to say System.IO. I'm
using the full namespaces here because else I would have to
repeat all these compiler flags here. So in the using here at the top
as well. If Windows, then using System.IO, et cetera, et cetera. So
again, that's choices that you want to make. But I'm just
going to do it this way. That file and then I'm going to say
WriteAllBytes. You probably want to do it async
actually WriteAllBytesAsync. Let's just do that because this is async already. So WriteAllBytesAsync. And then I
have to specify the file path. So let's just do C:\users\ my username\desktop\ DrawingView and I know it's going to
be a PNG. So let's just make this Test.png. There we have it and it's not going to know these
slashes. So you can either duplicate the slashes or you can add an @ sign
here so that it will pick up automatically
as well. And then I have to specify the bytes that I actually want
to write here. So I want to specify the memory stream to Array because that will get me the
bytes. And I need to await this of course. So I need to
do await to actually do this. Make this awatable.
So now I have everything to write. It on windows. Windows is
kind of easy, right? Windows lets you write to the file system. So if
I'm going to do this, I'm going to run this on Windows. I can do my
little drawing and then when I click the save
file, then it's going to write all the bytes to this little test PNG
here. So my application is coming up. I'm going to make the
best drawing that you've ever seen. This actually says
subscribe to my channel. So this is your signal.
If you haven't subscribed to my channel just yet. Find the
subscribe button down below and do it now. And then when I click Save image, it's
going to save the image. I didn't really give any feedback. So
this is not really great user experience, but oh well. Here in the folder
though, we can now see this test PNG. And whenever I double
click it, it's going to open this viewer. And we have the little
image now here as a file. So that's pretty cool, right?
We have this on Windows, so that's working. Now we need some
code for Android and as is usually the case, Android needs
a lot of code. Android has some weird things here. So
I'm going to copy and paste some code on here. Don't be
alarmed, it's a lot. And we have boom our code for Android
here as well. You can see it's grayed out. If we switch again here to
the different target platform here for Android in the top left, then
you can see that Windows gets grayed out. And now we have all of our code
for Android. This is going to get our current Activity. Activity
is just your screen, your thing. On Android we're going to use a content
resolver. Now note this API that you see here is kind of
newish. There is a deprecated API that you need to use
for older Android versions. I will include that in the final code that
you'll find on the GitHub repository. But this is the most up to date code
and you can see that we use this content resolver. We are
adding some metadata. So we are setting the display name, which is test PNG,
the Mime type, the relative path where we are going to save it and
do some other things right here. And then we're actually going to get
that bitmap from our stream. So here we can use the regular stream. I could
have taken in this memory stream code into the Windows one.
Maybe I need it for iOS as well. Then we're going to do
bitmap compress. We're going to save it as PNG 100%
quality. We're going to flush and close to
clean up all the resources. And now it also works on Android. Now I'm not
going to deploy it on Android. I already have it here on the Emulator. So it's
running here. You can see that same square. It actually hasn't
deployed with the save me here. So this has click me, but
this is the exact same code otherwise. And whenever I do this little drawing
right here, again, this has subscribed to my channel. Really
weird, but that's what it is in Dutch. So click this button and now it's
saved in the background to a file and it's going to be picked up
kind of like with the media features of your Android device. So if
I switch to the folders, the files and folders Explorer here on
Android that I have installed on this
emulator. It takes a little while before this refreshes. Maybe I can do it manually.
And here you can see it pop up the test PNG with the drawing that
I've just saved. So we can also do this on Android. Cool,
cool. Now for iOS again, it's pretty easy to actually do
this to just save something to the gallery. So I'm just going to paste
this code in here again and switch to iOS land. And here we can
just create a new image UIKit.UIImage with an
NSData.FromArray. I'm going to use that memory stream
again. See, there it is again. And I'm going to say image.SaveToPhotosAlbum.
You probably want to do something with this error
whenever something comes up that you detect the error, but otherwise it should
just save it to the Photos album. You probably do need the permissions
for this to actually do something like this. So again, I will double check
that, make sure that it's in the GitHub repository code. But this is all there
is to it to actually save a file to well, no, save a
drawing to a file. Well, that wasn't too bad, was it? It
just is one of those things that you kind of need to know how to do it.
But once you know it, then there is a lot of power in here.
Because now you can save these files or you can
upload them to some kind of API. You probably want to do that through
the stream directly and not maybe save the file first and send that. Because then
you have to save that file to a stream again and then stream that to,
well, anyway, you get the idea, right? So you can save this to API,
you can save this on the local device. You can maybe, I don't know,
put this on a PDF automatically if that's what you want. So there is lots of
options that you can do with this we're, which is really amazing. So
like I said at the beginning of this video, if there is something still unclear,
if you have other questions, please let me know down in the comments or just let
me know how nice this video was. And if you actually thought this video
was nice, then please click the like button to actually enforce that and
let the YouTube algorithm know to other people. This is the video to
watch. Subscribe to my channel. if you haven't done so already. And
I'll be seeing you for my next video. But not before I tell you that this
playlist has a couple of more .NET MAUI videos. So be sure to check
that out. And this video is recommended especially for you. See you for the
next video.