बड़ी चुनौती। यहाँ मेरा समाधान है। मैंने मूल कॉमिक के जितना करीब संभव हो पाने की कोशिश की, मैंने xkcd फ़ॉन्ट का भी उपयोग किया ।
यह एक WPF अनुप्रयोग है, लेकिन मैं System.Drawing
आलसी होने के कारण ड्राइंग भागों का उपयोग करता था।
मूल अवधारणा: डब्ल्यूपीएफ में, खिड़कियां होती हैं Visuals
, जिसका अर्थ है कि उन्हें प्रदान किया जा सकता है। मैं एक बिटमैप पर पूरे विंडो उदाहरण को प्रस्तुत करता हूं, काले और कुल काले या सफेद (फ़ॉन्ट चौरसाई और सामान की अनदेखी) की गणना करता हूं और प्रत्येक छवि के प्रत्येक चरण (प्रत्येक पैनल के लिए) की गणना भी करता हूं। फिर मैं इसे फिर से एक टाइमर पर करता हूं। यह एक या दो सेकंड के भीतर संतुलन तक पहुँच जाता है।
डाउनलोड:
MEGA
हमेशा वायरस, आदि के लिए आपके द्वारा डाउनलोड की गई फ़ाइलों की जाँच करें।
यदि आप इसे देखना चाहते हैं, तो आपको अपने सिस्टम के ऊपर फ़ॉन्ट स्थापित करना होगा, अन्यथा यह WPF डिफ़ॉल्ट है।
XAML:
<Window
x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="xkcd: 688" Height="300" Width="1000" WindowStyle="ToolWindow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.3*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" x:Name="bFirstPanel" BorderThickness="3" Padding="10px" Margin="0 0 10px 0">
<Grid>
<Label FontSize="18" FontFamily="xkcd" VerticalAlignment="Top">Fraction of this window that is white</Label>
<Label FontSize="18" FontFamily="xkcd" VerticalAlignment="Bottom">Fraction of this window that is black</Label>
<Image x:Name="imgFirstPanel"></Image>
</Grid>
</Border>
<Border Grid.Column="1" x:Name="bSecondPanel" BorderBrush="Black" BorderThickness="3" Padding="10px" Margin="10px 0">
<Grid>
<TextBlock FontSize="18" FontFamily="xkcd" VerticalAlignment="Top" HorizontalAlignment="Left">Amount of <LineBreak></LineBreak>black ink <LineBreak></LineBreak>by panel:</TextBlock>
<Image x:Name="imgSecondPanel"></Image>
</Grid>
</Border>
<Border Grid.Column="2" x:Name="bThirdPanel" BorderBrush="Black" BorderThickness="3" Padding="10px" Margin="10px 0 0 0">
<Grid>
<TextBlock FontSize="18" FontFamily="xkcd" VerticalAlignment="Top" HorizontalAlignment="Left">Location of <LineBreak></LineBreak>black ink <LineBreak></LineBreak>in this window:</TextBlock>
<Image x:Name="imgThirdPanel"></Image>
</Grid>
</Border>
</Grid>
</Window>
कोड:
using System;
using System.Drawing;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Brushes = System.Drawing.Brushes;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private Timer mainTimer = new Timer();
public MainWindow()
{
InitializeComponent();
Loaded += (o1,e1) =>
{
mainTimer = new Timer(1000/10);
mainTimer.Elapsed += (o, e) => {
try
{
Dispatcher.Invoke(Refresh);
} catch(Exception ex)
{
// Nope
}
};
mainTimer.Start();
};
}
private void Refresh()
{
var actualh = this.RenderSize.Height;
var actualw = this.RenderSize.Width;
var renderTarget = new RenderTargetBitmap((int) actualw, (int) actualh, 96, 96, PixelFormats.Pbgra32);
var sourceBrush = new VisualBrush(this);
var visual = new DrawingVisual();
var context = visual.RenderOpen();
// Render the window onto the target bitmap
using (context)
{
context.DrawRectangle(sourceBrush, null, new Rect(0,0, actualw, actualh));
}
renderTarget.Render(visual);
// Create an array with all of the pixel data
var stride = (int) actualw*4;
var data = new byte[stride * (int)actualh];
renderTarget.CopyPixels(data, stride, 0);
var blackness = 0f;
var total = 0f;
var blacknessFirstPanel = 0f;
var blacknessSecondPanel = 0f;
var blacknessThirdPanel = 0f;
var totalFirstPanel = 0f;
var totalSecondPanel = 0f;
var totalThirdPanel = 0f;
// Count all of the things
for (var i = 0; i < data.Length; i += 4)
{
var b = data[i];
var g = data[i + 1];
var r = data[i + 2];
if (r == 0 && r == g && g == b)
{
blackness += 1;
total += 1;
var x = i%(actualw*4) / 4;
if(x < actualw / 3f)
{
blacknessFirstPanel += 1;
totalFirstPanel += 1;
} else if (x < actualw * (2f / 3f))
{
blacknessSecondPanel += 1;
totalSecondPanel += 1;
}
else if (x < actualw)
{
blacknessThirdPanel += 1;
totalThirdPanel += 1;
}
} else if (r == 255 && r == g && g == b)
{
total += 1;
var x = i % (actualw * 4) / 4;
if (x < actualw / 3f)
{
totalFirstPanel += 1;
}
else if (x < actualw * (2f / 3f))
{
totalSecondPanel += 1;
}
else if (x < actualw)
{
totalThirdPanel += 1;
}
}
}
var black = blackness/total;
Redraw(black, blacknessFirstPanel, blacknessSecondPanel, blacknessThirdPanel, blackness, renderTarget);
}
private void Redraw(double black, double firstpanel, double secondpanel, double thirdpanel, double totalpanels, ImageSource window)
{
DrawPieChart(black);
DrawBarChart(firstpanel, secondpanel, thirdpanel, totalpanels);
DrawImage(window);
}
void DrawPieChart(double black)
{
var w = (float)bFirstPanel.ActualWidth;
var h = (float)bFirstPanel.ActualHeight;
var padding = 0.1f;
var b = new Bitmap((int)w, (int)h);
var g = Graphics.FromImage(b);
var px = padding*w;
var py = padding*h;
var pw = w - (2*px);
var ph = h - (2*py);
g.DrawEllipse(Pens.Black, px,py,pw,ph);
g.FillPie(Brushes.Black, px, py, pw, ph, 120, (float)black * 360);
g.DrawLine(Pens.Black, 30f, h * 0.1f, w / 2 + w * 0.1f, h / 2 - h * 0.1f);
g.DrawLine(Pens.Black, 30f, h - h * 0.1f, w / 2 - w * 0.2f, h / 2 + h * 0.2f);
imgFirstPanel.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(b.Width, b.Height));
}
void DrawBarChart(double b1, double b2, double b3, double btotal)
{
var w = (float)bFirstPanel.ActualWidth;
var h = (float)bFirstPanel.ActualHeight;
var padding = 0.1f;
var b = new Bitmap((int)w, (int)h);
var g = Graphics.FromImage(b);
var px = padding * w;
var py = padding * h;
var pw = w - (2 * px);
var ph = h - (2 * py);
g.DrawLine(Pens.Black, px, py, px, ph+py);
g.DrawLine(Pens.Black, px, py + ph, px+pw, py+ph);
var fdrawbar = new Action<int, double>((number, value) =>
{
var height = ph*(float) value/(float) btotal;
var width = pw/3f - 4f;
var x = px + (pw/3f)*(number-1);
var y = py + (ph - height);
g.FillRectangle(Brushes.Black, x, y, width, height);
});
fdrawbar(1, b1);
fdrawbar(2, b2);
fdrawbar(3, b3);
imgSecondPanel.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(b.Width, b.Height));
}
void DrawImage(ImageSource window)
{
imgThirdPanel.Source = window;
}
}
}
कोड को साफ नहीं किया गया है, लेकिन यह कुछ हद तक पठनीय है, क्षमा करें।