Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 9520 was 9520, checked in by abeham, 11 years ago

#2054:

  • Do not include in legend series that have no points
  • Added ability to changed legend docking (top, right, bottom, left) in addition to font size
  • Also added ability to hide legend
File size: 18.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 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      } finally { SuppressEvents = false; }
71      #endregion
72    }
73
74    private void UpdateFields() {
75      var area = GetCurrentChartArea();
76
77      try {
78        SuppressEvents = true;
79
80        if (workingChart.Titles.Count == 0) titleFontSizeComboBox.Text = "10";
81        else {
82          titleTextBox.Text = workingChart.Titles[0].Text;
83          titleFontSizeComboBox.Text = workingChart.Titles[0].Font.SizeInPoints.ToString();
84        }
85
86        primaryXTextBox.Text = area.AxisX.Title;
87        primaryYTextBox.Text = area.AxisY.Title;
88        secondaryXTextBox.Text = area.AxisX2.Title;
89        secondaryYTextBox.Text = area.AxisY2.Title;
90
91        axisFontSizeComboBox.Text = area.AxisX.TitleFont.SizeInPoints.ToString();
92        scalesFontSizeComboBox.Text = area.AxisX.LabelStyle.Font.SizeInPoints.ToString();
93        if (workingChart.Legends.Count == 0) legendFontSizeComboBox.Text = "6";
94        else legendFontSizeComboBox.Text = workingChart.Legends[0].Font.SizeInPoints.ToString();
95      } finally {
96        SuppressEvents = false;
97      }
98    }
99
100    private ChartArea GetCurrentChartArea() {
101      return workingChart.ChartAreas[chartAreaComboBox.Text];
102    }
103
104    private void UpdatePreview() {
105      float dpi;
106      float width;
107      float height;
108      GetImageParameters(out dpi, out width, out height);
109
110      if (previewPictureBox.Image != null) {
111        previewPictureBox.Image.Dispose();
112        previewPictureBox.Image = null;
113      }
114
115      int previewWidth, previewHeight;
116      if (width / height >= 1.0) {
117        previewWidth = previewPictureBox.Width;
118        previewHeight = (int)Math.Round(height / width * previewWidth);
119      } else {
120        previewHeight = previewPictureBox.Height;
121        previewWidth = (int)Math.Round(width / height * previewHeight);
122      }
123
124      var scaleFactor = (float)Math.Min(previewWidth / width, previewHeight / height);
125      if (scaleFactor >= 1) {
126        previewZoomLabel.Text = "100%";
127        previewWidth = (int)Math.Round(width);
128        previewHeight = (int)Math.Round(height);
129      } else previewZoomLabel.Text = (scaleFactor * 100).ToString("0") + "%";
130      rawImageSizeLabel.Text = GetRawImageSizeInMegabytes(width, height).ToString("0.00") + "M   " + "(" + Math.Round(width).ToString("0") + " x " + Math.Round(height).ToString("0") + ") pixels";
131
132      var image = new Bitmap(previewWidth, previewHeight);
133      image.SetResolution(dpi, dpi);
134      using (Graphics graphics = Graphics.FromImage(image)) {
135        if (scaleFactor < 1) graphics.ScaleTransform(scaleFactor, scaleFactor);
136        workingChart.Printing.PrintPaint(graphics, new Rectangle(0, 0, (int)Math.Round(width), (int)Math.Round(height)));
137      }
138      previewPictureBox.Image = image;
139    }
140
141    private void GetImageParameters(out float dpi, out float width, out float height) {
142      dpi = float.Parse(resolutionComboBox.Text);
143      if (resolutionUnitComboBox.Text == DPCM) dpi *= CMPERINCH;
144      width = (float)widthNumericUD.Value;
145      height = (float)heightNumericUD.Value;
146      if (lengthUnitComboBox.Text == CM) {
147        width /= CMPERINCH; height /= CMPERINCH;
148      }
149      width *= dpi; height *= dpi;
150    }
151
152    protected override void OnShown(EventArgs e) {
153      #region Create copy of chart
154      var prevContent = originalChart.Serializer.Content;
155      var prevFormat = originalChart.Serializer.Format;
156      originalChart.Serializer.Content = SerializationContents.Default;
157      originalChart.Serializer.Format = SerializationFormat.Binary;
158      using (var ms = new MemoryStream()) {
159        originalChart.Serializer.Save(ms);
160
161        ms.Seek(0, SeekOrigin.Begin);
162        workingChart = new EnhancedChart();
163        workingChart.Serializer.Format = originalChart.Serializer.Format;
164        workingChart.Serializer.Load(ms);
165      }
166
167      foreach (var s in workingChart.Series.Where(x => !x.Points.Any()).ToArray())
168        s.IsVisibleInLegend = false;
169
170      originalChart.Serializer.Content = prevContent;
171      originalChart.Serializer.Format = prevFormat;
172      #endregion
173
174      chartAreaComboBox.Items.Clear();
175      foreach (var area in originalChart.ChartAreas) {
176        chartAreaComboBox.Items.Add(area.Name);
177      }
178      chartAreaComboBox.SelectedIndex = 0;
179      SuppressEvents = true;
180      try {
181        showPrimaryXAxisCheckBox.Checked = originalChart.Series.Any(x => x.XAxisType == AxisType.Primary);
182        showPrimaryYAxisCheckBox.Checked = originalChart.Series.Any(x => x.YAxisType == AxisType.Primary);
183        showSecondaryXAxisCheckBox.Checked = originalChart.Series.Any(x => x.XAxisType == AxisType.Secondary);
184        showSecondaryYAxisCheckBox.Checked = originalChart.Series.Any(x => x.YAxisType == AxisType.Secondary);
185
186        if (!workingChart.Legends.Any()) {
187          legendPositionComboBox.Enabled = false;
188          legendFontSizeComboBox.Enabled = false;
189        } else {
190          legendPositionComboBox.Enabled = true;
191          legendFontSizeComboBox.Enabled = true;
192          if (workingChart.Legends[0].Enabled) {
193            switch (workingChart.Legends[0].Docking) {
194              case Docking.Top:
195                legendPositionComboBox.SelectedItem = "Top";
196                break;
197              case Docking.Right:
198                legendPositionComboBox.SelectedItem = "Right";
199                break;
200              case Docking.Bottom:
201                legendPositionComboBox.SelectedItem = "Bottom";
202                break;
203              case Docking.Left:
204                legendPositionComboBox.SelectedItem = "Left";
205                break;
206            }
207          } else {
208            legendPositionComboBox.SelectedItem = "Hidden";
209          }
210        }
211      } finally { SuppressEvents = false; }
212      base.OnShown(e);
213
214      if (togglePreviewCheckBox.Checked) UpdatePreview();
215    }
216
217    private void togglePreviewCheckBox_CheckedChanged(object sender, EventArgs e) {
218      splitContainer.Panel2Collapsed = !togglePreviewCheckBox.Checked;
219      togglePreviewCheckBox.Text = togglePreviewCheckBox.Checked ? "<" : ">";
220      if (splitContainer.Panel2Collapsed)
221        Width = cancelButton.Right + cancelButton.Margin.Right + Margin.Right + 10;
222      else
223        Width = splitContainer.Right + splitContainer.Margin.Right + Margin.Right;
224      if (togglePreviewCheckBox.Checked) UpdatePreview();
225    }
226
227    private void chartAreaComboBox_SelectedIndexChanged(object sender, EventArgs e) {
228      if (chartAreaComboBox.SelectedIndex >= 0)
229        UpdateFields();
230    }
231
232    private void legendPositionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
233      if (!SuppressEvents) {
234        if (legendPositionComboBox.SelectedIndex >= 0) {
235          var legend = workingChart.Legends[0];
236          var legendPosition = legendPositionComboBox.Items[legendPositionComboBox.SelectedIndex].ToString();
237          if (legendPosition != "Hidden" && !legend.Enabled)
238            legend.Enabled = true;
239          switch (legendPosition) {
240            case "Top":
241              legend.Docking = Docking.Top;
242              break;
243            case "Right":
244              legend.Docking = Docking.Right;
245              break;
246            case "Bottom":
247              legend.Docking = Docking.Bottom;
248              break;
249            case "Left":
250              legend.Docking = Docking.Left;
251              break;
252            case "Hidden":
253              legend.Enabled = false;
254              break;
255          }
256        }
257        UpdatePreview();
258      }
259    }
260
261    private void titleTextBox_TextChanged(object sender, EventArgs e) {
262      if (!SuppressEvents) {
263        if (string.IsNullOrEmpty(titleTextBox.Text))
264          workingChart.Titles.Clear();
265        else {
266          if (workingChart.Titles.Count > 0) {
267            workingChart.Titles[0].Text = titleTextBox.Text;
268          } else {
269            var t = new Title(titleTextBox.Text);
270            t.Font = ChangeFontSizePt(t.Font, float.Parse(titleFontSizeComboBox.Text));
271            workingChart.Titles.Add(t);
272          }
273        }
274        if (togglePreviewCheckBox.Checked) UpdatePreview();
275      }
276    }
277
278    private void primaryXTextBox_TextChanged(object sender, EventArgs e) {
279      if (!SuppressEvents) {
280        var area = GetCurrentChartArea();
281        area.AxisX.Title = primaryXTextBox.Text;
282        if (togglePreviewCheckBox.Checked) UpdatePreview();
283      }
284    }
285
286    private void primaryYTextBox_TextChanged(object sender, EventArgs e) {
287      if (!SuppressEvents) {
288        var area = GetCurrentChartArea();
289        area.AxisY.Title = primaryYTextBox.Text;
290        if (togglePreviewCheckBox.Checked) UpdatePreview();
291      }
292    }
293
294    private void secondaryXTextBox_TextChanged(object sender, EventArgs e) {
295      if (!SuppressEvents) {
296        var area = GetCurrentChartArea();
297        area.AxisX2.Title = secondaryXTextBox.Text;
298        if (togglePreviewCheckBox.Checked) UpdatePreview();
299      }
300    }
301
302    private void secondaryYTextBox_TextChanged(object sender, EventArgs e) {
303      if (!SuppressEvents) {
304        var area = GetCurrentChartArea();
305        area.AxisY2.Title = secondaryYTextBox.Text;
306        if (togglePreviewCheckBox.Checked) UpdatePreview();
307      }
308    }
309
310    private void showPrimaryXAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
311      if (!SuppressEvents) {
312        var area = GetCurrentChartArea();
313        var isChecked = ((CheckBox)sender).Checked;
314        area.AxisX.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
315        if (togglePreviewCheckBox.Checked) UpdatePreview();
316      }
317    }
318
319    private void showPrimaryYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
320      if (!SuppressEvents) {
321        var area = GetCurrentChartArea();
322        var isChecked = ((CheckBox)sender).Checked;
323        area.AxisY.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
324        if (togglePreviewCheckBox.Checked) UpdatePreview();
325      }
326    }
327
328    private void showSecondaryXAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
329      if (!SuppressEvents) {
330        var area = GetCurrentChartArea();
331        var isChecked = ((CheckBox)sender).Checked;
332        area.AxisX2.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
333        if (togglePreviewCheckBox.Checked) UpdatePreview();
334      }
335    }
336
337    private void showSecondaryYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
338      if (!SuppressEvents) {
339        var area = GetCurrentChartArea();
340        var isChecked = ((CheckBox)sender).Checked;
341        area.AxisY2.Enabled = isChecked ? AxisEnabled.True : AxisEnabled.False;
342        if (togglePreviewCheckBox.Checked) UpdatePreview();
343      }
344    }
345
346    private void widthNumericUD_ValueChanged(object sender, EventArgs e) {
347      float dpi, width, height;
348      GetImageParameters(out dpi, out width, out height);
349      if (GetRawImageSizeInMegabytes(width, height) > 25) // bigger than A4 at 300dpi
350        MessageBox.Show("Warning: The image is getting quite big.");
351      if (togglePreviewCheckBox.Checked) UpdatePreview();
352    }
353
354    private void heightNumericUD_ValueChanged(object sender, EventArgs e) {
355      float dpi, width, height;
356      GetImageParameters(out dpi, out width, out height);
357      if (GetRawImageSizeInMegabytes(width, height) > 25) // bigger than A4 at 300dpi
358        MessageBox.Show("Warning: The image is getting quite big.");
359      if (togglePreviewCheckBox.Checked) UpdatePreview();
360    }
361
362    private void titleFontSizeComboBox_TextChanged(object sender, EventArgs e) {
363      if (!SuppressEvents) {
364        float fontSize;
365        if (float.TryParse(titleFontSizeComboBox.Text, out fontSize)) {
366          if (workingChart.Titles.Count > 0) {
367            workingChart.Titles[0].Font = ChangeFontSizePt(workingChart.Titles[0].Font, fontSize);
368            if (togglePreviewCheckBox.Checked) UpdatePreview();
369          }
370        }
371      }
372    }
373
374    private void axisFontSizeComboBox_TextChanged(object sender, EventArgs e) {
375      if (!SuppressEvents) {
376        float fontSize;
377        if (float.TryParse(axisFontSizeComboBox.Text, out fontSize)) {
378          var area = GetCurrentChartArea();
379          foreach (Axis a in area.Axes)
380            a.TitleFont = ChangeFontSizePt(a.TitleFont, fontSize);
381        }
382        if (togglePreviewCheckBox.Checked) UpdatePreview();
383      }
384    }
385
386    private void scalesFontSizeComboBox_TextChanged(object sender, EventArgs e) {
387      if (!SuppressEvents) {
388        float fontSize;
389        if (float.TryParse(scalesFontSizeComboBox.Text, out fontSize)) {
390          var area = GetCurrentChartArea();
391          foreach (var a in area.Axes)
392            a.LabelStyle.Font = ChangeFontSizePt(a.LabelStyle.Font, fontSize);
393        }
394        if (togglePreviewCheckBox.Checked) UpdatePreview();
395      }
396    }
397
398    private void legendFontSizeComboBox_TextChanged(object sender, EventArgs e) {
399      if (!SuppressEvents) {
400        float fontSize;
401        if (float.TryParse(legendFontSizeComboBox.Text, out fontSize)) {
402          foreach (var l in workingChart.Legends)
403            l.Font = ChangeFontSizePt(l.Font, fontSize);
404        }
405        if (togglePreviewCheckBox.Checked) UpdatePreview();
406      }
407    }
408
409    private void numericComboBox_Validating(object sender, CancelEventArgs e) {
410      if (!(sender is ComboBox)) return;
411      float number;
412      e.Cancel = !float.TryParse((sender as ComboBox).Text, out number);
413    }
414
415    private void resolutionComboBox_TextChanged(object sender, EventArgs e) {
416      float resolution;
417      if (float.TryParse(resolutionComboBox.Text, out resolution)) {
418        if (togglePreviewCheckBox.Checked) UpdatePreview();
419      }
420    }
421
422    private void resolutionComboBox_Validating(object sender, CancelEventArgs e) {
423      float resolution;
424      e.Cancel = !float.TryParse(resolutionComboBox.Text, out resolution);
425    }
426
427    private void resolutionUnitComboBox_SelectedIndexChanged(object sender, EventArgs e) {
428      if (togglePreviewCheckBox.Checked) UpdatePreview();
429    }
430
431    private void lengthUnitComboBox_SelectedIndexChanged(object sender, EventArgs e) {
432      if (togglePreviewCheckBox.Checked) UpdatePreview();
433    }
434
435    private void okButton_Click(object sender, EventArgs e) {
436      float dpi;
437      float width;
438      float height;
439      GetImageParameters(out dpi, out width, out height);
440
441      var image = new Bitmap((int)Math.Round(width), (int)Math.Round(height));
442      image.SetResolution(dpi, dpi);
443      using (var graphics = Graphics.FromImage(image)) {
444        workingChart.Printing.PrintPaint(graphics, new Rectangle(0, 0, image.Width, image.Height));
445      }
446
447      if (titleTextBox.Text.Trim() != String.Empty) saveFileDialog.FileName = titleTextBox.Text.Trim();
448      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
449        var format = ImageFormat.Bmp;
450        var filename = saveFileDialog.FileName.ToLower();
451        if (filename.EndsWith("jpg")) {
452          format = ImageFormat.Jpeg;
453        } else if (filename.EndsWith("emf")) {
454          format = ImageFormat.Emf;
455        } else if (filename.EndsWith("gif")) {
456          format = ImageFormat.Gif;
457        } else if (filename.EndsWith("png")) {
458          format = ImageFormat.Png;
459        } else if (filename.EndsWith("tif")) {
460          format = ImageFormat.Tiff;
461        }
462        image.Save(saveFileDialog.FileName, format);
463      }
464
465      image.Dispose();
466
467      Cleanup();
468    }
469
470    private void cancelButton_Click(object sender, EventArgs e) {
471      Cleanup();
472    }
473
474    private void Cleanup() {
475      if (previewPictureBox.Image != null) previewPictureBox.Image.Dispose();
476      previewPictureBox.Image = null;
477      workingChart = null;
478    }
479
480    private static Font ChangeFontSizePt(Font font, float fontSize) {
481      if (font != null) {
482        float currentSize = font.Size;
483        if (currentSize != fontSize) {
484          font = new Font(font.Name, fontSize, font.Style, GraphicsUnit.Point, font.GdiCharSet, font.GdiVerticalFont);
485        }
486      }
487      return font;
488    }
489
490    private static float GetRawImageSizeInMegabytes(float width, float height) {
491      return ((3 * width * height) / (1024 * 1024));
492    }
493
494  }
495}
Note: See TracBrowser for help on using the repository browser.