차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

다음 판
이전 판
linuxpc:camera:index [2026/06/09 14:50] – created adminlinuxpc:camera:index [2026/06/09 23:02] (현재) admin
줄 30: 줄 30:
 {{ https://downloads.comfiletech.com/jPC/videos/jpc-qrcode-demo.mp4?476x424 }} {{ https://downloads.comfiletech.com/jPC/videos/jpc-qrcode-demo.mp4?476x424 }}
  
 +++++[소스 코드]|
 <code C#> <code C#>
-(원본 코드 그대로) </code>+#:package GirCore.GLib-2.0@0.6.3 
 +#:package GirCore.GdkPixbuf-2.0@0.6.3 
 +#:package GirCore.Gtk-4.0@0.6.3 
 + 
 +using GdkPixbuf; 
 +using Gio; 
 +using Gtk; 
 +using System.Diagnostics; 
 +using System.Runtime.InteropServices; 
 +using System.Threading.Channels; 
 +using Task = System.Threading.Tasks.Task; 
 + 
 +public class Program 
 +
 +    const int Width = 480; 
 +    const int Height = 320; 
 +    const int FrameSize = Width * Height * 3; 
 + 
 +    static IntPtr _scanner; 
 +    static Channel<byte[]> _previewChannel = Channel.CreateUnbounded<byte[]>(); 
 +    static Channel<byte[]> _scanChannel = Channel.CreateUnbounded<byte[]>(); 
 + 
 +    public static int Main(string[] args) 
 +    { 
 +        var app = Gtk.Application.New("org.example.QrDemo", ApplicationFlags.FlagsNone); 
 +        app.OnActivate += (gioApp, _) => CreateGUI((Gtk.Application)gioApp); 
 + 
 +        var status = app.RunWithSynchronizationContext(args); 
 +        return status; 
 +    } 
 + 
 +    static void CreateGUI(Gtk.Application app) 
 +    { 
 +        var window = ApplicationWindow.New(app); 
 +        window.Title = "GTK + ZBar QR Demo"; 
 +        window.SetDefaultSize(Width, Height + 80); 
 +        window.SetResizable(false); 
 + 
 +        var vbox = Box.New(Orientation.Vertical, 4); 
 + 
 +        var picture = Picture.New(); 
 +        picture.SetSizeRequest(Width, Height); 
 +        picture.SetHalign(Align.Center); 
 + 
 +        var label = Label.New("Waiting for QR..."); 
 + 
 +        vbox.Append(picture); 
 +        vbox.Append(label); 
 + 
 +        window.Child = vbox; 
 + 
 +        window.Present(); 
 + 
 +        _scanner = zbar_image_scanner_create(); 
 + 
 +        StreamFramesAndScan(picture, label); 
 +    } 
 + 
 +    private static void StreamFramesAndScan(Picture picture, Label label) 
 +    { 
 +        var psi = new ProcessStartInfo 
 +        { 
 +            FileName = "gst-launch-1.0", 
 +            Arguments = 
 +                "libcamerasrc ! " + 
 +                $"video/x-raw,width={Width},height={Height},framerate=30/1,format=NV12 ! " + 
 +                "videoconvert ! " + 
 +                $"video/x-raw,format=RGB ! " + 
 +                "multipartmux boundary=frame ! " + 
 +                "fdsink fd=1", 
 +            UseShellExecute = false, 
 +            RedirectStandardOutput = true, 
 +            RedirectStandardError = false, 
 +            CreateNoWindow = true 
 +        }; 
 + 
 +        if (Process.Start(psi) is not Process process) 
 +        { 
 +            GLib.Functions.IdleAdd(0, () => { label.SetText("Failed to start GStreamer"); return false; }); 
 +            return; 
 +        } 
 +         
 +        _previewChannel = Channel.CreateUnbounded<byte[]>(); 
 +        _scanChannel = Channel.CreateUnbounded<byte[]>(); 
 + 
 +        var stream = process.StandardOutput.BaseStream; 
 +        var cts = new CancellationTokenSource(); 
 + 
 +        ParseFrames(stream, process, label, cts); 
 +        GeneratePreview(picture, cts); 
 +        ScanForQRCode(label, cts); 
 +    } 
 + 
 +    static void ParseFrames(Stream stream, Process process, Label label, CancellationTokenSource cts) 
 +    { 
 +        Task.Run(async () => 
 +        { 
 +            try 
 +            { 
 +                var previewWriter = _previewChannel.Writer; 
 +                var scanWriter = _scanChannel.Writer; 
 +                 
 +                while (true) 
 +                { 
 +                    // Skip to frame boundary "\r\n\r\n" 
 +                    while (stream.ReadByte() != '\r') { } 
 +                    if (stream.ReadByte() != '\n' 
 +                        || stream.ReadByte() != '\r' 
 +                        || stream.ReadByte() != '\n'
 +                    { 
 +                        continue; 
 +                    } 
 + 
 +                    var frame = new byte[FrameSize]; 
 +                    stream.ReadExactly(frame); 
 + 
 +                    if (frame.Length == FrameSize) 
 +                    { 
 +                        await previewWriter.WriteAsync(frame, cts.Token); 
 +                        await scanWriter.WriteAsync(frame, cts.Token); 
 +                    } 
 +                } 
 +            } 
 +            finally 
 +            { 
 +                cts.Cancel(); 
 +                _previewChannel.Writer.TryComplete(); 
 +                _scanChannel.Writer.TryComplete(); 
 +            } 
 +        }); 
 +    } 
 + 
 +    static void GeneratePreview(Picture picture, CancellationTokenSource cts) 
 +    { 
 +        Task.Run(async () => 
 +        { 
 +            try 
 +            { 
 +                byte[]? lastFrame = null; 
 +                await foreach (var frame in _previewChannel.Reader.ReadAllAsync(cts.Token)) 
 +                { 
 +                    if (ReferenceEquals(frame, lastFrame)) continue; 
 +                    lastFrame = frame; 
 +                     
 +                    GLib.Functions.IdleAdd(0, () => 
 +                    { 
 +                        try 
 +                        { 
 +                            var pix = Pixbuf.NewFromBytes(GLib.Bytes.New(frame), Colorspace.Rgb, false, 8, Width, Height, Width * 3); 
 +                            picture.SetPixbuf(pix); 
 +                        } 
 +                        catch { } 
 +                        return false; 
 +                    }); 
 +                } 
 +            } 
 +            catch (OperationCanceledException) { } 
 +        }); 
 +    } 
 + 
 +    static void ScanForQRCode(Label label, CancellationTokenSource cts) 
 +    { 
 +        Task.Run(async () => 
 +        { 
 +            try 
 +            { 
 +                byte[]? lastFrame = null; 
 +                await foreach (var frame in _scanChannel.Reader.ReadAllAsync(cts.Token)) 
 +                { 
 +                    if (ReferenceEquals(frame, lastFrame)) continue; 
 +                    lastFrame = frame; 
 +                     
 +                    var text = ScanQrFromRgb(frame); 
 +                    if (!string.IsNullOrEmpty(text)) 
 +                        GLib.Functions.IdleAdd(0, () => { label.SetText($"QR Code: {text}"); return false; }); 
 +                } 
 +            } 
 +            catch (OperationCanceledException) { } 
 +        }); 
 +    } 
 + 
 +    readonly static uint FourCC = 'Y' | ((uint)'8' << 8) | ((uint)'0' << 16) | ((uint)'0' << 24); 
 + 
 +    private static string? ScanQrFromRgb(ReadOnlySpan<byte> rgb) 
 +    { 
 +        // Convert RGB to Grayscale 
 +        var gray = new byte[Width * Height]; 
 +        for (int i = 0; i < rgb.Length; i += 3) 
 +        { 
 +            int y = (int)((rgb[i] * 0.299) + (rgb[i + 1] * 0.587) + (rgb[i + 2] * 0.114)); 
 +            gray[i / 3] = (byte)(y < 0 ? 0 : y > 255 ? 255 : y); 
 +        } 
 + 
 +        IntPtr image = zbar_image_create(); 
 +        zbar_image_set_format(image, FourCC); 
 +        zbar_image_set_size(image, Width, Height); 
 + 
 +        IntPtr dataPtr = Marshal.AllocHGlobal(gray.Length); 
 +        try 
 +        { 
 +            Marshal.Copy(gray, 0, dataPtr, gray.Length); 
 +            zbar_image_set_data(image, dataPtr, (UIntPtr)gray.Length, IntPtr.Zero); 
 + 
 +            if (zbar_scan_image(_scanner, image) <= 0) 
 +            { 
 +                zbar_image_destroy(image); 
 +                return null; 
 +            } 
 + 
 +            IntPtr symbol = zbar_image_first_symbol(image); 
 +            string? result = symbol != IntPtr.Zero ? Marshal.PtrToStringAnsi(zbar_symbol_get_data(symbol)) : null; 
 +            zbar_image_destroy(image); 
 +            return result; 
 +        } 
 +        finally 
 +        { 
 +            Marshal.FreeHGlobal(dataPtr); 
 +        } 
 +    } 
 + 
 +    const string ZBarLib = "libzbar.so.0"; 
 +    [DllImport(ZBarLib)] 
 +    private static extern IntPtr zbar_image_scanner_create(); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern IntPtr zbar_image_create(); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern void zbar_image_destroy(IntPtr image); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern void zbar_image_set_format(IntPtr image, uint fourcc); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern void zbar_image_set_size(IntPtr image, uint width, uint height); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern void zbar_image_set_data(IntPtr image, IntPtr data, UIntPtr length, IntPtr cleanup); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern int zbar_scan_image(IntPtr scanner, IntPtr image); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern IntPtr zbar_image_first_symbol(IntPtr image); 
 + 
 +    [DllImport(ZBarLib)] 
 +    private static extern IntPtr zbar_symbol_get_data(IntPtr symbol)
 +
 + 
 +</code> 
 +++++
  
 [[..:index|JPC (임베디드 리눅스 Panel PC)]] [[..:index|JPC (임베디드 리눅스 Panel PC)]]