From a417bceaacd8b53fd5406ea01aafb369dc11b201 Mon Sep 17 00:00:00 2001 From: danielpalme Date: Thu, 24 Aug 2017 22:00:24 +0200 Subject: [PATCH] Issue #93: Added badges in PNG format --- README.md | 2 +- Readme.txt | 4 ++ .../BadgeReportBuilder.cs | 60 +++++++++++++++++-- .../Properties/AssemblyInfo.cs | 4 +- ReportGenerator/Properties/AssemblyInfo.cs | 4 +- .../Properties/AssemblyInfo.cs | 4 +- 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 70d714c4..ee120402 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The screenshots show two snippets of the generated reports: ![Screenshot 2](http://danielpalme.github.io/ReportGenerator/resources/screenshot2.png) ### Badges -Badges in SVG format can be generated if `-reporttypes:Badges` is used: +Badges in SVG and PNG format can be generated if `-reporttypes:Badges` is used: ![Sample badge](http://danielpalme.github.io/ReportGenerator/resources/badge.svg) diff --git a/Readme.txt b/Readme.txt index 7fcbe274..9dc75640 100644 --- a/Readme.txt +++ b/Readme.txt @@ -61,6 +61,10 @@ For further details take a look at LICENSE.txt. CHANGELOG +2.5.11.0 + + * New: Issue #93: Added badges in PNG format + 2.5.10.0 * New: Issue #94: Added filtering for files diff --git a/ReportGenerator.Reporting/BadgeReportBuilder.cs b/ReportGenerator.Reporting/BadgeReportBuilder.cs index 108e5784..1e737c5c 100644 --- a/ReportGenerator.Reporting/BadgeReportBuilder.cs +++ b/ReportGenerator.Reporting/BadgeReportBuilder.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using System.Drawing; +using System.Drawing.Imaging; using System.Globalization; using System.IO; using Palmmedia.ReportGenerator.Parser.Analysis; @@ -126,6 +128,16 @@ public class BadgeReportBuilder : IReportBuilder /// private const string CoverageTooltip = @"{1}"; + /// + /// The template for line coverage badge in PNG format. + /// + private const string LineCoveragePngTemplate = "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"; + + /// + /// The template for branch coverage badge in PNG format. + /// + private const string BranchCoveragePngTemplate = "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"; + /// /// Gets the report type. /// @@ -166,21 +178,29 @@ public void CreateSummaryReport(SummaryResult summaryResult) { File.WriteAllText( Path.Combine(this.TargetDirectory, "badge_linecoverage.svg"), - this.CreateBadge(summaryResult, true, false)); + this.CreateSvgBadge(summaryResult, true, false)); + + File.WriteAllBytes( + Path.Combine(this.TargetDirectory, "badge_linecoverage.png"), + this.CreatePngBadge(summaryResult, true)); } if (summaryResult.BranchCoverageQuota.HasValue) { File.WriteAllText( Path.Combine(this.TargetDirectory, "badge_branchcoverage.svg"), - this.CreateBadge(summaryResult, false, true)); + this.CreateSvgBadge(summaryResult, false, true)); + + File.WriteAllBytes( + Path.Combine(this.TargetDirectory, "badge_branchcoverage.png"), + this.CreatePngBadge(summaryResult, false)); } if (summaryResult.CoverageQuota.HasValue && summaryResult.BranchCoverageQuota.HasValue) { File.WriteAllText( Path.Combine(this.TargetDirectory, "badge_combined.svg"), - this.CreateBadge(summaryResult, true, true)); + this.CreateSvgBadge(summaryResult, true, true)); } } @@ -191,7 +211,7 @@ public void CreateSummaryReport(SummaryResult summaryResult) /// Indicates whether line coverage should be included. /// Indicates whether branch coverage should be included. /// The rendered SVG. - private string CreateBadge(SummaryResult summaryResult, bool includeLineCoverage, bool includeBranchCoverage) + private string CreateSvgBadge(SummaryResult summaryResult, bool includeLineCoverage, bool includeBranchCoverage) { string lineCoverageClass = includeLineCoverage && includeBranchCoverage ? "linecoverage" : string.Empty; string branchCoverageClass = includeLineCoverage && includeBranchCoverage ? "branchcoverage" : string.Empty; @@ -208,5 +228,37 @@ private string CreateBadge(SummaryResult summaryResult, bool includeLineCoverage includeLineCoverage ? string.Format(CoverageTooltip, lineCoverageClass, ReportResources.Coverage) : string.Empty, includeBranchCoverage ? string.Format(CoverageTooltip, branchCoverageClass, ReportResources.BranchCoverage) : string.Empty); } + + /// + /// Renderes the PNG. + /// + /// Indicates whether + /// Indicates whether line coverage or branch coverage should be displayed. + /// The rendered PNG. + private byte[] CreatePngBadge(SummaryResult summaryResult, bool lineCoverage) + { + string template = lineCoverage ? LineCoveragePngTemplate : BranchCoveragePngTemplate; + string text = (lineCoverage ? summaryResult.CoverageQuota.Value : summaryResult.BranchCoverageQuota.Value).ToString(CultureInfo.InvariantCulture) + "%"; + + using (var ms = new MemoryStream(Convert.FromBase64String(template))) + using (Image image = Bitmap.FromStream(ms)) + using (Graphics g = Graphics.FromImage(image)) + using (Font font = new Font("Verdana", 8, FontStyle.Regular, GraphicsUnit.Point)) + using (MemoryStream output = new MemoryStream()) + { + Rectangle rect = new Rectangle(112, 0, 155, 20); + + StringFormat stringFormat = new StringFormat() + { + Alignment = StringAlignment.Near, + LineAlignment = StringAlignment.Center + }; + + g.DrawString(text, font, Brushes.White, rect, stringFormat); + + image.Save(output, ImageFormat.Png); + return output.ToArray(); + } + } } } diff --git a/ReportGenerator.Reporting/Properties/AssemblyInfo.cs b/ReportGenerator.Reporting/Properties/AssemblyInfo.cs index b6eb7383..55b1e1f3 100644 --- a/ReportGenerator.Reporting/Properties/AssemblyInfo.cs +++ b/ReportGenerator.Reporting/Properties/AssemblyInfo.cs @@ -32,7 +32,7 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.10.0")] -[assembly: AssemblyFileVersion("2.5.10.0")] +[assembly: AssemblyVersion("2.5.11.0")] +[assembly: AssemblyFileVersion("2.5.11.0")] [assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/ReportGenerator/Properties/AssemblyInfo.cs b/ReportGenerator/Properties/AssemblyInfo.cs index dfbb9c8f..a108d9b5 100644 --- a/ReportGenerator/Properties/AssemblyInfo.cs +++ b/ReportGenerator/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern // übernehmen, indem Sie "*" eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.10.0")] -[assembly: AssemblyFileVersion("2.5.10.0")] +[assembly: AssemblyVersion("2.5.11.0")] +[assembly: AssemblyFileVersion("2.5.11.0")] [assembly: NeutralResourcesLanguageAttribute("en-US")] [assembly: CLSCompliant(true)] diff --git a/ReportGeneratorTest/Properties/AssemblyInfo.cs b/ReportGeneratorTest/Properties/AssemblyInfo.cs index 2c8a99a7..1c551806 100644 --- a/ReportGeneratorTest/Properties/AssemblyInfo.cs +++ b/ReportGeneratorTest/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.5.10.0")] -[assembly: AssemblyFileVersion("2.5.10.0")] +[assembly: AssemblyVersion("2.5.11.0")] +[assembly: AssemblyFileVersion("2.5.11.0")] [assembly: NeutralResourcesLanguageAttribute("en-US")]