Konsol uygulamasında bir Görüntü görüntüleme


86

Görüntüleri yöneten bir konsol uygulamam var. Şimdi konsol uygulamasındaki Görsellerin önizlemesi gibi bir şeye ihtiyacım var. Bunları konsolda göstermenin bir yolu var mı?

İşte mevcut karakter temelli cevapların bir karşılaştırması:

Giriş:

görüntü açıklamasını buraya girin

Çıktı:

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin


Konsol penceresinde olduğu gibi konsolda mı? Hayır. Bununla birlikte, ayrı bir iletişim kutusu / pencere başlatabilirsiniz.
Christian.K

Konsol uygulamaları öncelikle yalnızca metin uygulamaları için kullanılır. Bir resmi göstermenin bir yolu yoktur. Resmi görüntüleyen başka bir uygulama başlatabilirsiniz. Bu diğer uygulamanın, bir görüntüyü ona iletmek için büyük olasılıkla bir komut satırı seçeneğini desteklemesi gerekir.
Lindos Pechos

Neden bir konsol uygulaması kullanıyorsunuz? Nerede çalışıyor? Varsayılan resim görüntüleyiciyi veya sadece kendi winforms vb. uygulamanızı açmak için her zaman bir işlem başlatabilirsiniz ..
TaW

1
Antonín Lejsek'in kodunun iyileştirilmesine ihtiyacım var (bu harika). Birkaç renk eşleşmesi var ve iyileştirilmiş performansla hareketli
gifleri

Yanıtlar:


58

Ayrıca @DieterMeemken koduyla oynadım. Dikey çözünürlüğü yarıya indirdim ve ░▒▓ ile titreme ekledim. Solda Dieter Meemken sonucu, sağda my. Altta orijinal resim çıktıyla uyumlu olacak şekilde yeniden boyutlandırılmıştır. Çıktı sonucu Malwyns dönüştürme işlevi etkileyici olsa da, ne yazık ki tüm gri renkleri kullanmıyor.

static int[] cColors = { 0x000000, 0x000080, 0x008000, 0x008080, 0x800000, 0x800080, 0x808000, 0xC0C0C0, 0x808080, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0xFFFF00, 0xFFFFFF };

public static void ConsoleWritePixel(Color cValue)
{
    Color[] cTable = cColors.Select(x => Color.FromArgb(x)).ToArray();
    char[] rList = new char[] { (char)9617, (char)9618, (char)9619, (char)9608 }; // 1/4, 2/4, 3/4, 4/4
    int[] bestHit = new int[] { 0, 0, 4, int.MaxValue }; //ForeColor, BackColor, Symbol, Score

    for (int rChar = rList.Length; rChar > 0; rChar--)
    {
        for (int cFore = 0; cFore < cTable.Length; cFore++)
        {
            for (int cBack = 0; cBack < cTable.Length; cBack++)
            {
                int R = (cTable[cFore].R * rChar + cTable[cBack].R * (rList.Length - rChar)) / rList.Length;
                int G = (cTable[cFore].G * rChar + cTable[cBack].G * (rList.Length - rChar)) / rList.Length;
                int B = (cTable[cFore].B * rChar + cTable[cBack].B * (rList.Length - rChar)) / rList.Length;
                int iScore = (cValue.R - R) * (cValue.R - R) + (cValue.G - G) * (cValue.G - G) + (cValue.B - B) * (cValue.B - B);
                if (!(rChar > 1 && rChar < 4 && iScore > 50000)) // rule out too weird combinations
                {
                    if (iScore < bestHit[3])
                    {
                        bestHit[3] = iScore; //Score
                        bestHit[0] = cFore;  //ForeColor
                        bestHit[1] = cBack;  //BackColor
                        bestHit[2] = rChar;  //Symbol
                    }
                }
            }
        }
    }
    Console.ForegroundColor = (ConsoleColor)bestHit[0];
    Console.BackgroundColor = (ConsoleColor)bestHit[1];
    Console.Write(rList[bestHit[2] - 1]);
}


public static void ConsoleWriteImage(Bitmap source)
{
    int sMax = 39;
    decimal percent = Math.Min(decimal.Divide(sMax, source.Width), decimal.Divide(sMax, source.Height));
    Size dSize = new Size((int)(source.Width * percent), (int)(source.Height * percent));   
    Bitmap bmpMax = new Bitmap(source, dSize.Width * 2, dSize.Height);
    for (int i = 0; i < dSize.Height; i++)
    {
        for (int j = 0; j < dSize.Width; j++)
        {
            ConsoleWritePixel(bmpMax.GetPixel(j * 2, i));
            ConsoleWritePixel(bmpMax.GetPixel(j * 2 + 1, i));
        }
        System.Console.WriteLine();
    }
    Console.ResetColor();
}

kullanım:

Bitmap bmpSrc = new Bitmap(@"HuwnC.gif", true);    
ConsoleWriteImage(bmpSrc);

DÜZENLE

Renk mesafesi karmaşık bir konudur ( burada , burada ve bu sayfalardaki bağlantılar ...). YUV'de mesafeyi hesaplamaya çalıştım ve sonuçlar RGB'den daha kötüydü. Lab ve DeltaE ile daha iyi olabilirlerdi ama ben bunu denemedim. RGB'deki mesafe yeterince iyi görünüyor. Aslında sonuçlar, RGB renk uzayında hem öklid hem de Manhattan mesafesi için çok benzer, bu yüzden seçim yapılabilecek çok az renk olduğundan şüpheleniyorum.

Gerisi, tüm renk ve desen kombinasyonlarıyla (= semboller) rengin kaba kuvvetle karşılaştırılmasıdır. ░▒▓█ için doldurma oranını 1/4, 2/4, 3/4 ve 4/4 olarak belirttim. Bu durumda, üçüncü sembol aslında birinciden fazladır. Ancak oranlar bu kadar tek tip olmasaydı (yazı tipine bağlıdır) sonuçlar değişebilir, bu yüzden gelecekteki iyileştirmeler için orada bıraktım. Ortalama sembol rengi, doldurma oranına göre foregroudColor ve backgroundColor'un ağırlıklı ortalaması olarak hesaplanır. Doğrusal renkleri varsayar, bu da büyük bir sadeleştirmedir. Yani hala iyileştirme için yer var.


Teşekkür ederim @fubo. Btw, gama düzeltmeli RGB ve Lab ile deneyler yaptım ve her ikisi de iyileştirildi. Ancak doldurma oranının kullanılan yazı tipiyle eşleşecek şekilde ayarlanması gerekiyordu ve bu, truetype yazı tipleri için hiç işe yaramadı. Yani artık tüm çözüme uyan tek bir boyut olmayacaktı.
Antonín Lejsek

90

Bir konsolda bir görüntüyü göstermek konsolun amaçlanan kullanımı olmasa da, konsol penceresi diğer pencereler gibi sadece bir pencere olduğu için kesinlikle nesneleri hackleyebilirsiniz.

Aslında, grafik destekli konsol uygulamaları için bir metin kontrol kitaplığı geliştirmeye başladığımda. Çalışan bir kavram kanıtı demom olsa da bunu hiç bitirmedim:

Resimli metin kontrolleri

Konsolun yazı tipi boyutunu elde ederseniz, görüntüyü çok hassas bir şekilde yerleştirebilirsiniz.

Bunu şu şekilde yapabilirsiniz:

static void Main(string[] args)
{
    Console.WriteLine("Graphics in console window!");

    Point location = new Point(10, 10);
    Size imageSize = new Size(20, 10); // desired image size in characters

    // draw some placeholders
    Console.SetCursorPosition(location.X - 1, location.Y);
    Console.Write(">");
    Console.SetCursorPosition(location.X + imageSize.Width, location.Y);
    Console.Write("<");
    Console.SetCursorPosition(location.X - 1, location.Y + imageSize.Height - 1);
    Console.Write(">");
    Console.SetCursorPosition(location.X + imageSize.Width, location.Y + imageSize.Height - 1);
    Console.WriteLine("<");

    string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures), @"Sample Pictures\tulips.jpg");
    using (Graphics g = Graphics.FromHwnd(GetConsoleWindow()))
    {
        using (Image image = Image.FromFile(path))
        {
            Size fontSize = GetConsoleFontSize();

            // translating the character positions to pixels
            Rectangle imageRect = new Rectangle(
                location.X * fontSize.Width,
                location.Y * fontSize.Height,
                imageSize.Width * fontSize.Width,
                imageSize.Height * fontSize.Height);
            g.DrawImage(image, imageRect);
        }
    }
}

Mevcut konsol yazı tipi boyutunu şu şekilde elde edebilirsiniz:

private static Size GetConsoleFontSize()
{
    // getting the console out buffer handle
    IntPtr outHandle = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        IntPtr.Zero,
        OPEN_EXISTING,
        0,
        IntPtr.Zero);
    int errorCode = Marshal.GetLastWin32Error();
    if (outHandle.ToInt32() == INVALID_HANDLE_VALUE)
    {
        throw new IOException("Unable to open CONOUT$", errorCode);
    }

    ConsoleFontInfo cfi = new ConsoleFontInfo();
    if (!GetCurrentConsoleFont(outHandle, false, cfi))
    {
        throw new InvalidOperationException("Unable to get font information.");
    }

    return new Size(cfi.dwFontSize.X, cfi.dwFontSize.Y);            
}

Ve gerekli ek WinApi çağrıları, sabitleri ve türleri:

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetConsoleWindow();

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(
    string lpFileName,
    int dwDesiredAccess,
    int dwShareMode,
    IntPtr lpSecurityAttributes,
    int dwCreationDisposition,
    int dwFlagsAndAttributes,
    IntPtr hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GetCurrentConsoleFont(
    IntPtr hConsoleOutput,
    bool bMaximumWindow,
    [Out][MarshalAs(UnmanagedType.LPStruct)]ConsoleFontInfo lpConsoleCurrentFont);

[StructLayout(LayoutKind.Sequential)]
internal class ConsoleFontInfo
{
    internal int nFont;
    internal Coord dwFontSize;
}

[StructLayout(LayoutKind.Explicit)]
internal struct Coord
{
    [FieldOffset(0)]
    internal short X;
    [FieldOffset(2)]
    internal short Y;
}

private const int GENERIC_READ = unchecked((int)0x80000000);
private const int GENERIC_WRITE = 0x40000000;
private const int FILE_SHARE_READ = 1;
private const int FILE_SHARE_WRITE = 2;
private const int INVALID_HANDLE_VALUE = -1;
private const int OPEN_EXISTING = 3;

Ve sonuç:

[Konsolda Grafikler


2
Vay canına, bu gerçekten ilginç! Çalışan bir kavram kanıtı demom olmasına rağmen bunu hiç bitirmedim derken neyi kastettiğinizi biraz açıklar mısınız? Herhangi bir dezavantaj veya sadece eksik cila ..?
TaW

Bu, projenin çok eksik olduğu anlamına gelir. Temel mimari, taban olaya dayalı OO ortamı, fare desteği, mesaj pompası, vs. Ama böyle bile en temel kontroller yapılmış Button, TextBoxhala eksik vb. Hayalim, veri bağlama ve WPF benzeri "her şeyi herhangi bir şeye yerleştirme" felsefesiyle oldukça eksiksiz bir XAML desteği sağlamak. Ama bundan çok
uzağım

3
Tamam, anlıyorum, ama kod daha az eksiksiz, daha az iddialı bir proje için kullanılabilir gibi görünüyor, değil mi?
TaW

1
Şu anki haliyle ... pek değil. Ama onu biraz kararlı ve tutarlı hale getirdiğimde GitHub'da yayınlamayı planlıyorum.
György Kőszeg

Yönetilmeyen DLL'leri kullanma zorunluluğu dışında bu gerçekten harika görünüyor. Ayrıca, kütüphanelerin gelişimini nasıl takip edebiliriz?
Bir kulağakaçan

57

ASCII 219 (█) 'u iki kez kullanırsanız, piksel (██) gibi bir şeye sahip olursunuz. Artık konsol uygulamanızdaki piksel miktarı ve renk sayısı ile kısıtlısınız.

  • varsayılan ayarları korursanız yaklaşık 39x39 pikseliniz varsa, daha fazlasını isterseniz konsolunuzu Console.WindowHeight = resSize.Height + 1;ve ile yeniden boyutlandırabilirsiniz. Console.WindowWidth = resultSize.Width * 2;

  • Görüntünün en boy oranını olabildiğince uzak tutmalısınız, böylece çoğu durumda 39x39'a sahip olmazsınız

  • Malwyn , dönüştürmek System.Drawing.Coloriçin tamamen hafife alınmış bir yöntem yayınladıSystem.ConsoleColor

bu yüzden benim yaklaşımım

using System.Drawing;

public static int ToConsoleColor(System.Drawing.Color c)
{
    int index = (c.R > 128 | c.G > 128 | c.B > 128) ? 8 : 0;
    index |= (c.R > 64) ? 4 : 0;
    index |= (c.G > 64) ? 2 : 0;
    index |= (c.B > 64) ? 1 : 0;
    return index;
}

public static void ConsoleWriteImage(Bitmap src)
{
    int min = 39;
    decimal pct = Math.Min(decimal.Divide(min, src.Width), decimal.Divide(min, src.Height));
    Size res = new Size((int)(src.Width * pct), (int)(src.Height * pct));
    Bitmap bmpMin = new Bitmap(src, res);
    for (int i = 0; i < res.Height; i++)
    {
        for (int j = 0; j < res.Width; j++)
        {
            Console.ForegroundColor = (ConsoleColor)ToConsoleColor(bmpMin.GetPixel(j, i));
            Console.Write("██");
        }
        System.Console.WriteLine();
    }
}

Böylece yapabilirsiniz

ConsoleWriteImage(new Bitmap(@"C:\image.gif"));

örnek giriş:

görüntü açıklamasını buraya girin

örnek çıktı:

görüntü açıklamasını buraya girin


7
@willywonka_dailyblah - Day of the Tentacle'daki mor dokunaç. Not Doom
Blaatz0r

@ Blaatz0r yani Doom benzeri grafikler ... imma yeni bir çocuk bloğunda sadece

3
Hepsi affedildi :-p. Şansınız varsa, dokunaç eski ama harika bir oyunsa Day'i deneyin.
Blaatz0r

38

bu eğlenceliydi. Teşekkürler fubo , çözümünüzü denedim ve önizlemenin çözünürlüğünü 4 (2x2) artırabildim.

Her bir karakter için arka plan rengini ayarlayabileceğinizi öğrendim. Bu yüzden, iki ASCII 219 (█) karakter kullanmak yerine, ASCII 223 (▀) 'yi iki kez farklı ön plan ve arka plan renkleri ile kullandım. Bu, büyük Pikseli (██) 4 alt piksele böler (▀▄).

Bu örnekte, aradaki farkı kolayca görebilmeniz için her iki resmi de yan yana koydum:

görüntü açıklamasını buraya girin

İşte kod:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace ConsoleWithImage
{
  class Program
  {

    public static void ConsoleWriteImage(Bitmap bmpSrc)
    {
        int sMax = 39;
        decimal percent = Math.Min(decimal.Divide(sMax, bmpSrc.Width), decimal.Divide(sMax, bmpSrc.Height));
        Size resSize = new Size((int)(bmpSrc.Width * percent), (int)(bmpSrc.Height * percent));
        Func<System.Drawing.Color, int> ToConsoleColor = c =>
        {
            int index = (c.R > 128 | c.G > 128 | c.B > 128) ? 8 : 0;
            index |= (c.R > 64) ? 4 : 0;
            index |= (c.G > 64) ? 2 : 0;
            index |= (c.B > 64) ? 1 : 0;
            return index;
        };
        Bitmap bmpMin = new Bitmap(bmpSrc, resSize.Width, resSize.Height);
        Bitmap bmpMax = new Bitmap(bmpSrc, resSize.Width * 2, resSize.Height * 2);
        for (int i = 0; i < resSize.Height; i++)
        {
            for (int j = 0; j < resSize.Width; j++)
            {
                Console.ForegroundColor = (ConsoleColor)ToConsoleColor(bmpMin.GetPixel(j, i));
                Console.Write("██");
            }

            Console.BackgroundColor = ConsoleColor.Black;
            Console.Write("    ");

            for (int j = 0; j < resSize.Width; j++)
            {
                Console.ForegroundColor = (ConsoleColor)ToConsoleColor(bmpMax.GetPixel(j * 2, i * 2));
                Console.BackgroundColor = (ConsoleColor)ToConsoleColor(bmpMax.GetPixel(j * 2, i * 2 + 1));
                Console.Write("▀");

                Console.ForegroundColor = (ConsoleColor)ToConsoleColor(bmpMax.GetPixel(j * 2 + 1, i * 2));
                Console.BackgroundColor = (ConsoleColor)ToConsoleColor(bmpMax.GetPixel(j * 2 + 1, i * 2 + 1));
                Console.Write("▀");
            }
            System.Console.WriteLine();
        }
    }

    static void Main(string[] args)
    {
        System.Console.WindowWidth = 170;
        System.Console.WindowHeight = 40;

        Bitmap bmpSrc = new Bitmap(@"image.bmp", true);

        ConsoleWriteImage(bmpSrc);

        System.Console.ReadLine();
    }
  }
}

Örneği çalıştırmak için, "image.bmp" bit eşleminin yürütülebilir dosya ile aynı dizinde olması gerekir. Konsolun boyutunu artırdım, önizlemenin boyutu hala 39 ve şu adresten değiştirilebilirint sMax = 39; .

Taffer'in çözümü de çok güzel. Siz ikiniz benim oyumu aldınız ...


24

Renk uzayları hakkında okuyordum ve LAB alanı sizin için iyi bir seçenek gibi görünüyor (şu sorulara bakın: Renklerin benzerliğini kontrol etmek için renkler ve Algoritma arasında doğru bir "mesafe" bulma )

Wikipedia CIELAB sayfasından alıntı yapıldığında, bu renk uzayının avantajları şunlardır:

RGB ve CMYK renk modellerinden farklı olarak, Lab rengi insan görüşüne yakın olacak şekilde tasarlanmıştır. Algısal tekdüzelik arzular ve L bileşeni, insanın hafiflik algısıyla yakından eşleşir. Böylece, a ve b bileşenlerinde çıktı eğrilerini değiştirerek doğru renk dengesi düzeltmeleri yapmak için kullanılabilir.

Renkler arasındaki mesafeyi ölçmek için Delta E mesafesini kullanabilirsiniz .

Bununla, aşağıdakilerden daha iyi bir sonuç elde Coloredebilirsiniz ConsoleColor:

İlk olarak, CieLabbu alandaki renkleri temsil edecek bir sınıf tanımlayabilirsiniz :

public class CieLab
{
    public double L { get; set; }
    public double A { get; set; }
    public double B { get; set; }

    public static double DeltaE(CieLab l1, CieLab l2)
    {
        return Math.Pow(l1.L - l2.L, 2) + Math.Pow(l1.A - l2.A, 2) + Math.Pow(l1.B - l2.B, 2);
    }

    public static CieLab Combine(CieLab l1, CieLab l2, double amount)
    {
        var l = l1.L * amount + l2.L * (1 - amount);
        var a = l1.A * amount + l2.A * (1 - amount);
        var b = l1.B * amount + l2.B * (1 - amount);

        return new CieLab { L = l, A = a, B = b };
    }
}

Biri Delta E ( DeltaE) kullanarak mesafeyi ölçmek ve diğeri her bir rengin ne kadarını ( Combine) belirten iki rengi birleştirmek için iki statik yöntem vardır .

Ve gelen dönüşümü için RGBiçin LABaşağıdaki yöntemi (den kullanabilirsiniz burada ):

public static CieLab RGBtoLab(int red, int green, int blue)
{
    var rLinear = red / 255.0;
    var gLinear = green / 255.0;
    var bLinear = blue / 255.0;

    double r = rLinear > 0.04045 ? Math.Pow((rLinear + 0.055) / (1 + 0.055), 2.2) : (rLinear / 12.92);
    double g = gLinear > 0.04045 ? Math.Pow((gLinear + 0.055) / (1 + 0.055), 2.2) : (gLinear / 12.92);
    double b = bLinear > 0.04045 ? Math.Pow((bLinear + 0.055) / (1 + 0.055), 2.2) : (bLinear / 12.92);

    var x = r * 0.4124 + g * 0.3576 + b * 0.1805;
    var y = r * 0.2126 + g * 0.7152 + b * 0.0722;
    var z = r * 0.0193 + g * 0.1192 + b * 0.9505;

    Func<double, double> Fxyz = t => ((t > 0.008856) ? Math.Pow(t, (1.0 / 3.0)) : (7.787 * t + 16.0 / 116.0));

    return new CieLab
    {
        L = 116.0 * Fxyz(y / 1.0) - 16,
        A = 500.0 * (Fxyz(x / 0.9505) - Fxyz(y / 1.0)),
        B = 200.0 * (Fxyz(y / 1.0) - Fxyz(z / 1.0890))
    };
}

Fikir, @AntoninLejsek do ('█', '▓', '▒', '░') gibi gölge karakterleri kullanmaktır, bu, konsol renklerini birleştirerek ( Combineyöntemi kullanarak ) 16'dan fazla renk elde etmenizi sağlar .

Burada, kullanılacak renkleri önceden hesaplayarak bazı iyileştirmeler yapabiliriz:

class ConsolePixel
{
    public char Char { get; set; }

    public ConsoleColor Forecolor { get; set; }
    public ConsoleColor Backcolor { get; set; }
    public CieLab Lab { get; set; }
}

static List<ConsolePixel> pixels;
private static void ComputeColors()
{
    pixels = new List<ConsolePixel>();

    char[] chars = { '█', '▓', '▒', '░' };

    int[] rs = { 0, 0, 0, 0, 128, 128, 128, 192, 128, 0, 0, 0, 255, 255, 255, 255 };
    int[] gs = { 0, 0, 128, 128, 0, 0, 128, 192, 128, 0, 255, 255, 0, 0, 255, 255 };
    int[] bs = { 0, 128, 0, 128, 0, 128, 0, 192, 128, 255, 0, 255, 0, 255, 0, 255 };

    for (int i = 0; i < 16; i++)
        for (int j = i + 1; j < 16; j++)
        {
            var l1 = RGBtoLab(rs[i], gs[i], bs[i]);
            var l2 = RGBtoLab(rs[j], gs[j], bs[j]);

            for (int k = 0; k < 4; k++)
            {
                var l = CieLab.Combine(l1, l2, (4 - k) / 4.0);

                pixels.Add(new ConsolePixel
                {
                    Char = chars[k],
                    Forecolor = (ConsoleColor)i,
                    Backcolor = (ConsoleColor)j,
                    Lab = l
                });
            }
        }
}

Diğer bir iyileştirme, kullanmak LockBitsyerine kullanarak doğrudan görüntü verilerine erişim olabilir.GetPixel .

GÜNCELLEME : Görüntünün aynı renkte bölümleri varsa, tek tek karakterler yerine aynı renklere sahip karakter yığınlarını çizme sürecini önemli ölçüde hızlandırabilirsiniz:

public static void DrawImage(Bitmap source)
{
    int width = Console.WindowWidth - 1;
    int height = (int)(width * source.Height / 2.0 / source.Width);

    using (var bmp = new Bitmap(source, width, height))
    {
        var unit = GraphicsUnit.Pixel;
        using (var src = bmp.Clone(bmp.GetBounds(ref unit), PixelFormat.Format24bppRgb))
        {
            var bits = src.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, src.PixelFormat);
            byte[] data = new byte[bits.Stride * bits.Height];

            Marshal.Copy(bits.Scan0, data, 0, data.Length);

            for (int j = 0; j < height; j++)
            {
                StringBuilder builder = new StringBuilder();
                var fore = ConsoleColor.White;
                var back = ConsoleColor.Black;

                for (int i = 0; i < width; i++)
                {
                    int idx = j * bits.Stride + i * 3;
                    var pixel = DrawPixel(data[idx + 2], data[idx + 1], data[idx + 0]);


                    if (pixel.Forecolor != fore || pixel.Backcolor != back)
                    {
                        Console.ForegroundColor = fore;
                        Console.BackgroundColor = back;
                        Console.Write(builder);

                        builder.Clear();
                    }

                    fore = pixel.Forecolor;
                    back = pixel.Backcolor;
                    builder.Append(pixel.Char);
                }

                Console.ForegroundColor = fore;
                Console.BackgroundColor = back;
                Console.WriteLine(builder);
            }

            Console.ResetColor();
        }
    }
}

private static ConsolePixel DrawPixel(int r, int g, int b)
{
    var l = RGBtoLab(r, g, b);

    double diff = double.MaxValue;
    var pixel = pixels[0];

    foreach (var item in pixels)
    {
        var delta = CieLab.DeltaE(l, item.Lab);
        if (delta < diff)
        {
            diff = delta;
            pixel = item;
        }
    }

    return pixel;
}

Son olarak, şöyle arayın DrawImage:

static void Main(string[] args)
{
    ComputeColors();

    Bitmap image = new Bitmap("image.jpg", true);
    DrawImage(image);

}

Sonuç Resimleri:

Konsol1

Konsol2



Aşağıdaki çözümler karakterlere dayalı olmayıp tam ayrıntılı görüntüler sağlar


Bir nesne oluşturmak için işleyicisini kullanarak herhangi bir pencerenin üzerine çizim yapabilirsiniz Graphics. Bir konsol uygulamasının işleyicisini almak için şunu içe aktarabilirsiniz GetConsoleWindow:

[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow", SetLastError = true)]
private static extern IntPtr GetConsoleHandle();

Ardından, işleyiciyle (kullanarak Graphics.FromHwnd) bir grafik oluşturun ve Graphicsnesnedeki yöntemleri kullanarak görüntüyü çizin, örneğin:

static void Main(string[] args)
{            
    var handler = GetConsoleHandle();

    using (var graphics = Graphics.FromHwnd(handler))
    using (var image = Image.FromFile("img101.png"))
        graphics.DrawImage(image, 50, 50, 250, 200);
}

Versiyon 1

Bu iyi görünüyor, ancak konsol yeniden boyutlandırılırsa veya kaydırılırsa, görüntü kaybolur çünkü pencereler yenilenir (belki de sizin durumunuzda görüntüyü yeniden çizmek için bir tür mekanizma uygulamak mümkündür).


Diğer bir çözüm, Formkonsol uygulamasına bir pencere ( ) yerleştirmektir . Bunu yapmak için içeri aktarmanız SetParent(ve MoveWindowkonsolun içindeki pencereyi yeniden konumlandırmanız) gerekir:

[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

Sonra sadece bir oluşturmanız gerekir Formve set BackgroundImageistenen görüntüye özelliği (a bunu yapmak Threadveya Taskkonsol engelleme önlemek için):

static void Main(string[] args)
{
    Task.Factory.StartNew(ShowImage);

    Console.ReadLine();
}

static void ShowImage()
{
    var form = new Form
    {                
        BackgroundImage = Image.FromFile("img101.png"),
        BackgroundImageLayout = ImageLayout.Stretch
    };

    var parent = GetConsoleHandle();
    var child = form.Handle;

    SetParent(child, parent);
    MoveWindow(child, 50, 50, 250, 200, true);

    Application.Run(form);
}

Versiyon 2

Tabii ki FormBorderStyle = FormBorderStyle.Nonepencere kenarlıklarını gizlemeyi ayarlayabilirsiniz (sağdaki resim)

Bu durumda konsolu yeniden boyutlandırabilirsiniz ve görüntü / pencere hala orada olabilir.

Bu yaklaşımın bir yararı, pencereyi istediğiniz yere yerleştirebilmeniz ve sadece BackgroundImageözelliği değiştirerek istediğiniz zaman görüntüyü değiştirebilmenizdir .


Çabanız için teşekkürler, ancak yaklaşımınız Antonín Lejsek'in çözümünden 6 kat daha yavaş. Her neyse çok ilginç Tur sonucu.
Byyo

4

Doğrudan bir yolu yok. Ama böyle bir görüntü-ascii-art dönüştürücü kullanmak deneyebilirsiniz bu bir


:-) ancak, konsolun (pencerenin) renk yeteneklerinin de oldukça sınırlı olduğunu unutmayın. Yani "solma" efektleri vb. Mümkün bile değil.
Christian.K

1
Pekala, çözünürlüğe
uyuyor

1
@ Christian.K Antonín
Lejsek'in

0

Evet, FormKonsol uygulamasından a açarak soruyu biraz esnetirseniz yapabilirsiniz.

Konsol uygulamanızın bir formu açmasını ve bir görüntüyü görüntülemesini şu şekilde yapabilirsiniz:

  • projenize şu iki referansı dahil edin: System.DrawingveSystem.Windows.Forms
  • iki ad alanını da dahil edin:

using System.Windows.Forms;
using System.Drawing;

Bunu nasıl yapacağınıza dair bu gönderiye bakın !

Şimdi buna benzer bir şey eklemek için ihtiyacınız olan her şey:

Form form1 = new Form();
form1.BackgroundImage = bmp;
form1.ShowDialog();

Elbette bir PictureBox..

form1.Show();Önizleme gösterilirken konsolu canlı tutmak için kullanabilirsiniz ..

Orijinal gönderi: Elbette 25x80'lik bir pencere içinde bir görüntüyü düzgün şekilde görüntüleyemezsiniz ; Daha büyük bir pencere kullansanız ve grafikleri engelleseniz bile, bu bir önizleme değil, karmaşa olur!

Güncelleme: Görünüşe göre GDI konsol formuna bir resim çizebiliyorsunuz; taffer'ın cevabına bakın!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.