Afficher une image dans une application console

85

J'ai une application console qui gère les images. Maintenant, j'ai besoin de quelque chose comme un aperçu des images dans l'application console. Existe-t-il un moyen de les afficher dans la console?

Voici une comparaison des réponses actuelles basées sur les caractères:

Contribution:

entrez la description de l'image ici

Production:

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

Byyo
la source
Dans la console, comme dans la fenêtre de la console? Non. Vous pouvez cependant ouvrir une boîte de dialogue / une fenêtre distincte.
Christian.K
Les applications de console sont principalement utilisées pour les applications de texte uniquement. Il n'y a aucun moyen d'afficher une image. Vous pouvez lancer une autre application qui affiche l'image. Cette autre application devra probablement prendre en charge une option de ligne de commande pour lui transmettre une image.
Lindos Pechos
Pourquoi utilisez-vous une application console? Où va-t-il? vous pouvez toujours démarrer un processus pour afficher la visionneuse d'images par défaut ou simplement une application winforms, etc.
TaW
1
J'ai besoin d'une amélioration du code d'Antonín Lejsek (ce qui est génial). Il y a quelques erreurs de correspondance des couleurs et avec des performances améliorées, je pourrais aussi afficher des gifs animés
Byyo

Réponses:

55

J'ai continué à jouer avec le code de @DieterMeemken. J'ai réduit de moitié la résolution verticale et ajouté du tramage via °. Sur la gauche se trouve le résultat de Dieter Meemken, sur la droite mon. En bas, l'image originale est redimensionnée pour correspondre approximativement à la sortie. Résultat de sortie Si la fonction de conversion Malwyns est impressionnante, elle n'utilise pas toutes les couleurs grises, ce qui est dommage.

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

usage:

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

ÉDITER

La distance de couleur est un sujet complexe ( ici , ici et des liens sur ces pages ...). J'ai essayé de calculer la distance en YUV et les résultats étaient plutôt pires qu'en RVB. Ils pourraient être meilleurs avec Lab et DeltaE, mais je n'ai pas essayé cela. La distance en RVB semble être suffisante. En fait, les résultats sont très similaires pour les distances euclidienne et de Manhattan dans l'espace colorimétrique RVB, donc je suppose qu'il y a trop peu de couleurs parmi lesquelles choisir.

Le reste n'est que la force brute de comparer la couleur à toutes les combinaisons de couleurs et de motifs (= symboles). J'ai indiqué que le taux de remplissage pour ° █ était de 1/4, 2/4, 3/4 et 4/4. Dans ce cas, le troisième symbole est en fait redondant par rapport au premier. Mais si les ratios n'étaient pas aussi uniformes (dépend de la police), les résultats pourraient changer, alors je l'ai laissé là pour de futures améliorations. La couleur moyenne du symbole est calculée en tant que moyenne pondérée de ForegroudColor et backgroundColor en fonction du taux de remplissage. Il suppose des couleurs linéaires, ce qui est également une grande simplification. Il y a donc encore place à l'amélioration.

Antonín Lejsek
la source
Merci @fubo. Btw j'ai expérimenté avec RVB corrigé gamma et Lab et les deux étaient des améliorations. Mais le taux de remplissage devait être réglé pour correspondre à la police utilisée et cela ne fonctionnait pas du tout pour les polices TrueType. Ce ne serait donc plus une solution unique.
Antonín Lejsek
88

Bien que montrer une image dans une console ne soit pas l'utilisation prévue de la console, vous pouvez sûrement pirater les choses, car la fenêtre de la console n'est qu'une fenêtre, comme toutes les autres fenêtres.

En fait, une fois que j'ai commencé à développer une bibliothèque de contrôles de texte pour les applications console avec support graphique. Je n'ai jamais fini cela, même si j'ai une démonstration de démonstration de principe:

Commandes de texte avec image

Et si vous obtenez la taille de police de la console, vous pouvez placer l'image très précisément.

Voici comment vous pouvez le faire:

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

Voici comment obtenir la taille de police actuelle de la console:

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

Et les appels, constantes et types WinApi supplémentaires requis:

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

Et le résultat:

[Graphiques dans la console

György Kőszeg
la source
2
Wow, c'est vraiment intéressant! Pourriez-vous s'il vous plaît expliquer un peu ce que vous entendez par Je n'ai jamais terminé cela, bien que j'aie une démonstration de validation de principe ? Des inconvénients ou juste le vernis manquant ..?
TaW
Cela signifie que le projet est très incomplet. J'ai créé l'architecture de base, l'environnement OO de base basé sur les événements, le support de la souris, la pompe de message, etc. Mais même les contrôles les plus fondamentaux tels que Button, TextBoxetc. sont toujours manquants. Mon rêve est de faire un support XAML assez complet avec liaison de données et avec une philosophie de type WPF "incorporer n'importe quoi dans n'importe quoi". Mais je suis très loin de ça ... enfin, en ce moment :)
György Kőszeg
3
OK, je vois, mais le code semble pouvoir être utilisé pour n'importe quel projet moins complet, moins ambitieux, oui?
TaW
1
Eh bien, dans sa forme actuelle ... pas vraiment. Mais je prévois de le publier sur GitHub une fois que je le rendrai quelque peu stable et cohérent.
György Kőszeg
Cela a l'air vraiment cool, sauf pour la nécessité d'utiliser des DLL non gérées. Aussi, comment pouvons-nous suivre le développement des bibliothèques?
un perce-oreille
56

Si vous utilisez ASCII 219 (█) deux fois, vous avez quelque chose comme un pixel (██). Vous êtes désormais limité par la quantité de pixels et le nombre de couleurs dans votre application console.

  • si vous conservez les paramètres par défaut, vous avez environ 39x39 pixels, si vous en voulez plus, vous pouvez redimensionner votre console avec Console.WindowHeight = resSize.Height + 1;etConsole.WindowWidth = resultSize.Width * 2;

  • vous devez garder le rapport hauteur / largeur de l'image autant que possible, vous n'aurez donc pas 39x39 dans la plupart des cas

  • Malwyn a affiché une méthode totalement sous - estimés pour convertir System.Drawing.ColoràSystem.ConsoleColor

donc mon approche serait

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

afin que vous puissiez

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

exemple d'entrée:

entrez la description de l'image ici

exemple de sortie:

entrez la description de l'image ici

fubo
la source
7
@willywonka_dailyblah - C'est le tentacule violet du jour du tentacule. Not Doom
Blaatz0r
@ Blaatz0r je veux dire des graphismes de type Doom ... imma new kid on teh block I know only Doom
3
Tout est pardonné :-p. Si jamais vous en avez l'occasion, essayez Day si le tentacule est un grand jeu vieux mais génial.
Blaatz0r
37

c'était amusant. Merci fubo , j'ai essayé votre solution et j'ai pu augmenter la résolution de l'aperçu de 4 (2x2).

J'ai trouvé que vous pouvez définir la couleur d'arrière-plan pour chaque caractère individuel. Donc, au lieu d'utiliser deux caractères ASCII 219 (█), j'ai utilisé ASCII 223 (▀) deux fois avec des couleurs de premier plan et d'arrière-plan différentes. Cela divise le gros Pixel (██) en 4 sous-pixels comme celui-ci (▀▄).

Dans cet exemple, je place les deux images l'une à côté de l'autre pour que vous puissiez voir facilement la différence:

entrez la description de l'image ici

Voici le code:

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

Pour exécuter l'exemple, le bitmap "image.bmp" doit se trouver dans le même répertoire que l'exécutable. J'ai augmenté la taille de la console, la taille de l'aperçu est toujours de 39 et peut être modifiée àint sMax = 39; .

La solution de taffer est également très cool. Vous avez tous les deux mon vote favorable ...

Dieter Meemken
la source
23

Je lisais sur les espaces colorimétriques et l' espace LAB semble être une bonne option pour vous (voir ces questions: Trouver une «distance» précise entre les couleurs et l' algorithme pour vérifier la similitude des couleurs )

Citant la page Wikipedia CIELAB , les avantages de cet espace colorimétrique sont:

Contrairement aux modèles de couleurs RVB et CMJN, la couleur Lab est conçue pour se rapprocher de la vision humaine. Il aspire à l'uniformité perceptuelle et sa composante L correspond étroitement à la perception humaine de la légèreté. Ainsi, il peut être utilisé pour effectuer des corrections précises de l'équilibre des couleurs en modifiant les courbes de sortie dans les composantes a et b.

Pour mesurer la distance entre les couleurs, vous pouvez utiliser la distance Delta E.

Avec cela, vous pouvez mieux vous rapprocher de Colorà ConsoleColor:

Tout d'abord, vous pouvez définir une CieLabclasse pour représenter les couleurs dans cet espace:

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

Il existe deux méthodes statiques, l'une pour mesurer la distance en utilisant Delta E ( DeltaE) et l'autre pour combiner deux couleurs en spécifiant la quantité de chaque couleur ( Combine).

Et pour transformer de RGBen, LABvous pouvez utiliser la méthode suivante (à partir d' ici ):

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'idée est d'utiliser des caractères d'ombre comme @AntoninLejsek do ('█', '▓', '▒', ''), cela vous permet d'obtenir plus de 16 couleurs combinant les couleurs de la console (en utilisant la Combineméthode).

Ici, nous pouvons faire quelques améliorations en pré-calculant les couleurs à utiliser:

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

Une autre amélioration pourrait être d'accéder directement aux données d'image en utilisant LockBitsau lieu d'utiliserGetPixel .

MISE À JOUR : Si l'image comporte des parties de la même couleur, vous pouvez accélérer considérablement le processus de dessin d'un morceau de caractères ayant les mêmes couleurs, au lieu de caractères individuels:

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

Enfin, appelez DrawImagecomme ceci:

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

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

}

Images de résultat:

Console1

Console2



Les solutions suivantes ne sont pas basées sur des caractères mais fournissent des images détaillées complètes


Vous pouvez dessiner sur n'importe quelle fenêtre en utilisant son gestionnaire pour créer un Graphicsobjet. Pour obtenir le gestionnaire d'une application console, vous pouvez le faire en important GetConsoleWindow:

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

Ensuite, créez un graphique avec le gestionnaire (en utilisant Graphics.FromHwnd) et dessinez l'image en utilisant les méthodes de l' Graphicsobjet, par exemple:

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

Version 1

Cela semble correct mais si la console est redimensionnée ou défilée, l'image disparaît car la fenêtre est rafraîchie (peut-être que la mise en œuvre d'une sorte de mécanisme pour redessiner l'image est possible dans votre cas).


Une autre solution consiste à intégrer une fenêtre ( Form) dans l'application console. Pour ce faire, vous devez importer SetParent(et MoveWindowdéplacer la fenêtre à l'intérieur de la 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);

Ensuite, il vous suffit de créer une propriété Formet de définir BackgroundImagel'image souhaitée (faites-le sur un Threadou Taskpour éviter de bloquer 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);
}

Version 2

Bien sûr, vous pouvez définir FormBorderStyle = FormBorderStyle.Nonepour masquer les bordures des fenêtres (image de droite)

Dans ce cas, vous pouvez redimensionner la console et l'image / la fenêtre est toujours là.

L'un des avantages de cette approche est que vous pouvez localiser la fenêtre où vous le souhaitez et modifier l'image à tout moment en modifiant simplement la BackgroundImagepropriété.

Arturo Menchaca
la source
Merci pour vos efforts mais votre approche est 6 fois plus lente que la solution d'Antonín Lejsek. Bref, résultat du tour très intéressant.
Byyo
4

Il n'y a pas de moyen direct. Mais vous pouvez essayer d'utiliser un convertisseur image-ascii-art comme celui-ci

DarkWanderer
la source
:-) cependant, notez que les capacités de couleur de la console (fenêtre) sont également assez limitées. Ainsi, les effets de "fondu", etc. ne sont même pas possibles.
Christian.K
1
Eh bien, cela correspond à la résolution: P
DarkWanderer
1
@ Christian.K La réponse d'Antonín Lejsek rend la décoloration possible
Byyo
1

Oui, vous pouvez le faire, si vous étirez un peu la question en ouvrant un à Formpartir de l'application Console.

Voici comment vous pouvez demander à votre application console d'ouvrir un formulaire et d'afficher une image:

  • inclure ces deux références dans votre projet: System.DrawingetSystem.Windows.Forms
  • incluez également les deux espaces de noms:

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

Voir cet article pour savoir comment faire cela !

Maintenant, tout ce dont vous avez besoin pour ajouter quelque chose comme ceci:

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

Bien sûr, vous pouvez également utiliser un PictureBox..

Et vous pouvez utiliser form1.Show();pour maintenir la console active pendant que l'aperçu s'affiche.

Message original: Bien sûr, vous ne pouvez pas afficher correctement une image dans une fenêtre 25x80; même si vous utilisez une fenêtre plus grande et bloquez les graphiques, ce ne serait pas un aperçu mais un désordre!

Mise à jour: il semble que vous puissiez après tout dessiner une image par GDI sur le formulaire de console; voir la réponse de Taffer!

TaW
la source