Guest User

TileRenderer

a guest
Dec 4th, 2010
307
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System;
  2. using System.Configuration;
  3. using System.IO;
  4. using System.Threading;
  5. using System.Windows;
  6. using System.Windows.Media;
  7. using System.Windows.Media.Imaging;
  8. using System.Windows.Threading;
  9.  
  10. namespace WPFRenderDemo
  11. {
  12.     public class TileRenderer
  13.     {
  14.         private string outputPath;
  15.         private bool isDemoMode;
  16.         private Window win;
  17.         private DispatcherTimer timer;
  18.         private TileTemplate tileTemplate;
  19.         private int counter;
  20.  
  21.         public void Start()
  22.         {
  23.             // Папка, в которую будут сохранены отрисованные картинки
  24.             this.outputPath = ConfigurationManager.AppSettings["TilesPath"];
  25.  
  26.             // В режиме демонстрации картинки отображаются в окне с интервалом в 1с
  27.             // В рабочем режиме окно прячется и картинки сохраняются на диск
  28.             this.isDemoMode = bool.Parse(ConfigurationManager.AppSettings["DemoRender"]);
  29.  
  30.             if (!this.isDemoMode)
  31.                 // Создает папку, если она не сужествует и удаляет из нее все файлы *.png
  32.                 ClearOutputDirectory();
  33.  
  34.             // Для запуска WPF нужен поток с SingleThreadApartment
  35.             // Создаем такой потов, в котором будет выполняться вся отрисовка
  36.             var thread = new Thread(Run);
  37.             thread.SetApartmentState(ApartmentState.STA);
  38.             thread.Start();
  39.         }
  40.  
  41.         private void Run()
  42.         {
  43.             // Начало STAThread
  44.  
  45.             this.win = new Window();
  46.             this.win.SizeToContent = SizeToContent.WidthAndHeight;
  47.             this.win.Loaded += Loaded;
  48.  
  49.             // В рабочем режиме окно нужно прятать,
  50.             // чтобы ускорить процесс отрисовки
  51.             if (!this.isDemoMode)
  52.                 this.win.Visibility = Visibility.Hidden;
  53.  
  54.             // Добавляем UserControl с шаблоном для картинок
  55.             // В нашем случае - это Grid с единственным TextBlock
  56.             this.tileTemplate = new TileTemplate();
  57.             this.win.Content = tileTemplate;
  58.  
  59.             // Запускаем приложение, после этого должно появиться наше окно
  60.             var app = new Application();
  61.             app.Run(win);
  62.         }
  63.  
  64.         private void Loaded(object sender, RoutedEventArgs e)
  65.         {
  66.             // Окно загружено, теперь создаем таймер,
  67.             // по которому будет срабатывать отрисовка
  68.  
  69.             // В рабочем режиме таймаут должен быть минимальным,
  70.             // чтобы ускорить процесс отрисовки
  71.             TimeSpan timeout = new TimeSpan(1);
  72.  
  73.             // В демонстрационном режиме таймаут выбран так,
  74.             // чтобы можно было успеть разглядеть каждую картинку
  75.             if (this.isDemoMode)
  76.                 timeout = TimeSpan.FromSeconds(1);
  77.  
  78.             this.timer = new DispatcherTimer(
  79.                 timeout,
  80.                 DispatcherPriority.Background,
  81.                 Tick,
  82.                 win.Dispatcher);
  83.             this.timer.Start();
  84.         }
  85.  
  86.         private void Tick(object sender, EventArgs args)
  87.         {
  88.             // После срабатывания таймера окно перерисовывается
  89.             // и можно сохранять его содержимое в виде картинки
  90.  
  91.             // Сохранение происходит только в рабочем режиме
  92.             if (!this.isDemoMode)
  93.             {
  94.                 string fileName = string.Format(@"{0}\{1}.png", this.outputPath, this.counter++);
  95.                 Save(fileName);
  96.             }
  97.  
  98.             // После сотой картинки приложение будет завершено
  99.             if (this.counter >= 100)
  100.             {
  101.                 this.timer.Stop();
  102.                 this.win.Close();
  103.             }
  104.  
  105.             // Подготавливаем окно, передавая нашему UserControl
  106.             // новые данные. В данном случае это случайные значения
  107.             // цветовых каналов.
  108.             var random = new Random();
  109.             var rgb = new byte[3];
  110.             random.NextBytes(rgb);
  111.             this.tileTemplate.Fill(rgb[0], rgb[1], rgb[2]);
  112.         }
  113.  
  114.         private void Save(string fileName)
  115.         {
  116.             // RenderTargetBitmap позволяет перевести любой
  117.             // контрол WPF в bitmap.
  118.             // В конструктор передаются размеры итогового bitmap,
  119.             // его разрешение и формат
  120.             var bitmap = new RenderTargetBitmap(320, 240, 96, 96,
  121.                                                 PixelFormats.Default);
  122.             bitmap.Render(tileTemplate);
  123.  
  124.             // Так как из всех форматов поддерживается только
  125.             // Pbgra32, его нужно перевести в человеческий Rgb24
  126.             // Для этого воспользуемся специальным конвертером
  127.             var formatConv = new FormatConvertedBitmap();
  128.             formatConv.BeginInit();
  129.             formatConv.Source = bitmap;
  130.             formatConv.DestinationFormat = PixelFormats.Rgb24;
  131.             formatConv.EndInit();
  132.  
  133.             // После всего этого bitmap можно сохранять в PNG
  134.             var encoder = new PngBitmapEncoder();
  135.             encoder.Frames.Add(BitmapFrame.Create(formatConv));
  136.  
  137.             using (var stream = File.Create(fileName))
  138.             {
  139.                 encoder.Save(stream);
  140.             }
  141.         }
  142.  
  143.         private void ClearOutputDirectory()
  144.         {
  145.             var outputDir = new DirectoryInfo(this.outputPath);
  146.             if (!outputDir.Exists)
  147.                 outputDir.Create();
  148.  
  149.             var oldTiles = outputDir.GetFiles("*.png");
  150.             foreach (var tile in oldTiles)
  151.                 tile.Delete();
  152.         }
  153.     }
  154. }
RAW Paste Data