कंसोल एप्लिकेशन में एक छवि प्रदर्शित करें


85

मेरे पास एक कंसोल एप्लिकेशन है जो छवियों का प्रबंधन करता है। अब मुझे कंसोल एप्लिकेशन के भीतर छवियों के पूर्वावलोकन जैसा कुछ चाहिए। क्या उन्हें सांत्वना में प्रदर्शित करने का कोई तरीका है?

यहाँ वर्तमान वर्ण आधारित उत्तरों की तुलना है:

इनपुट:

यहाँ छवि विवरण दर्ज करें

आउटपुट:

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें


कंसोल में, कंसोल विंडो में के रूप में? हालाँकि, आप एक अलग संवाद / विंडो शुरू कर सकते हैं।
क्रिश्चियन.के Christian

कंसोल एप्लिकेशन मुख्य रूप से केवल एप्लिकेशन के लिए उपयोग किए जाते हैं। छवि प्रदर्शित करने का कोई तरीका नहीं है। आप एक और एप्लिकेशन लॉन्च कर सकते हैं जो छवि प्रदर्शित करता है। इस अन्य एप्लिकेशन को एक छवि को पास करने के लिए कमांड लाइन विकल्प का समर्थन करने की आवश्यकता होगी।
लिंडोस पिकोस

आप कंसोल एप्लिकेशन का उपयोग क्यों करते हैं? यह कहां चलता है? आप हमेशा अपने स्वयं के डिफ़ॉल्ट छवि दर्शक या बस एक winforms आदि ऐप को लाने के लिए एक प्रक्रिया शुरू कर सकते हैं ..
TaW

1
मुझे एंटोनिन लेसेसे के कोड में सुधार की आवश्यकता है (जो बहुत अच्छा है)। कुछ रंग-मिसमेच हैं और बेहतर प्रदर्शन के साथ मैं एनिमेटेड
जिफ

जवाबों:


55

मैंने आगे @DieterMeemken के कोड से खेला। मैंने ऊर्ध्वाधर रिज़ॉल्यूशन को आधा कर दिया और ering के माध्यम से डिटेरिंग जोड़ा। बाईं ओर डाइटर मीमकेन परिणाम है, दाईं ओर। तल पर मूल तस्वीर को आउटपुट से मिलान करने के लिए आकार दिया गया है। आउटपुट परिणाम जबकि Malwyns रूपांतरण फ़ंक्शन प्रभावशाली है, यह सभी ग्रे रंगों का उपयोग नहीं करता है, जो दया है।

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

उपयोग:

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

संपादित करें

रंग की दूरी जटिल विषय है ( यहां , यहां और उन पृष्ठों पर लिंक ...)। मैंने YUV में दूरी की गणना करने की कोशिश की और परिणाम आरजीबी की तुलना में खराब थे। वे लैब और डेल्टा के साथ बेहतर हो सकते हैं, लेकिन मैंने यह कोशिश नहीं की। RGB में दूरी काफी अच्छी लगती है। वास्तव में परिणाम RGB रंग अंतरिक्ष में यूक्लिडियन और मैनहट्टन दोनों दूरी के लिए बहुत अनुकरणीय हैं, इसलिए मुझे संदेह है कि चुनने के लिए बहुत कम रंग हैं।

बाकी रंग और पैटर्न (= प्रतीकों) के सभी संयोजनों के खिलाफ रंग की तुलना में सिर्फ क्रूर बल है। मैंने I 1/4, 2/4, 3/4 और 4/4 होने के लिए भरण अनुपात कहा। उस मामले में तीसरा प्रतीक वास्तव में पहले के लिए बेमानी है। लेकिन अगर अनुपात ऐसी वर्दी नहीं थे (फ़ॉन्ट पर निर्भर करता है), तो परिणाम बदल सकते हैं, इसलिए मैंने इसे भविष्य में सुधार के लिए छोड़ दिया। भरे हुए अनुपात के अनुसार प्रतीक के औसत रंग की गणना अग्रभूमि और बैकग्राउंड के वजन के औसत के रूप में की जाती है। यह रैखिक रंगों को मानता है, जो कि बड़ा सरलीकरण भी है। इसलिए अभी भी सुधार की गुंजाइश है।


थैंक यू @fubo Btw मैंने गामा को सही RGB और Lab के साथ प्रयोग किया और दोनों में सुधार हुआ। लेकिन भरे हुए अनुपात का उपयोग किए गए फ़ॉन्ट से मिलान करने के लिए सेट किया जाना था और यह truetype फोंट के लिए बिल्कुल भी काम नहीं करता था। तो यह अब नहीं होगा एक आकार सभी sollution फिट बैठता है।
एंटनी लेजसेक

88

यद्यपि कंसोल में एक छवि दिखाना कंसोल का इच्छित उपयोग नहीं है, आप निश्चित रूप से चीजों को हैक कर सकते हैं, क्योंकि कंसोल विंडो केवल एक विंडो है, किसी भी अन्य विंडो की तरह।

दरअसल, एक बार मैंने ग्राफिक्स समर्थन के साथ कंसोल एप्लिकेशन के लिए एक टेक्स्ट कंट्रोल लाइब्रेरी विकसित करना शुरू कर दिया है। मैंने कभी भी ऐसा नहीं किया है, हालांकि मेरे पास एक वर्किंग प्रूफ-ऑफ-कॉन्सेप्ट डेमो है:

छवि के साथ पाठ नियंत्रण

और यदि आप कंसोल फ़ॉन्ट आकार प्राप्त करते हैं, तो आप छवि को बहुत सटीक रूप से रख सकते हैं।

यह आप इसे कैसे कर सकते हैं:

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

इस प्रकार आप वर्तमान कंसोल फ़ॉन्ट आकार प्राप्त कर सकते हैं:

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

और आवश्यक अतिरिक्त WinApi कॉल, स्थिरांक और प्रकार:

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

और परिणाम:

[कंसोल में ग्राफिक्स


2
वाह, यह वास्तव में दिलचस्प है! क्या आप कृपया थोड़ा विस्तार से बता सकते हैं कि आपके कहने का मतलब है कि मैंने कभी भी ऐसा काम नहीं किया है, हालांकि मेरे पास एक वर्किंग प्रूफ-ऑफ-कॉन्सेप्ट डेमो है ? कोई कमियां या सिर्फ गायब पॉलिश ..?
ताव

इसका मतलब है कि परियोजना बहुत अधूरी है। मैंने बुनियादी वास्तुकला, आधार घटना-चालित OO पर्यावरण, माउस समर्थन, संदेश पंप, आदि बनाया, लेकिन यहां तक ​​कि सबसे मौलिक नियंत्रण जैसे कि Button, TextBoxआदि अभी भी गायब हैं। मेरा सपना डेटा बाइंडिंग के साथ और WPF की तरह "कुछ भी एम्बेड करें" दर्शन के साथ एक पूर्ण XAML समर्थन करना है। लेकिन मैं उससे बहुत दूर हूँ ... ठीक है, इस क्षण में :)
गियोगी कोज़ेग

3
ठीक है, मैं देखता हूं, लेकिन कोड ऐसा लगता है कि इसका उपयोग किसी भी कम पूर्ण, कम महत्वाकांक्षी परियोजना के लिए किया जा सकता है, हां?
ताव

1
खैर, अपने वर्तमान रूप में ... वास्तव में नहीं। लेकिन मैं इसे GitHub पर प्रकाशित करने की योजना बना रहा हूं क्योंकि मैं इसे कुछ हद तक स्थिर और सुसंगत बना देता हूं।
ग्योर्गी कोसजेग

यह मानव रहित DLL का उपयोग करने की आवश्यकता को छोड़कर वास्तव में अच्छा लग रहा है। इसके अलावा, हम पुस्तकालयों के विकास पर नज़र कैसे रख सकते हैं?
एक ईयरविग

56

यदि आप दो बार ASCII 219 (█) का उपयोग करते हैं, तो आपके पास एक पिक्सेल (AS) जैसा कुछ है। अब आप अपने कंसोल एप्लिकेशन में पिक्सेल की मात्रा और रंगों की संख्या द्वारा प्रतिबंधित हैं।

  • यदि आप डिफ़ॉल्ट सेटिंग्स रखते हैं तो आपके पास लगभग 39x39 पिक्सेल हैं, यदि आप अधिक चाहते हैं तो आप अपने कंसोल को Console.WindowHeight = resSize.Height + 1;और के साथ आकार बदल सकते हैं Console.WindowWidth = resultSize.Width * 2;

  • आपको जहाँ तक संभव हो छवि का पहलू-अनुपात रखना होगा, इसलिए आपके पास ज्यादातर मामलों में 39x39 नहीं होंगे

  • माल्विन ने परिवर्तित System.Drawing.Colorकरने के लिए एक पूरी तरह से कम करने की विधि पोस्ट कीSystem.ConsoleColor

इसलिए मेरा दृष्टिकोण होगा

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

तो तुम कर सकते हो

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

नमूना इनपुट:

यहाँ छवि विवरण दर्ज करें

नमूना उत्पादन:

यहाँ छवि विवरण दर्ज करें


7
@willywonka_dailyblah - यह टेंटेकल के दिन से बैंगनी रंग का तम्बू है। नहीं कयामत
Blaatz0r

@ Blaatz0r का अर्थ है कयामत जैसा ग्राफिक्स ... तेह ब्लॉक पर imma नया बच्चा मैं केवल Doom जानता हूं

3
सब माफ है: यदि आपके पास मौका है तो दिन का प्रयास करें यदि टेंटकल एक महान खेल पुराना लेकिन महान है।
Blaatz0r

37

वह मजेदार था। धन्यवाद fubo , मैंने आपके समाधान की कोशिश की और 4 (2x2) द्वारा पूर्वावलोकन के संकल्प को बढ़ाने में सक्षम था।

मैंने पाया, कि आप प्रत्येक व्यक्तिगत चार के लिए पृष्ठभूमि का रंग निर्धारित कर सकते हैं। इसलिए, दो ASCII 219 (char) वर्णों का उपयोग करने के बजाय, मैंने ASCII 223 (with) का उपयोग दो बार अलग-अलग अग्रभूमि और पृष्ठभूमि रंगों के साथ किया। यह बड़े पिक्सेल (██) को इस तरह 4 उपपिक्सल में विभाजित करता है (।)।

इस उदाहरण में मैंने दोनों छवियों को एक दूसरे के बगल में रखा है, ताकि आप आसानी से अंतर देख सकें:

यहाँ छवि विवरण दर्ज करें

यहाँ कोड है:

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

उदाहरण को चलाने के लिए, बिटमैप "image.bmp" को निष्पादन योग्य के समान निर्देशिका में होना चाहिए। मैंने कंसोल का आकार बढ़ाया, पूर्वावलोकन का आकार अभी भी 39 है और इसे बदला जा सकता हैint sMax = 39;

टैफर से समाधान भी बहुत अच्छा है। तुम दोनों मेरा उत्थान करो ...


23

मैं रंग स्थानों के बारे में पढ़ रहा था और LAB स्थान आपके लिए एक अच्छा विकल्प प्रतीत होता है (इस प्रश्न को देखें: रंगों की समानता की जाँच करने के लिए रंगों और एल्गोरिथम के बीच एक सटीक "दूरी" ढूँढना )

विकिपीडिया CIELAB पृष्ठ का हवाला देते हुए , इस रंग स्थान के फायदे हैं:

आरजीबी और सीएमवाईके रंग मॉडल के विपरीत, लैब रंग मानव दृष्टि को अनुमानित करने के लिए डिज़ाइन किया गया है। यह अवधारणात्मक एकरूपता की आकांक्षा करता है, और इसका एल घटक प्रकाश की मानवीय धारणा से निकटता से मेल खाता है। इस प्रकार, इसका उपयोग ए और बी घटकों में आउटपुट घटता को संशोधित करके सटीक रंग संतुलन सुधार करने के लिए किया जा सकता है।

रंगों के बीच की दूरी को मापने के लिए आप डेल्टा ई दूरी का उपयोग कर सकते हैं ।

इस के साथ आप से बेहतर अनुमान लगा सकता है Colorकरने के लिएConsoleColor :

सबसे पहले, आप CieLabइस स्थान में रंगों का प्रतिनिधित्व करने के लिए एक वर्ग को परिभाषित कर सकते हैं :

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

दो स्थिर तरीके हैं, एक डेल्टा ई ( DeltaE) का उपयोग करके दूरी को मापने के लिए और अन्य दो रंगों को संयोजित करने के लिए कि प्रत्येक रंग का कितना निर्दिष्ट है ( Combine)।

और से बदलने के लिए RGBकरने के लिए LABआप निम्न विधि (से उपयोग कर सकते हैं यहाँ ):

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

विचार @AntoninLejsek do ('use', '▒', '▓', '░') जैसे शेड वर्णों का उपयोग करता है, यह आपको सांत्वना रंगों ( Combineविधि का उपयोग करके ) को मिलाकर 16 से अधिक रंग प्राप्त करने की अनुमति देता है ।

यहां, हम रंगों का उपयोग करने के लिए पूर्व-गणना करके कुछ सुधार कर सकते हैं:

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

एक और सुधार का उपयोग LockBitsकरने के बजाय सीधे छवि डेटा तक पहुंच प्राप्त की जा सकती है GetPixel

अद्यतन : यदि छवि में एक ही रंग के हिस्से हैं, तो आप वर्णों के बजाय समान रंगों वाले वर्णों को आकर्षित करने की प्रक्रिया को काफी तेज़ कर सकते हैं:

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

अंत में, DrawImageजैसे कॉल करें :

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

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

}

परिणाम छवियाँ:

Console1

Console2



निम्नलिखित समाधान वर्णों पर आधारित नहीं हैं, लेकिन पूर्ण विस्तृत चित्र प्रदान करते हैं


आप किसी भी विंडो को ऑब्जेक्ट बनाने के लिए उसके हैंडलर का उपयोग करके खींच सकते हैं Graphics। कंसोल एप्लिकेशन के हैंडलर प्राप्त करने के लिए आप इसे आयात कर सकते हैं GetConsoleWindow:

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

फिर, हैंडलर (उपयोग Graphics.FromHwnd) के साथ एक ग्राफिक्स बनाएं और Graphicsउदाहरण के लिए, ऑब्जेक्ट में विधियों का उपयोग करके चित्र बनाएं :

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

संस्करण 1

यह ठीक लग रहा है, लेकिन यदि कंसोल को आकार या स्क्रॉल किया जाता है, तो छवि गायब हो जाती है क्योंकि खिड़कियां ताज़ा होती हैं (शायद आपके मामले में छवि को फिर से बनाने के लिए किसी तरह के तंत्र को लागू करना संभव है)।


एक अन्य समाधान एक विंडो ( Form) को कंसोल एप्लिकेशन में एम्बेड कर रहा है । ऐसा करने के लिए आपको आयात करना होगा SetParent(और MoveWindowविंडो को कंसोल के अंदर स्थानांतरित करना होगा):

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

तो फिर तुम सिर्फ एक बनाने की जरूरत Formहै और सेट BackgroundImageवांछित छवि के लिए संपत्ति (एक पर कर Threadया Taskकंसोल को अवरुद्ध से बचने के लिए):

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

संस्करण 2

बेशक आप FormBorderStyle = FormBorderStyle.Noneविंडो बॉर्डर्स (राइट इमेज) छिपाने के लिए सेट कर सकते हैं

इस स्थिति में आप कंसोल और इमेज / विंडो का आकार बदल सकते हैं।

इस दृष्टिकोण के साथ एक लाभ यह है कि आप उस विंडो का पता लगा सकते हैं जहां आप चाहते हैं और किसी भी समय छवि बदलकर केवल BackgroundImageसंपत्ति बदल सकते हैं।


आपके प्रयास के लिए धन्यवाद लेकिन आप दृष्टिकोण एंटोन लेजसेक के समाधान की तुलना में 6 गुना धीमा हैं। वैसे भी बहुत दिलचस्प परिणाम है।
बाय्यो

4

कोई सीधा रास्ता नहीं है। लेकिन आप इस तरह के एक छवि-से-अस्सी-कला कनवर्टर का उपयोग करने का प्रयास कर सकते हैं


:-) हालाँकि, ध्यान दें कि कंसोल (विंडो की) रंग क्षमताएं भी बहुत सीमित हैं। तो "लुप्त होती" प्रभाव, आदि भी संभव नहीं हैं।
क्रिश्चियन.के Christian

1
खैर, यह रिज़ॉल्यूशन से मेल खाता है: पी
डार्कवेंडर

1
@ क्रिश्चियन.के एंटनी लेजसेक का जवाब लुप्त होता है
बियोयो

1

हां, आप ऐसा कर सकते हैं, यदि आप Formकंसोल एप्लिकेशन के भीतर से एक प्रश्न को खोलकर थोड़ा खिंचाव देते हैं ।

यहां बताया गया है कि आप किस तरह से आवेदन को सांत्वना दे सकते हैं एक फॉर्म खोलें और एक छवि प्रदर्शित करें:

  • अपनी परियोजना में इन दो संदर्भों को शामिल करें: System.DrawingऔरSystem.Windows.Forms
  • दो नामस्थानों को भी शामिल करें:

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

इस पोस्ट को देखें कि यह कैसे करना है !

अब आप सभी को इसे कुछ इस तरह से जोड़ना होगा:

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

बेशक आप भी एक का उपयोग कर सकते हैं PictureBox..

और आप form1.Show();पूर्वावलोकन दिखाने के दौरान कंसोल को जीवित रखने के लिए उपयोग कर सकते हैं ।

मूल पोस्ट: बेशक आप एक छवि को 25x80 विंडो के अंदर ठीक से प्रदर्शित नहीं कर सकते हैं; यहां तक ​​कि अगर आप एक बड़ी खिड़की का उपयोग करते हैं और ग्राफिक्स का उपयोग करते हैं तो यह पूर्वावलोकन नहीं बल्कि एक गड़बड़ होगा!

अद्यतन: ऐसा लगता है जैसे आप कंसोल फॉर्म पर एक GDI- चित्र बनाने के बाद कर सकते हैं; देखिए टाफर का जवाब!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.