MergeRows.cs
- //
- // This code is part of Document Solutions for Imaging demos.
- // Copyright (c) MESCIUS inc. All rights reserved.
- //
- using System;
- using System.IO;
- using System.Drawing;
- using System.Text;
- using System.Data;
- using System.Linq;
- using System.Collections.Generic;
- using GrapeCity.Documents.Drawing;
- using GrapeCity.Documents.Imaging;
- using GrapeCity.Documents.Text;
- using GrapeCity.Documents.Html;
-
- namespace DsImagingWeb.Demos
- {
- // This sample shows how to build and render a table-based report
- // grouped by the first column, with that column's cells with same
- // values merged.
- // This sample uses a JavaScript code in the HTML to actually
- // merge the cells, demonstrating the use of JavaScript when
- // rendering HTML to images.
- // Note that the sample limits the number of rows so that
- // the whole table fits in the image.
- //
- // Please see notes in comments at the top of HelloWorldHtml
- // sample code for details on adding DsHtml to your projects.
- public class MergeRows
- {
- public Stream GenerateImageStream(string targetMime, Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
- {
- const string TTAG = "___TABLE___";
-
- // HTML page template:
- const string tableTpl =
- "<!DOCTYPE html>" +
- "<html>" +
- "<head>" +
- "<style>" +
-
- "html * {" +
- " font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif !important;" +
- "}" +
-
- "h1 {" +
- " color: #1a5276;" +
- " background-color: #d2b4de;" +
- " text-align: center;" +
- " padding: 6px;" +
- "}" +
-
- "thead {display: table-header-group;}" +
-
- "#products {" +
- " font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif;" +
- " border-collapse: collapse;" +
- " width: 100%;" +
- "}" +
-
- "#products td, #products th {" +
- " border: 1px solid #ddd;" +
- " padding: 8px;" +
- "}" +
-
- // "#products tr:nth-child(even){background-color: #f2f2f2;}" +
-
- "#products tr:hover {background-color: #ddd;}" +
-
- "#products th {" +
- " padding-top: 12px;" +
- " padding-bottom: 12px;" +
- " text-align: left;" +
- " background-color: #a569bd;" +
- " color: white;" +
- "}" +
- "</style>" +
-
- "</head>" +
- "<body onload='mergeRows()'>" +
-
- // solution from https://stackoverflow.com/questions/56587070/merge-neighbouring-html-table-cells-with-same-value-using-js
- "<script>" +
- "function mergeRows() {" +
- " const table = document.querySelector('table');" +
- " let headerCell = null;" +
- " for (let row of table.rows)" +
- " {" +
- " const firstCell = row.cells[0];" +
- " if (headerCell === null || firstCell.innerText !== headerCell.innerText)" +
- " {" +
- " headerCell = firstCell;" +
- " }" +
- " else" +
- " {" +
- " headerCell.rowSpan++;" +
- " firstCell.remove();" +
- " }" +
- " }" +
- "}" +
- "</script>" +
-
- TTAG +
-
- "</body>" +
- "</html>";
-
- const string tableHead = "<h1>Products by Suppliers</h1>";
-
- const string tableFmt =
- "<table id='products'>" +
- " <thead>" +
- " <th>Supplier</th>" +
- " <th>Description</th>" +
- " <th>Quantity Per Unit</th>" +
- " <th>Unit Price</th>" +
- " </thead>" +
- "{0}" +
- "</table>";
-
- const string dataRowFmt =
- " <tr>" +
- " <td>{0}</td>" +
- " <td>{1}</td>" +
- " <td>{2}</td>" +
- " <td align='right'>{3:C}</td>" +
- " </tr>";
-
- DataSet ds = new DataSet();
- ds.ReadXml(Path.Combine("Resources", "data", "GcNWind.xml"));
-
- DataTable dtProds = ds.Tables["Products"];
- DataTable dtSupps = ds.Tables["Suppliers"];
-
- var products =
- (from prod in dtProds.Select()
- join supp in dtSupps.Select()
- on prod["SupplierID"] equals supp["SupplierID"]
- orderby supp["CompanyName"]
- select new
- {
- ProductName = prod["ProductName"],
- Supplier = supp["CompanyName"],
- QuantityPerUnit = prod["QuantityPerUnit"],
- UnitPrice = prod["UnitPrice"]
- }).Take(16);
-
- var sb = new StringBuilder();
- sb.AppendLine(tableHead);
- foreach (var prod in products)
- sb.AppendFormat(dataRowFmt, prod.Supplier, prod.ProductName, prod.QuantityPerUnit, prod.UnitPrice);
-
- var html = tableTpl.Replace(TTAG, string.Format(tableFmt, sb.ToString()));
-
- var tfile = Path.GetTempFileName();
- var ms = new MemoryStream();
- // We use GcHtmlBrowser to render the whole generated HTML to an image.
- // Note that GcHtmlBrowser natively supports only JPEG, PNG and WEBP formats.
- // In this sample we limit the output to those formats.
- // For a more flexible approach that allows rendering HTML into any
- // image format supported by DsImaging, please see HtmlRenderPage0.
- using var browser = Common.Util.NewHtmlBrowser();
- using var htmlPage = browser.NewPage(html, new PageOptions() { WindowSize = pixelSize });
- tfile = Path.GetTempFileName();
- switch (targetMime)
- {
- case Common.Util.MimeTypes.JPEG:
- htmlPage.SaveAsJpeg(tfile);
- break;
- case Common.Util.MimeTypes.PNG:
- htmlPage.SaveAsPng(tfile);
- break;
- case Common.Util.MimeTypes.WEBP:
- htmlPage.SaveAsWebp(tfile);
- break;
- default:
- throw new Exception("Unsupported image format.");
- }
- // Copy the created image from the temp file to target stream:
- using (var ts = File.OpenRead(tfile))
- ts.CopyTo(ms);
- // Clean up:
- File.Delete(tfile);
- // Done.
- return ms;
- }
- }
- }
-