Xamarinで、画像を作成する

タグの編集
投稿者 kojiro  (社会人) 投稿日時 2024/3/6 09:29:57
いつもお世話になっております。
c#の初級講座で、
 
namespace DrawPenLesson
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            Draw(e.Graphics);
        }
        private void Draw(Graphics g)
        {
            g.Clear(Color.Black);
            Point[] points1 = new Point[4];
            points1[0] = new Point(0, 0);
            points1[1] = new Point(150, 60);
            points1[2] = new Point(80, 200);
            points1[3] = new Point(500, 150);

            //Pen boldPen = new Pen(Color.HotPink, 5);
            Pen pen1 = new Pen(Color.Red, 5);


            //Point p1 = new Point(20, 20);
            //Point p2 = new Point(500, 200);
            //g.DrawLine(boldPen, p1, p2);
            g.DrawLines(pen1, points1);

            Point[] points2 = new Point[6];
            points2[0] = new Point(300, 50);
            points2[1] = new Point(600, 500);
            points2[2] = new Point(50, 450);
            points2[3] = new Point(400, 110);
            points2[4] = new Point(500, 560);
            points2[5] = new Point(130, 40);

            Pen pen2 = new Pen(Color.BlueViolet, 8);
            g.DrawLines(pen2, points2);

            //Point p3 = new Point(100, 400);
            //g.DrawLine(boldPen, p2, p3);
        }
    }
}
 


が、ありますが、xamarinでは、どんなコントロールを使って、作るのでしょうか?
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/3/6 17:58:22
提示されたサンプルコードは、Pen の Dispose が漏れてます…。
(そもそも、C# 初級講座の記事が、using 無しのコードになっているわけですが)

System.Drawing は GDI+ (一部 GDI) 依存のライブラリなので、
Windows 以外のプラットフォームには向きません。

一応、mono の sysdrawing-coregraphics な実装はあるのですけれどね。
https://learn.microsoft.com/ja-jp/xamarin/cross-platform/internals/available-assemblies


Shape や Path で表現するか、Canvas 、Paint あたりについて調べてみてください。

Xamarin の場合
https://learn.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/shapes/?WT.mc_id=DT-MVP-8907
https://learn.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/graphics/skiasharp/?WT.mc_id=DT-MVP-8907
https://dev.classmethod.jp/articles/xamarin-android-draw-line/

.NET MAUI の場合
https://learn.microsoft.com/ja-jp/dotnet/maui/user-interface/graphics/draw?WT.mc_id=DT-MVP-8907&view=net-maui-8.0


> c#の初級講座で、
誤)c#
正)C#
投稿者 kojiro  (社会人) 投稿日時 2024/3/7 23:28:59
SkiaSharpを研究してみましたが、実際の稼働には及ばずです。
Xamarinでは、あきらめて、JavaScriptを検討してみます。
ありがとうございました。
投稿者 kojiro  (社会人) 投稿日時 2024/3/13 16:37:51
.NET MAUIによるマルチプラットフォームアプリ開発 がVisual Studioで、できるようですね。
以下参考です。
https://learn.microsoft.com/ja-jp/dotnet/maui/get-started/first-app?view=net-maui-8.0&tabs=vswin&pivots=devices-android
https://www.amazon.co.jp/gp/product/4296080237/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

投稿者 kojiro  (社会人) 投稿日時 2024/4/21 16:43:52
.NET MAUIを使って、WindowsのPictureBoxのような役目を持たすことに、成功しました。GraphicsViewコントロールを使うようで、描画だけしかできないと、思っていましたが、https://github.com/dotnet/Microsoft.Maui.Graphics/discussions/332により、コントロール内の座標を得ることにも成功しました。



投稿者 kojiro  (社会人) 投稿日時 2024/4/21 19:58:38
参考までに、実現までのプロセスを書きます。
.NET MAUIは、.NETマルチプラットフォーム・・、ASP.NETとWeb開発、.NETデスクトップ開発にチェックを入れて、VS2022Communityをインストールしました。新しいプロジェクトで、.NET MAUI アプリを選んで、作ります。画像にあるのは、MainPage.xamlとMain.Page.XAml.csです。プロジェクト名は、MAUITOUCHとしております。エミュレーターは、ASP29あたりで作るとよいと思います。BIOSのVirtualizationにチェック(これは、ほぼ、入っていると思います)。それから、"Hyper-V"機能を有効にしないと、エミュレーターは、なかなか動かないと思います。実機への装着などは、Android Studioなどと同じです。VS2022でエラーが出た場合、色々VSのソフトやネットで調べましたが、ChatGPT(https://chat.openai.com/)が参考になることを、話してくれることも、あります。間違ってても、勉強になりました。
投稿者 kojiro  (社会人) 投稿日時 2024/4/23 16:55:00
示したコードは、確かにマウスクリック時の座標を、Textという名前のラベルに示しますが、マウスクリック時の座標を中心とした円を作成することは、できていません。どなたか、教えていただければ、幸いです。_(\\)_
投稿者 kojiro  (社会人) 投稿日時 2024/4/23 17:40:50
適当な時に、トライしたことも含めて、新しくスレッドを立てます。
投稿者 kojiro  (社会人) 投稿日時 2024/4/23 21:02:09
MauiTouch1として作ったプログラムを、公開しておきます。画像は少し違います。
 
MainPage.xaml:

ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiTouch1"
             x:Class="MauiTouch1.MainPage">
    <ContentPage.Resources>
        <local:GraphicsDrawable x:Key="drawable" />
    </ContentPage.Resources>
    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">


            <Label
                Text="グラフィック描画"
                x:Name="Text"
                FontSize="18"
                HorizontalOptions="Center" />

            <GraphicsView 
                Drawable="{StaticResource drawable}"
                x:Name="graph"
                HeightRequest="200" WidthRequest="200"
                StartInteraction="OnStartInteraction"
                EndInteraction="OnEndInteraction"
                />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

MainPage.xaml.cs
 
namespace MauiTouch1;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void OnStartInteraction(object Sender, TouchEventArgs evt)
    {
        PointF firstPoint = evt.Touches.FirstOrDefault();
        string msg = $"Touch/click at {firstPoint}";
        Text.Text = msg;
    }
    private void OnEndInteraction(object Sender, TouchEventArgs evt)
    {
        PointF lastPoint = evt.Touches.LastOrDefault();
        string msg = $", released at {lastPoint}";
        Text.Text += msg;
    }


}

public class GraphicsDrawable : IDrawable
{
    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        canvas.FillColor = Colors.DarkBlue;
        canvas.FillCircle(100, 100, 80);
        canvas.StrokeColor = Colors.LightPink;
        canvas.StrokeSize = 1;
        double rad = 0;
        float x1 = 200;
        float y1 = 100;
        for (int i = 0; i < 100; i++)
        {
            float x2 = (float)(Math.Cos(rad) * 100) + 100;
            float y2 = (float)(Math.Sin(rad) * 100) + 100;
            canvas.DrawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
            rad += Math.PI * (170.0 / 180.0);
        }
    }
}


です。MainPage.xamlで残っている最初の行
 
<?xml version="1.0" encoding="utf-8" ?>
 
 
は取らないと、エラーになります。
投稿者 kojiro  (社会人) 投稿日時 2024/4/30 19:04:01
マイクロソフトコミュニティで、ついに解答を得ました。.NET MAUIのgraphicsVew コントロールで、そのコントロール内をタッチしたときに、それを中心とした円を描かせるコードを示してくださいました。
https://learn.microsoft.com/en-us/answers/questions/1660779/how-to-add-to-graphicsview-class-with-drawableprop
とりあえず、うれしいです。
投稿者 kojiro  (社会人) 投稿日時 2024/5/8 16:57:20
最終的な、サンプルコードです。GraphicsViewコントロール内をクリックすると、円が描かれます。
MainPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiTouch2"
             x:Class="MauiTouch2.MainPage">
    <ContentPage.Resources>
        <local:GraphicsDrawable x:Key="drawable" />
    </ContentPage.Resources>
    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">
            <GraphicsView x:Name="graph" HorizontalOptions="Center" VerticalOptions="Start" HeightRequest="300" WidthRequest="300"
                      StartInteraction="OnStartInteraction" >
                <GraphicsView.Drawable>
                    <local:GraphicsDrawable x:Name="drawable" />
                </GraphicsView.Drawable>
            </GraphicsView>
            <Label
                Text="text"
                x:Name="Text"
                FontSize="10"
                HorizontalOptions="Start"
                VerticalOptions="End"
                />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

MainPage.xaml.cs:
 
namespace MauiTouch2;
public partial class MainPage : ContentPage
{   
    public MainPage()
    {
        InitializeComponent();
    }
    private async void OnStartInteraction(object sender, TouchEventArgs evt)
    {
        PointF firstPoint = evt.Touches.FirstOrDefault();
        string msg = $"Touch/click at {firstPoint}";
        Text.Text = msg;
        await this.drawable.OnTouchAsync(this.graph, firstPoint, CancellationToken.None);
    }
}
public class HitItem
{
    public PointF pos { get; set; }
    //public float radius { get; set; }
}

public class GraphicsDrawable : IDrawable
{
    public List<HitItem> HitItems { get; } = new List<HitItem>();
    public async Task OnTouchAsync(IGraphicsView view, PointF point, CancellationToken token)
    {
        HitItem c = new HitItem();
        c.pos = point;
        //c.radius = 0;
        //lock (this.HitItems)
        //{
           this.HitItems.Add(c);
       // }
       // DateTime start = DateTime.Now;
       // DateTime end = start.AddDays(1);
       // while ( !token.IsCancellationRequested) //DateTime.Now <= end &&
       // {
            //c.radius = 20;  // (float)(start - DateTime.Now).TotalSeconds * 100;
            view.Invalidate();
            await Task.Delay(30);
       // }

        //lock (this.HitItems)
        //{
            this.HitItems.Remove(c);
        //}

        //view.Invalidate();
    }

    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        DrawBack(canvas, dirtyRect);
        DrawHitPoint(canvas, dirtyRect);
    }

    private void DrawHitPoint(ICanvas canvas, RectF dirtyRect)
    {
        if (HitItems.Count == 0)
        {
            return;
        }
        canvas.SaveState();
        canvas.StrokeColor = Colors.Black;
        canvas.StrokeSize = 2;
        canvas.ClipRectangle(dirtyRect);
        HitItem[] items;
        lock (this.HitItems)
        {
            items = this.HitItems.ToArray();
        }
        // foreach (var item in items)
        // {
        canvas.DrawCircle(items[0].pos, 20);
       // }
        canvas.ResetState();
    }
    private void DrawBack(ICanvas canvas, RectF dirtyRect)
    {
        int x = 300;
        canvas.StrokeColor = Colors.Black;
        canvas.StrokeSize = 3;
        canvas.DrawLine(0, 0, x, 0);
        canvas.DrawLine(0, x, x, x);
        canvas.DrawLine(0, 0, 0, x);
        canvas.DrawLine(x, 0, x, x);      
    }
}