source: trunk/sources/HeuristicLab.Visualization.ChartControlsExtensions/3.3/ImageExportDialog.cs @ 12012

Last change on this file since 12012 was 12012, checked in by ascheibe, 7 years ago

#2212 merged r12008, r12009, r12010 back into trunk

File size: 19.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.ComponentModel;
24using System.Drawing;
25using System.Drawing.Imaging;
26using System.IO;
27using System.Linq;
28using System.Windows.Forms;
29using System.Windows.Forms.DataVisualization.Charting;
30
31namespace HeuristicLab.Visualization.ChartControlsExtensions {
32  public sealed partial class ImageExportDialog : Form {
33    private const float CMPERINCH = 2.54f;
34    private static readonly string DPI = "dpi", DPCM = "dpcm", INCH = "inch", CM = "cm";
35    private Chart originalChart, workingChart;
36    private bool SuppressEvents { get; set; }
37
38    /// <summary>
39    /// Initializes a new ImageExportDialog.
40    /// </summary>
41    /// <remarks>
42    /// Throws an ArgumentNullException if <paramref name="chart"/> is null.
43    /// </remarks>
44    /// <param name="chart">The chart for which the export should be generated.</param>
45    public ImageExportDialog(Chart chart) {
46      if (chart == null) throw new ArgumentNullException("chart");
47      this.originalChart = chart;
48      InitializeComponent();
49      #region Custom Initialization
50      SuppressEvents = true;
51      try {
52        resolutionUnitComboBox.Items.Add(DPI);
53        resolutionUnitComboBox.Items.Add(DPCM);
54        lengthUnitComboBox.Items.Add(INCH);
55        lengthUnitComboBox.Items.Add(CM);
56        resolutionUnitComboBox.SelectedIndex = 0;
57        if (System.Globalization.RegionInfo.CurrentRegion.IsMetric)
58          lengthUnitComboBox.SelectedIndex = 1;
59        else lengthUnitComboBox.SelectedIndex = 0;
60
61        titleFontSizeComboBox.Text = "10";
62        axisFontSizeComboBox.Text = "8";
63        scalesFontSizeComboBox.Text = "6";
64        legendFontSizeComboBox.Text = "6";
65        resolutionComboBox.Text = "150";
66        SuppressEvents = false;
67        splitContainer.Panel2Collapsed = true;
68        Width = 305;
69        Height = 625;
70      }
71      finally { SuppressEvents = false; }
72      #endregion
73    }
74
75    private void UpdateFields() {
76      var area = GetCurrentChartArea();
77
78      try {
79        SuppressEvents = true;
80
81        if (workingChart.Titles.Count == 0) titleFontSizeComboBox.Text = "10";
82        else {
83          titleTextBox.Text = workingChart.Titles[0].Text;
84          titleFontSizeComboBox.Text = workingChart.Titles[0].Font.SizeInPoints.ToString();
85        }
86
87        primaryXTextBox.Text = area.AxisX.Title;
88        primaryYTextBox.Text = area.AxisY.Title;
89        secondaryXTextBox.Text = area.AxisX2.Title;
90        secondaryYTextBox.Text = area.AxisY2.Title;
91
92        axisFontSizeComboBox.Text = area.AxisX.TitleFont.SizeInPoints.ToString();
93        scalesFontSizeComboBox.Text = area.AxisX.LabelStyle.Font.SizeInPoints.ToString();
94        if (workingChart.Legends.Count == 0) legendFontSizeComboBox.Text = "6";
95        else legendFontSizeComboBox.Text = workingChart.Legends[0].Font.SizeInPoints.ToString();
96      }
97      finally {
98        SuppressEvents = false;
99      }
100    }
101
102    private ChartArea GetCurrentChartArea() {
103      return workingChart.ChartAreas[chartAreaComboBox.Text];
104    }
105
106    private void UpdatePreview() {
107      float dpi;
108      float width;
109      float height;
110      GetImageParameters(out dpi, out width, out height);
111
112      if (previewPictureBox.Image != null) {
113        previewPictureBox.Image.Dispose();
114        previewPictureBox.Image = null;
115      }
116
117      int previewWidth, previewHeight;
118      if (width / height >= 1.0) {
119        previewWidth = previewPictureBox.Width;
120        previewHeight = (int)Math.Round(height / width * previewWidth);
121      } else {
122        previewHeight = previewPictureBox.Height;
123        previewWidth = (int)Math.Round(width / height * previewHeight);
124      }
125
126      var scaleFactor = (float)Math.Min(previewWidth / width, previewHeight / height);
127      if (scaleFactor >= 1) {
128        previewZoomLabel.Text = "100%";
129        previewWidth = (int)Math.Round(width);
130        previewHeight = (int)Math.Round(height);
131      } else previewZoomLabel.Text = (scaleFactor * 100).ToString("0") + "%";
132      rawImageSizeLabel.Text = GetRawImageSizeInMegabytes(width, height).ToString("0.00") + "M   " + "(" + Math.Round(width).ToString("0") + " x " + Math.Round(height).ToString("0") + ") pixels";
133
134      var image = new Bitmap(previewWidth, previewHeight);
135      image.SetResolution(dpi, dpi);
136      using (Graphics graphics = Graphics.FromImage(image)) {
137        if (scaleFactor < 1) graphics.ScaleTransform(scaleFactor, scaleFactor);
138        workingChart.Printing.PrintPaint(graphics, new Rectangle(0, 0, (int)Math.Round(width), (int)Math.Round(height)));
139      }
140      previewPictureBox.Image = image;
141    }
142
143    private void GetImageParameters(out float dpi, out float width, out float height) {
144      dpi = float.Parse(resolutionComboBox.Text);
145      if (resolutionUnitComboBox.Text == DPCM) dpi *= CMPERINCH;
146      width = (float)widthNumericUD.Value;
147      height = (float)heightNumericUD.Value;
148      if (lengthUnitComboBox.Text == CM) {
149        width /= CMPERINCH; height /= CMPERINCH;
150      }
151      width *= dpi; height *= dpi;
152    }
153
154    protected override void OnShown(EventArgs e) {
155      #region Create copy of chart
156      var prevContent = originalChart.Serializer.Content;
157      var prevFormat = originalChart.Serializer.Format;
158      originalChart.Serializer.Content = SerializationContents.Default;
159      originalChart.Serializer.Format = SerializationFormat.Binary;
160      using (var ms = new MemoryStream()) {
161        originalChart.Serializer.Save(ms);
162
163        ms.Seek(0, SeekOrigin.Begin);
164        workingChart = new EnhancedChart();
165        workingChart.Serializer.Format = originalChart.Serializer.Format;
166        workingChart.Serializer.Load(ms);
167      }
168
169      foreach (var s in workingChart.Series.Where(x => !x.Points.Any()).ToArray())
170        s.IsVisibleInLegend = false;
171
172      originalChart.Serializer.Content = prevContent;
173      originalChart.Serializer.Format = prevFormat;
174      #endregion
175
176      chartAreaComboBox.Items.Clear();
177      foreach (var area in originalChart.ChartAreas) {
178        chartAreaComboBox.Items.Add(area.Name);
179      }
180      chartAreaComboBox.SelectedIndex = 0;
181      SuppressEvents = true;
182      try {
183        showPrimaryXAxisCheckBox.Checked = originalChart.Series.Any(x => x.XAxisType == AxisType.Primary);
184        showPrimaryYAxisCheckBox.Checked = originalChart.Series.Any(x => x.YAxisType == AxisType.Primary);
185        showSecondaryXAxisCheckBox.Checked = originalChart.Series.Any(x => x.XAxisType == AxisType.Secondary);
186        showSecondaryYAxisCheckBox.Checked = originalChart.Series.Any(x => x.YAxisType == AxisType.Secondary);
187
188        if (!workingChart.Legends.Any()) {
189          legendPositionComboBox.Enabled = false;
190          legendFontSizeComboBox.Enabled = false;
191        } else {
192          legendPositionComboBox.Enabled = true;
193          legendFontSizeComboBox.Enabled = true;
194          if (workingChart.Legends[0].Enabled) {
195            switch (workingChart.Legends[0].Docking) {
196              case Docking.Top:
197                legendPositionComboBox.SelectedItem = "Top";
198                break;
199              case Docking.Right:
200                legendPositionComboBox.SelectedItem = "Right";
201                break;
202              case Docking.Bottom:
203                legendPositionComboBox.SelectedItem = "Bottom";
204                break;
205              case Docking.Left:
206                legendPositionComboBox.SelectedItem = "Left";
207                break;
208            }
209          } else {
210            legendPositionComboBox.SelectedItem = "Hidden";
211          }
212        }
213      }
214      finally { SuppressEvents = false; }
215      base.OnShown(e);
216
217      if (togglePreviewCheckBox.Checked) UpdatePreview();
218    }
219
220    private void togglePreviewCheckBox_CheckedChanged(object sender, EventArgs e) {
221      splitContainer.Panel2Collapsed = !togglePreviewCheckBox.Checked;
222      togglePreviewCheckBox.Text = togglePreviewCheckBox.Checked ? "<" : ">";
223      if (splitContainer.Panel2Collapsed)
224        Width = cancelButton.Right + cancelButton.Margin.Right + Margin.Right + 10;
225      else
226        Width = splitContainer.Right + splitContainer.Margin.Right + Margin.Right;
227      if (togglePreviewCheckBox.Checked) UpdatePreview();
228    }
229
230    private void chartAreaComboBox_SelectedIndexChanged(object sender, EventArgs e) {
231      if (chartAreaComboBox.SelectedIndex >= 0)
232        UpdateFields();
233    }
234
235    private void legendPositionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
236      if (!SuppressEvents) {
237        if (legendPositionComboBox.SelectedIndex >= 0) {
238          var legend = workingChart.Legends[0];
239          var legendPosition = legendPositionComboBox.Items[legendPositionComboBox.SelectedIndex].ToString();
240          if (legendPosition != "Hidden" && !legend.Enabled)
241            legend.Enabled = true;
242          switch (legendPosition) {
243            case "Top":
244              legend.Docking = Docking.Top;
245              break;
246            case "Right":
247              legend.Docking = Docking.Right;
248              break;
249            case "Bottom":
250              legend.Docking = Docking.Bottom;
251              break;
252            case "Left":
253              legend.Docking = Docking.Left;
254              break;
255            case "Hidden":
256              legend.Enabled = false;
257              break;
258          }
259        }
260        UpdatePreview();
261      }
262    }
263
264    private void titleTextBox_TextChanged(object sender, EventArgs e) {
265      if (!SuppressEvents) {
266        if (string.IsNullOrEmpty(titleTextBox.Text))
267          workingChart.Titles.Clear();
268        else {
269          if (workingChart.Titles.Count > 0) {
270            workingChart.Titles[0].Text = titleTextBox.Text;
271          } else {
272            var t = new Title(titleTextBox.Text);
273            t.Font = ChangeFontSizePt(t.Font, float.Parse(titleFontSizeComboBox.Text));
274            workingChart.Titles.Add(t);
275          }
276        }
277        if (togglePreviewCheckBox.Checked) UpdatePreview();
278      }
279    }
280
281    private void primaryXTextBox_TextChanged(object sender, EventArgs e) {
282      if (!SuppressEvents) {
283        var area = GetCurrentChartArea();
284        area.AxisX.Title = primaryXTextBox.Text;
285        if (togglePreviewCheckBox.Checked) UpdatePreview();
286      }
287    }
288
289    private void primaryYTextBox_TextChanged(object sender, EventArgs e) {
290      if (!SuppressEvents) {
291        var area = GetCurrentChartArea();
292        area.AxisY.Title = primaryYTextBox.Text;
293        if (togglePreviewCheckBox.Checked) UpdatePreview();
294      }
295    }
296
297    private void secondaryXTextBox_TextChanged(object sender, EventArgs e) {
298      if (!SuppressEvents) {
299        var area = GetCurrentChartArea();
300        area.AxisX2.Title = secondaryXTextBox.Text;
301        if (togglePreviewCheckBox.Checked) UpdatePreview();
302      }
303    }
304
305    private void secondaryYTextBox_TextChanged(object sender, EventArgs e) {
306      if (!SuppressEvents) {
307        var area = GetCurrentChartArea();
308        area.AxisY2.Title = secondaryYTextBox.Text;
309        if (togglePreviewCheckBox.Checked) UpdatePreview();
310      }
311    }
312
313    private void showPrimaryXAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
314      if (!SuppressEvents) {
315        var area = GetCurrentChartArea();
316        var isChecked = ((CheckBox)sender).Checked;
317        area.AxisX.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
318        if (togglePreviewCheckBox.Checked) UpdatePreview();
319      }
320    }
321
322    private void showPrimaryYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
323      if (!SuppressEvents) {
324        var area = GetCurrentChartArea();
325        var isChecked = ((CheckBox)sender).Checked;
326        area.AxisY.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
327        if (togglePreviewCheckBox.Checked) UpdatePreview();
328      }
329    }
330
331    private void showSecondaryXAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
332      if (!SuppressEvents) {
333        var area = GetCurrentChartArea();
334        var isChecked = ((CheckBox)sender).Checked;
335        area.AxisX2.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
336        if (togglePreviewCheckBox.Checked) UpdatePreview();
337      }
338    }
339
340    private void showSecondaryYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
341      if (!SuppressEvents) {
342        var area = GetCurrentChartArea();
343        var isChecked = ((CheckBox)sender).Checked;
344        area.AxisY2.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
345        if (togglePreviewCheckBox.Checked) UpdatePreview();
346      }
347    }
348
349    private void widthNumericUD_ValueChanged(object sender, EventArgs e) {
350      float dpi, width, height;
351      GetImageParameters(out dpi, out width, out height);
352      if (GetRawImageSizeInMegabytes(width, height) > 25) // bigger than A4 at 300dpi
353        MessageBox.Show("Warning: The image is getting quite big.");
354      if (togglePreviewCheckBox.Checked) UpdatePreview();
355    }
356
357    private void heightNumericUD_ValueChanged(object sender, EventArgs e) {
358      float dpi, width, height;
359      GetImageParameters(out dpi, out width, out height);
360      if (GetRawImageSizeInMegabytes(width, height) > 25) // bigger than A4 at 300dpi
361        MessageBox.Show("Warning: The image is getting quite big.");
362      if (togglePreviewCheckBox.Checked) UpdatePreview();
363    }
364
365    private void titleFontSizeComboBox_TextChanged(object sender, EventArgs e) {
366      if (!SuppressEvents) {
367        float fontSize;
368        if (float.TryParse(titleFontSizeComboBox.Text, out fontSize)) {
369          if (workingChart.Titles.Count > 0) {
370            workingChart.Titles[0].Font = ChangeFontSizePt(workingChart.Titles[0].Font, fontSize);
371            if (togglePreviewCheckBox.Checked) UpdatePreview();
372          }
373        }
374      }
375    }
376
377    private void axisFontSizeComboBox_TextChanged(object sender, EventArgs e) {
378      if (!SuppressEvents) {
379        float fontSize;
380        if (float.TryParse(axisFontSizeComboBox.Text, out fontSize)) {
381          var area = GetCurrentChartArea();
382          foreach (Axis a in area.Axes)
383            a.TitleFont = ChangeFontSizePt(a.TitleFont, fontSize);
384        }
385        if (togglePreviewCheckBox.Checked) UpdatePreview();
386      }
387    }
388
389    private void scalesFontSizeComboBox_TextChanged(object sender, EventArgs e) {
390      if (!SuppressEvents) {
391        float fontSize;
392        if (float.TryParse(scalesFontSizeComboBox.Text, out fontSize)) {
393          var area = GetCurrentChartArea();
394          foreach (var a in area.Axes)
395            a.LabelStyle.Font = ChangeFontSizePt(a.LabelStyle.Font, fontSize);
396        }
397        if (togglePreviewCheckBox.Checked) UpdatePreview();
398      }
399    }
400
401    private void legendFontSizeComboBox_TextChanged(object sender, EventArgs e) {
402      if (!SuppressEvents) {
403        float fontSize;
404        if (float.TryParse(legendFontSizeComboBox.Text, out fontSize)) {
405          foreach (var l in workingChart.Legends)
406            l.Font = ChangeFontSizePt(l.Font, fontSize);
407        }
408        if (togglePreviewCheckBox.Checked) UpdatePreview();
409      }
410    }
411
412    private void numericComboBox_Validating(object sender, CancelEventArgs e) {
413      if (!(sender is ComboBox)) return;
414      float number;
415      e.Cancel = !float.TryParse((sender as ComboBox).Text, out number);
416    }
417
418    private void resolutionComboBox_TextChanged(object sender, EventArgs e) {
419      float resolution;
420      if (float.TryParse(resolutionComboBox.Text, out resolution)) {
421        if (togglePreviewCheckBox.Checked) UpdatePreview();
422      }
423    }
424
425    private void resolutionComboBox_Validating(object sender, CancelEventArgs e) {
426      float resolution;
427      e.Cancel = !float.TryParse(resolutionComboBox.Text, out resolution);
428    }
429
430    private void resolutionUnitComboBox_SelectedIndexChanged(object sender, EventArgs e) {
431      if (togglePreviewCheckBox.Checked) UpdatePreview();
432    }
433
434    private void lengthUnitComboBox_SelectedIndexChanged(object sender, EventArgs e) {
435      if (togglePreviewCheckBox.Checked) UpdatePreview();
436    }
437
438    private void okButton_Click(object sender, EventArgs e) {
439      float dpi;
440      float width;
441      float height;
442      GetImageParameters(out dpi, out width, out height);
443      var image = new Bitmap((int)Math.Round(width), (int)Math.Round(height));
444      image.SetResolution(dpi, dpi);
445      if (titleTextBox.Text.Trim() != String.Empty) saveFileDialog.FileName = titleTextBox.Text.Trim();
446      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
447        var format = ImageFormat.Bmp;
448        var filename = saveFileDialog.FileName.ToLower();
449        if (filename.EndsWith("emf")) {
450          using (var graphics = Graphics.FromImage(image)) {
451            var rectangle = new Rectangle(0, 0, image.Width, image.Height);
452            using (var metafile = new Metafile(filename, graphics.GetHdc(), rectangle, MetafileFrameUnit.Pixel, EmfType.EmfPlusDual)) {
453              graphics.ReleaseHdc();
454              using (var g = Graphics.FromImage(metafile)) {
455                workingChart.Printing.PrintPaint(g, rectangle);
456              }
457            }
458          }
459        } else {
460          using (var graphics = Graphics.FromImage(image)) {
461            workingChart.Printing.PrintPaint(graphics, new Rectangle(0, 0, image.Width, image.Height));
462          }
463          if (filename.EndsWith("jpg")) {
464            format = ImageFormat.Jpeg;
465          } else if (filename.EndsWith("gif")) {
466            format = ImageFormat.Gif;
467          } else if (filename.EndsWith("png")) {
468            format = ImageFormat.Png;
469          } else if (filename.EndsWith("tif")) {
470            format = ImageFormat.Tiff;
471          }
472          image.Save(saveFileDialog.FileName, format);
473        }
474      }
475      image.Dispose();
476      Cleanup();
477    }
478
479    private void cancelButton_Click(object sender, EventArgs e) {
480      Cleanup();
481    }
482
483    private void Cleanup() {
484      if (previewPictureBox.Image != null) previewPictureBox.Image.Dispose();
485      previewPictureBox.Image = null;
486      workingChart = null;
487    }
488
489    private static Font ChangeFontSizePt(Font font, float fontSize) {
490      if (font != null) {
491        float currentSize = font.Size;
492        if (currentSize != fontSize) {
493          font = new Font(font.Name, fontSize, font.Style, GraphicsUnit.Point, font.GdiCharSet, font.GdiVerticalFont);
494        }
495      }
496      return font;
497    }
498
499    private static float GetRawImageSizeInMegabytes(float width, float height) {
500      return ((3 * width * height) / (1024 * 1024));
501    }
502
503  }
504}
Note: See TracBrowser for help on using the repository browser.