EXCEL(带图)转html

文章目录

  • 叙述
  • 1、效果
  • 2、excel 转换主逻辑
  • 3、其他补充
        • 3.0 主前端bootstrap
        • 3.1 my.css:
        • 3.2 my.js
        • 3.3 入口home.html
        • 3.4 Data.ashx

叙述

要实现H5 展示excel
查询 了一下没有好的办法,自己写了一个,简单记录一下

1、效果

在这里插入图片描述
用bootstrap 根据sheet做了一个菜单。

2、excel 转换主逻辑

using System;
using System.IO;
using System.Text;
using NPOI.OpenXmlFormats.Spreadsheet;
using NPOI.XSSF.Model;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using static NPOI.HSSF.Util.HSSFColor;
using NPOI.XSSF.Streaming;
using System.Collections.Generic;
using System.Linq;public class ForExcel
{public static string Main(string excelFilePath){string htmlFilePath = AppDomain.CurrentDomain.BaseDirectory + "show1.html";//excelFilePath= HttpUtility.UrlDecode(excelFilePath);try{string htmlContent = ConvertWorkbookToHtml(excelFilePath);File.WriteAllText(htmlFilePath, htmlContent, Encoding.UTF8);return "show1.html";}catch (Exception ex){return "false";}}public static string ConvertWorkbookToHtml(string filePath){IWorkbook workbook;using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)){if (Path.GetExtension(filePath) == ".xls")workbook = new HSSFWorkbook(fs); // 处理 Excel 2003elseworkbook = new XSSFWorkbook(fs); // 处理 Excel 2007+}StringBuilder htmlBuilder = new StringBuilder();htmlBuilder.Append("<html>");htmlBuilder.Append("<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><script src=\"assist/bootstrap/jquery-3.7.0.min.js\"></script>\r\n    <script src=\"assist/bootstrap/js/bootstrap.js\"></script>\r\n    <link href=\"assist/bootstrap/css/bootstrap.css\" rel=\"stylesheet\" />  <link href=\"assist/my.css\" rel=\"stylesheet\" />");//脚本htmlBuilder.Append("<script type=\"text/javascript\">"+ "        function onMenu(o){"+ "            $(\".nav-link\").removeClass(\"active\");"+ "            $(\"#nav\" + o).addClass(\"active\");"+ "            $(\".dtable\").hide();"+ "            $(\"#dtable\" + o).show();"+ "" + "        }"+ "   window.onload = function () {"+ "            var menuheight = $(\".menu\").height()+10;"+ "            $(\".content\").css(\"padding-top\", menuheight+40);"+ "        }</script >");htmlBuilder.Append("</head>");//顶部返回htmlBuilder.Append("<body>"+ "<nav class='navbar navbar-light bg-light'>"+ "<div class='container-fluid'>"+ "<a href='javascript:history.back()' class='back-arrow' aria-label='返回'>&lt;</a>"+ "</div>"+ "</nav>"+ "<div class='menu'>");//菜单htmlBuilder.Append("<ul class=\"nav nav-tabs\">");for (int i = 0; i < workbook.NumberOfSheets; i++){ISheet sheet = workbook.GetSheetAt(i);htmlBuilder.AppendFormat(" <li class=\"nav-item\">\r\n  <a class=\"nav-link " + (i == 0 ? "active" : "") + "\" "+ $" id=\"nav{i}\""+ $" href=\"javascript:onMenu({i})\">{sheet.SheetName}</a>"+ "</li>", sheet.SheetName);}htmlBuilder.Append(" </ul></div>");//内容htmlBuilder.Append("<div  class='content'>");for (int i = 0; i < workbook.NumberOfSheets; i++){htmlBuilder.Append($"<table class='dtable' id='dtable{i}' " + (i != 0 ? "style='display:none;'" : "") + ">");ISheet sheet = workbook.GetSheetAt(i);//标记插入图片后导致的位移List<tude> InImg = new List<tude>();//最大列、最大行int maxcol = 0; int maxrow = sheet.LastRowNum;//图片不占单元格,但是需要循环到位置if (sheet is XSSFSheet xssfSheet2){foreach (var drawing in xssfSheet2.GetDrawingPatriarch().GetShapes()){if (drawing is XSSFPicture picture){int m1 = picture.ClientAnchor.Col2;int m2 = picture.ClientAnchor.Row2;if (m1 > maxcol) maxcol = m1;if (m2 > maxrow) maxrow = m2;}}}for (int x = 0; x < maxrow; x++)//行{IRow row = sheet.GetRow(x);htmlBuilder.Append("<tr>");if (x == 0)//没图片就取第一行列数{ if (row.LastCellNum > maxcol) maxcol = row.LastCellNum; }for (int j = 0; j < maxcol; j++)//列{ICell cell; string cellValue;if (row != null){cell = row.GetCell(j);cellValue = cell?.ToString() ?? "";}else cellValue = "";// 检查单元格是否包含图片bool hasImage = false;if (sheet is XSSFSheet xssfSheet){foreach (var drawing in xssfSheet.GetDrawingPatriarch().GetShapes()){int nowrow = 0; int nowcol = 0;if (drawing is XSSFPicture picture){if (picture.ClientAnchor.Col1 == j && picture.ClientAnchor.Row1 == x){byte[] imageBytes = ((XSSFPicture)drawing).PictureData.Data;string base64Image = Convert.ToBase64String(imageBytes);string imageFormat = ((XSSFPicture)drawing).PictureData.MimeType.Split('/')[1];cellValue = $"<img src='data:image/{imageFormat};base64,{base64Image}'/>";hasImage = true;nowrow = picture.ClientAnchor.Row2 - picture.ClientAnchor.Row1;//图片占几行nowcol = picture.ClientAnchor.Col2 - picture.ClientAnchor.Col1;//图片占列行//标记坐标,解决多行多列导致的位移for(int a= picture.ClientAnchor.Row1; a<= picture.ClientAnchor.Row2;a++)//行{for (int b = picture.ClientAnchor.Col1; b <= picture.ClientAnchor.Col2; b++)//列{tude t = new tude();t.xx = b;//列 xt.yy = a;//行 yInImg.Add(t);}}if (hasImage)htmlBuilder.AppendFormat("<td rowspan='{1}'  colspan='{2}' >{0}</td>", cellValue, nowrow, nowcol);}}}}if (!hasImage){if (InImg.Where(p=>p.xx==j &p.yy==x).ToList().Count>0) { }//坐标校对 是否被图片占用else{htmlBuilder.AppendFormat("<td>{0}</td>", cellValue);}}}htmlBuilder.Append("</tr>");}//整个sheet没有内容,只有图if (maxcol == 0 && maxrow == 0){if (sheet is XSSFSheet xssfSheet){foreach (var drawing in xssfSheet.GetDrawingPatriarch().GetShapes()){htmlBuilder.Append("<tr>");if (drawing is XSSFPicture picture){byte[] imageBytes = ((XSSFPicture)drawing).PictureData.Data;string base64Image = Convert.ToBase64String(imageBytes);string imageFormat = ((XSSFPicture)drawing).PictureData.MimeType.Split('/')[1];string cellValue = $"<img src='data:image/{imageFormat};base64,{base64Image}'/>";htmlBuilder.AppendFormat("<td>{0}</td>", cellValue);}htmlBuilder.Append("</tr>");}}}htmlBuilder.Append("</table>");}htmlBuilder.Append("</div>");htmlBuilder.Append("</body></html>");return htmlBuilder.ToString();}class tude { public int xx { set; get; }public int yy { set; get; }
}

主要比较坑的是
1、使用 foreach (IRow row in sheet),永远访问不到插入的图片,因为单元格是空
2、workbook.GetAllPictures()很容易获取到图片,sheet就很难 各种报错
补充一些环境 .Net FramWork4.72 +NPOI 2.6.2

3、其他补充

3.0 主前端bootstrap

下载:https://bootstrap.p2hp.com/docs/5.3/getting-started/download/
不想搞太复杂,bootstrap就JS+CSS 下载解压复制到项目就行
我的样式

3.1 my.css:
body {padding-left: 10px;background-color: #e1e0e0;margin-bottom: 50px;
}
table {border: solid 1px #e1e0e0;background-color: white;}
table td {border: solid 1px #e1e0e0;}.nav {padding-left: 10px;padding-top: 10px;background-color:#e1e0e0
}
.menu {width: 100%;position: fixed;top: 40px;z-index: 100;
}
.content {position: relative;padding-top: 40px;z-index: 99;
}
@media (min-width: 768px) {}
@media (max-width: 768px) {.menu {position: fixed;top:40px;float: left;left: 10px;max-width: 350px;}.content {max-width:350px;overflow:scroll;}.nav-item {font-size:11px;white-space: nowrap;
/*        max-width: 60px;overflow: hidden;*/}}.navbar {position: fixed;z-index: 100;width:100%;background-color: #f8f9fa;box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.back-arrow {text-decoration: none !important;color: inherit;display: inline-block;}
3.2 my.js
//加密
function encryptAES(plainText, key) {const encrypted = CryptoJS.AES.encrypt(plainText, CryptoJS.enc.Utf8.parse(key), {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();
}
//URL参数
function getQueryParam(param) {const regex = new RegExp('[?&]' + param + '=([^&#]*)');const match = regex.exec(window.location.search);return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
}
3.3 入口home.html

请求

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title></title><script src="assist/bootstrap/jquery-3.7.0.min.js"></script><script src="assist/my.js"></script><script type="text/javascript">window.onload = function () {var _src = getQueryParam('src');if (_src == null) return;var src =$.ajax({url: 'Data.ashx',type: 'POST',data: { src: _src },success: function (response) {window.location.href = response;}});}</script>
</head>
<body></body>
</html>
3.4 Data.ashx
public class Data : IHttpHandler
{public void ProcessRequest(HttpContext context){context.Response.ContentType = "text/plain";context.Response.Write(myvoid(context.Request.Form["src"]));}private string myvoid(string url) {if (url.Contains(".xlsx"))rst = ForExcel.Main(url);}}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88005.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序富文本Editor插入图片、超链接、公式等的一次尝试

小程序插入图片 通过EditorContext.insertImage接口可以实现图片的插入&#xff1a; EditorContext.insertImage({src,width,height,data, })如何插入超链接、公式、视频、表格等等? 通过EditorContext.insertCustomBlock应该是可以实现的&#xff0c;具体实现方式我没有了…

传输层协议TCP、UDP

传输层协议TCP、UDP 1、TCP和UDP报文格式 传输层协议TCPvsUDP 传输层主要两个传输协议&#xff0c;分别是TCP和UDP&#xff0c;负责提供流量控制、排序服务和错误校验。 &#xff08;1&#xff09;TCP是面向连接的&#xff0c;一般用于传输数据量比较少&#xff0c;且对可靠性要…

设计模式—专栏简介

大学总是忙着参加ACM实验室的各种事情&#xff0c;到了毕业的时候&#xff0c;对于设计模式也是仅了解单例模式。毕业后&#xff0c;刚开始代码也是乱写一通&#xff0c;完全没有章法。整个开发环境也是为了解决问题&#xff0c;从来没有考虑结构化什么的&#xff08;没办法&am…

面试150 链表的复制

思路 python可以使用调库法&#xff0c;使用深度拷贝 """ # Definition for a Node. class Node:def __init__(self, x: int, next: Node None, random: Node None):self.val int(x)self.next nextself.random random """class Solution:de…

MySQL分布式ID冲突详解:场景、原因与解决方案

引言 在分布式系统开发中&#xff0c;你是否遇到过这样的崩溃时刻&#xff1f;——明明每个数据库实例的自增ID都从1开始&#xff0c;插入数据时却提示“Duplicate entry ‘100’ for key ‘PRIMARY’”&#xff1b;或者分库分表后&#xff0c;不同库里的订单ID竟然重复&#x…

c++文字游戏_闯关打怪2.0(开源)

本次更新内容: 1.增强对手性能 2.可暂停(按N) 3.修复些许bug 4.增加boos关(第10、20、30...关) 1. 游戏概述 本游戏是一个基于Windows控制台的回合制战斗游戏,采用俯视视角的2D平面设计。玩家控制角色"p"在1325大小的封闭场景中与敌人"@"战斗,通过…

Java学习第十二部分——idea各种项目简介

目录 一.前言 二.语言介绍 三.生成器介绍 四.拓展 一.前言 打开idea项目创建时发现如上情况&#xff0c;“新建项目”下面的是语言&#xff0c;生成器下面的是这些语言对应的生成器工具&#xff0c;本文将简单介绍。 二.语言介绍 Java 用途&#xff1a;Java是一种广泛使…

Codeforces Round 868 (Div. 2) D. Unique Palindromes(1900,构造)

Problem - D - Codeforces 不错的字符串构造体&#xff0c;记录一下 首先注意到k≤20这一条件。对于一个长度为n的字符串&#xff0c;最多有n个不同的回文子串&#xff0c;这种情况出现在所有字符都相同时。因此&#xff0c;限制条件中的xi必须满足xi≤ci&#xff0c;且相邻两…

ClickHouse 全生命周期性能优化

引言 ClickHouse作为列式存储的OLAP数据库&#xff0c;以其极致的查询性能著称&#xff0c;但"高性能"并非开箱即用。不合理的表设计、SQL写法或集群配置&#xff0c;可能导致性能衰减甚至服务不可用。本文基于ClickHouse 24.3版本&#xff0c;从设计规范、开发规范、…

Linux sed 命令 详解

在 Linux 系统中&#xff0c;sed&#xff08;Stream Editor&#xff09;是一个非常强大且灵活的文本处理工具。它不仅可以用于简单的文本替换、删除和插入操作&#xff0c;还能实现复杂的文本转换任务。 &#x1f4cc; 一、什么是 sed&#xff1f; sed 是一个基于模式匹配对文…

项目进度同步不及时,如何提升信息透明度

项目进度同步不及时的核心问题包括沟通渠道不畅通、缺乏统一的信息平台、未建立明确的进度更新机制、团队意识不足、责任划分不明确等。其中&#xff0c;缺乏统一的信息平台最为关键。统一的信息平台能够确保所有相关人员实时掌握最新的进度状态&#xff0c;避免信息孤岛&#…

使用各种CSS美化网页

实验目的1.理解CSS的概念&#xff0c;掌握CSS定义样式的方法&#xff0c;具备使用CSS和相关库进行界面样式设计的能力。 2.掌握Bootstrap 5的基本使用方法。3.Bootstrap框架练习实验步骤1. 实验准备创建一个HTML文件&#xff08;如 index.html&#xff09;。引入Bootstrap5的CS…

在PPT的文本框中,解决一打字,英文双引号就变成中文了

问题&#xff1a;在制作PPT的过程中&#xff0c;插入文本框&#xff0c;在里面输入代码类的格式时&#xff0c;使用英文的双引号""&#xff0c;但是只要在后面输入内容&#xff0c;或者逗号等&#xff0c;英文双引号就变成中文了&#xff0c;很烦原因&#xff1a;大概…

iOS 证书过期如何处理

找到钥匙串位置创建新的CSR文件。点击菜单中钥匙串访问—>证书助理—>从证书颁发机构请求证书…进入证书助理&#xff0c;填写信息&#xff08;用户名称和邮箱随便写&#xff09;&#xff0c;请求是 选择 存储到磁盘创建好CSR文件&#xff0c;回到developer 证书管理中心…

CODESYS + 全志T113-i + 国产系统OneOS,打造新一代工业控制解决方案!

创龙科技与中移物联网有限公司、CODESYS携手合作&#xff0c;成功实现了T113-i工业评估板对国产系统OneOS CODESYS软件的适配&#xff0c;此举将让工业自动化领域的工程师们更高效地开发&#xff0c;并为众多企业产品的快速上市提供强有力的保障。 解决方案简介 CODESYS简介 …

三、jenkins使用tomcat部署项目

一、安装tomcattomcat本来应该是第3台服务器的&#xff08;第一台&#xff1a;gitlab&#xff0c;第二台&#xff1a;jenkins&#xff0c;第三台&#xff1a;tomcat&#xff09;&#xff0c;我这里资源有限&#xff0c;就把tomcat安装jenkins服务器了。#解压tocmcat [rootbogon…

华为eNSP防火墙实验(包含详细步骤)

拓扑图 这里要用的防火墙是 &#xff0c; 需要导入 目录 防火墙配置1&#xff08;启动图形化界面&#xff09; cloud配置 缓冲区服务器配置 防火墙配置2&#xff08;各端口的ip地址&#xff09; 外部路由器配置 本地路由器配置 防火墙配置3&#xff08;配置安全策略&a…

Linux/Unix线程及其同步(create、wait、exit、互斥锁、条件变量、多线程)

线程 文章目录线程I 线程基本概念1、为什么引入线程2、PthreadsII 线程基本操作1、创建线程2、终止线程3、线程ID4、连接已终止线程5、线程基本操作示例III 通过互斥量同步线程1、基本概念2、互斥量&#xff08;Mutex&#xff09;3、静态分配互斥量4、互斥量锁定与解锁5、互斥量…

vue3 el-table 行数据沾满格 取消自动换行

在 Vue.js 使用 Element UI 或 Element Plus 的 <el-table> 组件时&#xff0c;如果你希望其中的单元格内容不自动换行&#xff0c;可以通过设置 CSS 样式来实现。这里有几种方法可以做到这一点&#xff1a;方法1&#xff1a;使用 CSS 样式你可以直接在 <el-table-col…

操作系统级TCP性能优化:高并发场景下的内核参数调优实践

在高并发网络场景中&#xff0c;操作系统内核的TCP/IP协议栈配置对系统性能起着决定性作用。本文聚焦操作系统层面&#xff0c;深入解析内核参数调优策略&#xff0c;帮助读者构建稳定高效的网络通信架构。 一、连接管理参数优化&#xff1a;从三次握手到队列控制 1.1 监听队列…