Visualizza un'immagine in un'applicazione console


86

Ho un'applicazione console che gestisce le immagini. Ora ho bisogno di qualcosa come un'anteprima delle immagini all'interno dell'applicazione console. C'è un modo per visualizzarli nella console?

Ecco un confronto delle attuali risposte basate sui personaggi:

Ingresso:

inserisci qui la descrizione dell'immagine

Produzione:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


Nella console, come nella finestra della console? No. Tuttavia, potresti avviare una finestra di dialogo / finestra separata.
Christian.K

Le applicazioni console vengono utilizzate principalmente per applicazioni di solo testo. Non è possibile visualizzare un'immagine. È possibile avviare un'altra applicazione che visualizza l'immagine. Quest'altra applicazione molto probabilmente dovrà supportare un'opzione della riga di comando per passare un'immagine ad essa.
Lindos Pechos

Perché usi un'applicazione console? Dove corre? puoi sempre avviare un processo per visualizzare il visualizzatore di immagini predefinito o semplicemente un'app winforms ecc ..
TaW

1
Ho bisogno di un miglioramento del codice di Antonín Lejsek (che è fantastico). Ci sono alcune mancate corrispondenze di colore e con prestazioni migliorate potrei anche visualizzare gif animate
Byyo

Risposte:


58

Ho inoltre giocato con il codice di @DieterMeemken. Ho dimezzato la risoluzione verticale e aggiunto il dithering tramite ░▒▓. A sinistra c'è il risultato di Dieter Meemken, a destra il mio. In basso è l'immagine originale ridimensionata per adattarsi all'output. Risultato di output Sebbene la funzione di conversione di Malwyns sia impressionante, non utilizza tutti i colori grigi, peccato.

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();
}

utilizzo:

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

MODIFICARE

La distanza del colore è un argomento complesso ( qui , qui e link su quelle pagine ...). Ho provato a calcolare la distanza in YUV e i risultati sono stati piuttosto peggiori che in RGB. Potrebbero essere migliori con Lab e DeltaE, ma non l'ho provato. La distanza in RGB sembra essere abbastanza buona. In effetti i risultati sono molto simili sia per la distanza euclidea che per quella di Manhattan nello spazio colore RGB, quindi sospetto che ci siano troppo pochi colori tra cui scegliere.

Il resto è solo un confronto a forza bruta del colore con tutte le combinazioni di colori e motivi (= simboli). Ho dichiarato che il rapporto di riempimento per ░▒▓█ era 1/4, 2/4, 3/4 e 4/4. In tal caso il terzo simbolo è infatti ridondante rispetto al primo. Ma se i rapporti non fossero così uniformi (dipende dal carattere), i risultati potrebbero cambiare, quindi l'ho lasciato lì per miglioramenti futuri. Il colore medio del simbolo viene calcolato come media pesata di foregroudColor e backgroundColor in base al rapporto di riempimento. Assume colori lineari, cosa che è anche grande semplificazione. Quindi c'è ancora spazio per miglioramenti.


Grazie @fubo. A proposito, ho sperimentato RGB con correzione gamma e Lab ed entrambi sono stati migliorati. Ma il rapporto di riempimento doveva essere impostato in modo che corrispondesse al carattere utilizzato e non funzionava affatto per i caratteri TrueType. Quindi non sarebbe più stata una taglia unica.
Antonín Lejsek

90

Sebbene mostrare un'immagine in una console non sia l'uso previsto della console, puoi sicuramente hackerare le cose, poiché la finestra della console è solo una finestra, come qualsiasi altra finestra.

In realtà, una volta che ho iniziato a sviluppare una libreria di controlli di testo per applicazioni console con supporto grafico. Non l'ho mai finito, anche se ho una demo di prova funzionante:

Controlli di testo con immagine

E se ottieni la dimensione del carattere della console, puoi posizionare l'immagine in modo molto preciso.

Ecco come puoi farlo:

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);
        }
    }
}

Ecco come ottenere la dimensione del carattere della console corrente:

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);            
}

E le chiamate, le costanti e i tipi WinApi aggiuntivi richiesti:

[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;

E il risultato:

[Grafica nella console


2
Wow, è davvero interessante! Potresti per favore elaborare un po 'cosa intendi per non l'ho mai finito, anche se ho una demo funzionante ? Qualche inconveniente o solo lo smalto mancante ..?
TaW

Significa che il progetto è molto incompleto. Ho realizzato l'architettura di base, l'ambiente OO di base basato sugli eventi, il supporto del mouse, il message pump, ecc. Ma mancano ancora anche i controlli più fondamentali come Button, TextBoxecc. Il mio sogno è creare un supporto XAML abbastanza completo con l'associazione dei dati e con la filosofia "incorporare qualsiasi cosa in qualsiasi cosa" simile a WPF. Ma sono molto lontano da quello ... beh, in questo momento :)
György Kőszeg

3
OK, capisco, ma sembra che il codice possa essere utilizzato per qualsiasi progetto meno completo e meno ambizioso, sì?
TaW

1
Ebbene, nella sua forma attuale ... non proprio. Ma ho intenzione di pubblicarlo su GitHub una volta che lo avrò reso in qualche modo stabile e coerente.
György Kőszeg

Sembra davvero interessante, tranne per la necessità di utilizzare DLL non gestite. Inoltre, come possiamo tenere traccia dello sviluppo delle librerie?
una forbicina il

57

Se usi ASCII 219 (█) due volte, hai qualcosa come un pixel (██). Ora sei limitato dalla quantità di pixel e dal numero di colori nella tua applicazione console.

  • se mantieni le impostazioni di default hai circa 39x39 pixel, se vuoi di più puoi ridimensionare la tua console con Console.WindowHeight = resSize.Height + 1;eConsole.WindowWidth = resultSize.Width * 2;

  • devi mantenere le proporzioni dell'immagine il più lontano possibile, quindi non avrai 39x39 nella maggior parte dei casi

  • Malwyn pubblicato un metodo totalmente sottovalutato per convertire System.Drawing.ColoraSystem.ConsoleColor

quindi il mio approccio sarebbe

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();
    }
}

così puoi

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

input di esempio:

inserisci qui la descrizione dell'immagine

output di esempio:

inserisci qui la descrizione dell'immagine


7
@willywonka_dailyblah - È il tentacolo viola di Day of the Tentacle. Not Doom
Blaatz0r

@ Blaatz0r intendo grafica simile a Doom ... imma new kid on the block I only know Doom

3
Tutto è perdonato :-p. Se mai ne hai la possibilità, prova Day se il tentacolo è un grande gioco vecchio ma fantastico.
Blaatz,

38

è stato divertente. Grazie fubo , ho provato la tua soluzione e sono riuscito ad aumentare la risoluzione dell'anteprima di 4 (2x2).

Ho scoperto che puoi impostare il colore di sfondo per ogni singolo carattere. Quindi, invece di usare due caratteri ASCII 219 (█), ho usato ASCII 223 (▀) due volte con colori di primo piano e di sfondo diversi. Questo divide il grande Pixel (██) in 4 subpixel come questo (▀▄).

In questo esempio metto entrambe le immagini una accanto all'altra, così puoi vedere facilmente la differenza:

inserisci qui la descrizione dell'immagine

Ecco il codice:

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();
    }
  }
}

Per eseguire l'esempio, la bitmap "image.bmp" deve trovarsi nella stessa directory dell'eseguibile. Ho aumentato la dimensione della console, la dimensione dell'anteprima è ancora 39 e può essere modificata in int sMax = 39;.

Anche la soluzione di taffer è molto fresca. Voi due avete il mio voto positivo ...


24

Stavo leggendo degli spazi colore e lo spazio LAB sembra essere una buona opzione per te (vedi queste domande: Trovare una "distanza" accurata tra i colori e l' algoritmo per verificare la somiglianza dei colori )

Citando la pagina CIELAB di Wikipedia , i vantaggi di questo spazio colore sono:

A differenza dei modelli di colore RGB e CMYK, Lab color è progettato per approssimare la visione umana. Aspira all'uniformità percettiva e la sua componente L corrisponde strettamente alla percezione umana della leggerezza. Pertanto, può essere utilizzato per effettuare correzioni accurate del bilanciamento del colore modificando le curve di output nei componenti a e b.

Per misurare la distanza tra i colori è possibile utilizzare la distanza Delta E.

Con questo puoi approssimare meglio da Colora ConsoleColor:

Innanzitutto, puoi definire una CieLabclasse per rappresentare i colori in questo spazio:

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 };
    }
}

Esistono due metodi statici, uno per misurare la distanza utilizzando Delta E ( DeltaE) e l'altro per combinare due colori specificando la quantità di ciascun colore ( Combine).

E per trasformare da RGBa LABpuoi usare il seguente metodo (da qui ):

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))
    };
}

L'idea è usare caratteri sfumati come @AntoninLejsek do ('█', '▓', '▒', '░'), questo ti permette di ottenere più di 16 colori combinando i colori della console (usando il Combinemetodo).

Qui, possiamo apportare alcuni miglioramenti pre-calcolando i colori da utilizzare:

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
                });
            }
        }
}

Un altro miglioramento potrebbe essere l'accesso diretto ai dati dell'immagine utilizzando LockBitsinvece di utilizzare GetPixel.

AGGIORNAMENTO : Se l'immagine ha parti con lo stesso colore puoi velocizzare notevolmente il processo disegnando pezzi di caratteri con gli stessi colori, invece di singoli caratteri:

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;
}

Infine, chiama in questo DrawImagemodo:

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

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

}

Immagini dei risultati:

Console 1

Console2



Le seguenti soluzioni non si basano sui caratteri ma forniscono immagini dettagliate complete


Puoi disegnare su qualsiasi finestra usando il suo gestore per creare un Graphicsoggetto. Per ottenere il gestore di un'applicazione console puoi farlo importando GetConsoleWindow:

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

Quindi, crea una grafica con il gestore (usando Graphics.FromHwnd) e disegna l'immagine usando i metodi in Graphicsoggetto, ad esempio:

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);
}

Versione 1

Questo sembra a posto, ma se la console viene ridimensionata o fatta scorrere, l'immagine scompare perché le finestre vengono aggiornate (forse nel tuo caso è possibile implementare una sorta di meccanismo per ridisegnare l'immagine).


Un'altra soluzione è incorporare una finestra ( Form) nell'applicazione console. Per fare questo devi importare SetParent(e MoveWindowriposizionare la finestra all'interno della console):

[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);

Quindi devi solo creare Forme impostare la BackgroundImageproprietà sull'immagine desiderata (fallo su a Threado Taskper evitare di bloccare la console):

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);
}

Version2

Ovviamente puoi impostare FormBorderStyle = FormBorderStyle.Noneper nascondere i bordi delle finestre (immagine a destra)

In questo caso puoi ridimensionare la console e l'immagine / finestra sarà ancora lì.

Un vantaggio di questo approccio è che puoi posizionare la finestra dove vuoi e cambiare l'immagine in qualsiasi momento semplicemente cambiando la BackgroundImageproprietà.


Grazie per il tuo impegno, ma il tuo approccio è 6 volte più lento della soluzione di Antonín Lejsek. Comunque risultato sul giro molto interessante.
Byyo

4

Non esiste un modo diretto. Ma potresti provare a usare un convertitore da immagine ad arte ascii come questo


:-) tuttavia, nota che anche le capacità di colore della console (finestra) sono piuttosto limitate. Quindi effetti di "dissolvenza", ecc. Non sono nemmeno possibili.
Christian.K

1
Bene, corrisponde alla risoluzione: P
DarkWanderer

1
@ Christian.K La risposta di Antonín Lejsek rende possibile lo sbiadimento
Byyo

0

Sì, puoi farlo, se estendi un po 'la domanda aprendo un Formdall'interno dell'applicazione Console.

Ecco come puoi fare in modo che l'applicazione console apra un modulo e visualizzi un'immagine:

  • includi questi due riferimenti nel tuo progetto: System.DrawingeSystem.Windows.Forms
  • includere anche i due spazi dei nomi:

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

Guarda questo post su come farlo !

Ora tutto ciò che serve per aggiungere qualcosa del genere:

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

Ovviamente puoi anche usare un PictureBox..

E puoi usare form1.Show();per mantenere viva la console mentre viene mostrata l'anteprima ..

Post originale: Ovviamente non puoi visualizzare correttamente un'immagine all'interno di una finestra 25x80; anche se usi una finestra più grande e blocchi la grafica non sarebbe un'anteprima ma un pasticcio!

Aggiornamento: sembra che dopo tutto sia possibile disegnare un'immagine GDI sul modulo della console; vedi la risposta di taffer!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.