Exibir uma imagem em um aplicativo de console

86

Tenho um aplicativo de console que gerencia imagens. Agora preciso de algo como uma visualização das imagens no aplicativo de console. Existe uma maneira de exibi-los no console?

Aqui está uma comparação das respostas atuais baseadas em caracteres:

Entrada:

insira a descrição da imagem aqui

Resultado:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Byyo
fonte
No console, como na janela do console? Não. Você poderia iniciar uma caixa de diálogo / janela separada, no entanto.
Christian.K
Os aplicativos de console são usados ​​principalmente para aplicativos somente de texto. Não há como exibir uma imagem. Você pode iniciar outro aplicativo que exiba a imagem. Este outro aplicativo provavelmente precisaria suportar uma opção de linha de comando para passar uma imagem para ele.
Lindos Pechos
Por que você usa um aplicativo de console? Onde funciona? você sempre pode iniciar um processo para abrir o visualizador de imagens padrão ou simplesmente um aplicativo winforms etc. de sua preferência.
TaW
1
Eu preciso melhorar o código de Antonín Lejsek (que é ótimo). Existem alguns erros de combinação de cores e com o desempenho aprimorado, eu poderia exibir gifs animados também
Byyo

Respostas:

58

Continuei brincando com o código de @DieterMeemken. Reduzi pela metade a resolução vertical e adicionei pontilhamento via ░▒▓. À esquerda está o resultado de Dieter Meemken, à direita meu. Na parte inferior está a imagem original redimensionada para coincidir com a saída. Resultado de saída Embora a função de conversão do Malwyn seja impressionante, ela não usa todas as cores cinza, o que é uma pena.

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

uso:

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

EDITAR

Distância de cor é um tópico complexo ( aqui , aqui e links nessas páginas ...). Tentei calcular a distância em YUV e os resultados foram piores do que em RGB. Eles poderiam ser melhores com Lab e DeltaE, mas eu não tentei isso. A distância em RGB parece ser boa o suficiente. Na verdade, os resultados são muito semelhantes para as distâncias de euclidiana e manhattan no espaço de cores RGB, então eu suspeito que há poucas cores para escolher.

O resto é apenas comparação de força bruta de cor contra todas as combinações de cores e padrões (= símbolos). Eu declarei que a proporção de preenchimento para ░▒▓█ é 1/4, 2/4, 3/4 e 4/4. Nesse caso, o terceiro símbolo é de fato redundante para o primeiro. Mas se as proporções não fossem tão uniformes (depende da fonte), os resultados poderiam mudar, então eu deixei lá para melhorias futuras. A cor média do símbolo é calculada como a média ponderada de foregroudColor e backgroundColor de acordo com a proporção de preenchimento. Assume cores lineares, o que também é uma grande simplificação. Portanto, ainda há espaço para melhorias.

Antonín Lejsek
fonte
Obrigado @fubo. Btw eu experimentei com RGB corrigido por gama e Lab e ambos foram melhorias. Mas a taxa de preenchimento teve que ser definida para corresponder à fonte usada e não funcionou de forma alguma para fontes TrueType. Portanto, não seria mais solução única.
Antonín Lejsek
90

Embora mostrar uma imagem em um console não seja o uso pretendido do console, você certamente pode hackear as coisas, já que a janela do console é apenas uma janela, como qualquer outra janela.

Na verdade, uma vez comecei a desenvolver uma biblioteca de controles de texto para aplicativos de console com suporte gráfico. Nunca terminei isso, embora tenha uma demonstração de prova de conceito funcionando:

Controles de texto com imagem

E se você obtiver o tamanho da fonte do console, poderá posicionar a imagem com muita precisão.

É assim que você pode fazer:

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

Veja como você pode obter o tamanho da fonte do console atual:

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 as chamadas WinApi adicionais necessárias, constantes e tipos:

[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 o resultado:

[Gráficos no console

György Kőszeg
fonte
2
Uau, isso é realmente interessante! Você poderia explicar um pouco o que quer dizer com eu nunca terminei isso, embora eu tenha uma demonstração de prova de conceito funcionando ? Alguma desvantagem ou apenas a falta de polimento ..?
TaW
Isso significa que o projeto está muito incompleto. Fiz a arquitetura básica, o ambiente OO baseado em eventos, o suporte ao mouse, a bomba de mensagem, etc. Mas mesmo os controles mais fundamentais, como etc Button, TextBoxainda estão faltando. Meu sonho é fazer um suporte XAML razoavelmente completo com vinculação de dados e com a filosofia "incorporar qualquer coisa em qualquer coisa" semelhante ao WPF. Mas estou muito longe disso ... bem, neste momento :)
György Kőszeg
3
OK, entendo, mas o código parece que pode ser usado para qualquer projeto menos completo e menos ambicioso, certo?
TaW
1
Bem, em sua forma atual ... não realmente. Mas pretendo publicá-lo no GitHub assim que torná-lo um tanto estável e coerente.
György Kőszeg
Isso parece muito legal, exceto pela necessidade de usar DLLs não gerenciadas. Além disso, como podemos acompanhar o desenvolvimento das bibliotecas?
uma tesourinha de
57

Se você usar ASCII 219 (█) duas vezes, terá algo como um pixel (██). Agora você está restrito pela quantidade de pixels e pelo número de cores em seu aplicativo de console.

  • se você manter as configurações padrão que você tem sobre 39x39 pixel, se você quiser mais você pode redimensionar a sua consola com Console.WindowHeight = resSize.Height + 1;eConsole.WindowWidth = resultSize.Width * 2;

  • você tem que manter a proporção da imagem o mais longe possível, então você não terá 39x39 na maioria dos casos

  • Malwyn postou um método totalmente subestimado para converter System.Drawing.ColorparaSystem.ConsoleColor

então minha abordagem seria

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

então você pode

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

amostra de entrada:

insira a descrição da imagem aqui

saída de amostra:

insira a descrição da imagem aqui

fubo
fonte
7
@willywonka_dailyblah - É o tentáculo roxo do Dia do Tentáculo. Not Doom
Blaatz0r
@ Blaatz0r quero dizer gráficos parecidos com Doom ... sou novo garoto no bloco, eu só conheço Doom
3
Tudo está perdoado :-p. Se você tiver a chance, tente Day se o tentáculo é um grande jogo antigo, mas ótimo.
Blaatz0r de
38

foi divertido. Obrigado fubo , tentei a sua solução e consegui aumentar a resolução da pré-visualização em 4 (2x2).

Eu descobri que você pode definir a cor de fundo para cada caractere individual. Então, em vez de usar dois caracteres ASCII 219 (█), usei ASCII 223 (▀) duas vezes com cores diferentes de primeiro e segundo plano. Isso divide o grande Pixel (██) em 4 subpixels como este (▀▄).

Neste exemplo, coloquei as duas imagens uma ao lado da outra, para que você possa ver a diferença facilmente:

insira a descrição da imagem aqui

Aqui está o código:

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

Para executar o exemplo, o bitmap "image.bmp" deve estar no mesmo diretório do executável. Aumentei o tamanho do console, o tamanho da visualização ainda é 39 e pode ser alterado emint sMax = 39; .

A solução da taffer também é muito legal. Vocês dois têm meu voto positivo ...

Dieter Meemken
fonte
24

Eu estava lendo sobre espaços de cores e o espaço LAB parece ser uma boa opção para você (veja estas perguntas: Encontrar uma “distância” precisa entre as cores e o algoritmo para verificar a similaridade das cores )

Citando a página CIELAB da Wikipedia , as vantagens deste espaço de cores são:

Ao contrário dos modelos de cores RGB e CMYK, as cores Lab são projetadas para aproximar a visão humana. Ele aspira a uniformidade perceptual e seu componente L corresponde à percepção humana de leveza. Portanto, ele pode ser usado para fazer correções precisas de equilíbrio de cores, modificando as curvas de saída nos componentes a e b.

Para medir a distância entre as cores, você pode usar a distância Delta E.

Com isso você pode aproximar melhor de Colora ConsoleColor:

Em primeiro lugar, você pode definir uma CieLabclasse para representar as cores neste espaço:

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

Existem dois métodos estáticos, um para medir a distância usando Delta E ( DeltaE) e outro para combinar duas cores especificando quanto de cada cor (Combine ).

E para transformar de RGBem, LABvocê pode usar o seguinte método (a partir daqui ):

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

A ideia é usar caracteres de sombra como @AntoninLejsek do ('█', '▓', '▒', '░'), isso permite que você obtenha mais de 16 cores combinando as cores do console (usando o Combinemétodo).

Aqui, podemos fazer algumas melhorias ao pré-calcular as cores a serem usadas:

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

Outra melhoria pode ser o acesso direto aos dados da imagem usando em LockBitsvez de usar GetPixel.

ATUALIZAÇÃO : Se a imagem tiver partes com a mesma cor você pode acelerar consideravelmente o processo de desenho de pedaços de caracteres com as mesmas cores, ao invés de caracteres individuais:

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

Finalmente, chame DrawImageassim:

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

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

}

Imagens de resultado:

Console1

Console2



As soluções a seguir não são baseadas em caracteres, mas fornecem imagens detalhadas completas


Você pode desenhar sobre qualquer janela usando seu manipulador para criar um Graphicsobjeto. Para obter o manipulador de um aplicativo de console, você pode importá-lo GetConsoleWindow:

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

Em seguida, crie um gráfico com o manipulador (usando Graphics.FromHwnd) e desenhe a imagem usando os métodos em Graphicsobjeto, por exemplo:

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

Versão 1

Parece bom, mas se o console for redimensionado ou rolado, a imagem desaparece porque a janela é atualizada (talvez seja possível implementar algum tipo de mecanismo para redesenhar a imagem no seu caso).


Outra solução é embutir uma janela ( Form) no aplicativo de console. Para fazer isso, você deve importar SetParent(e MoveWindowrealocar a janela dentro do 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);

Então você só precisa criar uma propriedade Forme definir BackgroundImagea imagem desejada (faça em a Threadou Taskpara evitar bloquear o 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);
}

Versão 2

Claro que você pode configurar FormBorderStyle = FormBorderStyle.Nonepara ocultar as bordas das janelas (imagem à direita)

Neste caso, você pode redimensionar o console e a imagem / janela ainda estará lá.

Um benefício dessa abordagem é que você pode localizar a janela onde quiser e alterar a imagem a qualquer momento, apenas alterando a BackgroundImagepropriedade.

Arturo Menchaca
fonte
Obrigado pelo seu esforço, mas sua abordagem é 6x mais lenta do que a solução de Antonín Lejsek. De qualquer forma, resultado de volta muito interessante.
Byyo
4

Não há um caminho direto. Mas você pode tentar usar um conversor de imagem para ascii-art como este

DarkWanderer
fonte
:-) no entanto, observe que os recursos de cores do console (janela) também são bastante limitados. Assim, efeitos de "desvanecimento", etc. não são nem possíveis.
Christian.K
1
Bem, corresponde à resolução: P
DarkWanderer
1
A resposta de @Cristian.K Antonín Lejsek torna o desbotamento possível
Byyo
0

Sim, você pode fazer isso, se esticar um pouco a questão abrindo um Formde dentro do aplicativo Console.

Veja como você pode fazer com que seu aplicativo de console abra um formulário e exiba uma imagem:

  • inclua essas duas referências em seu projeto: System.DrawingeSystem.Windows.Forms
  • incluem os dois namespaces também:

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

Veja este post sobre como fazer isso !

Agora tudo o que você precisa para adicionar algo como isto:

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

Claro, você também pode usar um PictureBox..

E você pode usar form1.Show();para manter o console ativo enquanto a visualização é exibida.

Postagem original: é claro que você não pode exibir uma imagem corretamente dentro de uma janela 25x80; mesmo se você usar uma janela maior e bloquear os gráficos, não será uma prévia, mas uma bagunça!

Atualização: Parece que você pode, afinal, desenhar uma imagem com GDI no Formulário do Console; veja a resposta do taffer!

TaW
fonte