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;
}
}
}