C# 如何将SPL文件转换成EMF文件

编程入门 行业动态 更新时间:2024-10-26 04:28:26

C# <a href=https://www.elefans.com/category/jswz/34/1771359.html style=如何将SPL文件转换成EMF文件"/>

C# 如何将SPL文件转换成EMF文件

本文主要讲述如何将SPL文件转换成EMF文件。


目录

一、什么是SPL文件和EMF文件

(一)SPL文件

(二)EMF文件

二、文件解析

(一)SPL格式

(二)打开SPL文件

(三)解析SPL文件

 三、编程思路

(一)记录EMF文件的位置和大小

(二)找到EMF文件的开始位置和大小

(三)将SPL文件转换成EMF文件


一、什么是SPL文件和EMF文件

(一)SPL文件

如下图把标记处的复选框打钩,这样就可以在打印过程中把打印的文档保留下来。

保留的临时文件存储在⽬录 C:\Windows\System32\spool\PRINTERS下 。

每次打印保留两个⽂件分别以.SHD 和 .SPL 结尾,.SHD 为打印控制⽂件,.SPL 存储打印内容。

我们可以通过解析 SPL⽂件的⽅式来获得打印内容。


(二)EMF文件

EMF文件是一种图片格式,可以用画图软件打开。

EMF(增强元文件)是Windows操作系统用来打印缓存文件格式的术语。打印作业发送到打印机后,如果正在打印另一个文件,计算机将读取新文件并将其存储,通常存储在硬盘或存储器中,以便以后打印。


二、文件解析

(一)SPL格式

简单来说,SPL文件中封装了多个EMF文件,下图是一个SPL文件的二进制格式。


(二)打开SPL文件

可以用WinHex软件打开SPL文件读取其二进制数据(以十六进制显示),读取的数据如下图。

读取的二进制文件有几个要点需要注意:

(1)读取的数据是以双字为一个单位,即四个字节,对于十六进制来说,就是“00 00 01 00”为一个单位。

(2)读取的数据高位存储在低位位置,低位数据存储在高位位置,比如说第一个单位的数据“00 00 01 00”实际上“00 01 00 00”(反过来)。


(三)解析SPL文件

下图中标注部分是SPL头,封装了SPL文件的一些信息,包括EMF文件的位置,可以找到网上其他的一些资料,找到SPL头的具体内容。一些资料中说的SPL头的第二个单位的数据是EMF头的位置,可是对于一些文件来说,确实如此,而也有一些文件并非如此,具体原因不清楚,还需要找到SPL头的具体文档说明,才能知道。如下图中第二个单位是“00 00 00 7C”,指示的是数据第0000007C位置的数据“00 00 00 0C”正是EMF头的开始位置。

 EMF头的开始数据是“00 00 00 0C”,下一个单位是EMF文件的大小,即“00 14 0B FC”,即EMF文件正式开始的位置加上EMF文件的大小,就是EMF文件的结尾处,这里要注意的是,EMF文件是不包含EMF头的,即EMF文件正式开始的位置是下一个单位“00 00 00 01”。

EMF文件正式开始的位置“00 00 00 84”加上EMF文件的大小“00 14 0B FC”,再减1,就是EMF文件的结尾位置“00 14 0C 85”,即下图中的“00 00 00 14”处,这样就找到了一个EMF文件,从“00 00 00 01”到“00 00 00 14”,就是一个EMF文件。

 三、编程思路

我的想法比较简单,就是以字节形式遍历整个SPL文件,找到“0C 00 00 00 XX XX XX XX 01 00 00 00”,符合这个条件的一般都是EMF文件,然后从“01 00 00 00”开始,按照其中文件大小的数据,读取一整个EMF文件,然后以同样方式继续读取下一个EMF文件。

代码写的不好,比较复杂,如下:


(一)记录EMF文件的位置和大小

用两个全局变量记录EMF文件的位置和大小:

        //用一个列表记录一个SPL文件中所有EMF文件的起始位置private static List<int> _startIndexs;//用一个列表记录一个SPL文件中所有EMF文件的数据大小private static List<int> _emfDataCount;

(二)找到EMF文件的开始位置和大小

定义一个方法,用来找到EMF文件的开始位置和大小:

        /// <summary>/// 这个方法可以找到一个SPL文件中所有的EMF文件的开始位置和大小,并分别记录到两个列表中/// </summary>/// <param name="srcFilePath">需要提供SPL文件路径(包含文件名)作为参数</param>private static void FindEmf(string srcFilePath){//初始化两个用来记录EMF文件开始位置和大小的列表_startIndexs = new List<int>();_emfDataCount = new List<int>();//读取SPL文件using (FileStream fsR = new FileStream(srcFilePath, FileMode.Open, FileAccess.Read)){//设置一个20M的字节数组作为缓存区来记录读取的数据byte[] buffer = new byte[20 * 1024 * 1024];int i = fsR.Read(buffer, 0, buffer.Length);//当SPL文件超过20M时,需要读取多遍来记录数据,whileCount用来记录读取的遍数int whileCount = -1;bool flag = false;bool flagB = false;//当i=0时,说明已经读取完SPL文件while (i > 0){whileCount++;//遍历缓存区数组for (int j = 0; j < i; j++){if (!flag){if (j <= 20 * 1024 * 1024-12){if (j % 4 == 0){//找到“0C 00 00 00 XX XX XX XX 01 00 00 00”if (buffer[j] == 12 && buffer[j + 1] == 0 && buffer[j + 2] == 0 && buffer[j + 3] == 0 && buffer[j + 8] == 1 && buffer[j + 9] == 0 && buffer[j + 10] == 0 && buffer[j + 11] == 0){//记录emf起始位置_startIndexs.Add(whileCount *( 20 * 1024 * 1024) + j + 8);//记录emf大小_emfDataCount.Add((buffer[j + 7]) * 256 * 256 * 256 + (buffer[j + 6]) * 256 * 256 + (buffer[j + 5]) * 256 + (buffer[j + 4]));}}}else{//当“0C 00 00 00”在数组倒数第二个单位时,需要判断循环读取第二遍时数组第一个单位是否是“01 00 00 00”if (j == 20 * 1024 * 1024-8){if (buffer[j] == 12 && buffer[j + 1] == 0 && buffer[j + 2] == 0 && buffer[j + 3] == 0){//记录emf起始位置_startIndexs.Add(whileCount * (20 * 1024 * 1024) + j + 8);//记录emf大小_emfDataCount.Add((buffer[j + 7]) * 256 * 256 * 256 + (buffer[j + 6]) * 256 * 256 + (buffer[j + 5]) * 256 + (buffer[j + 4]));flag = true;flagB = true;}}//当“0C 00 00 00”在数组倒数第一个单位时,需要判断循环读取第二遍时数组第二个单位是否是“01 00 00 00”if (j == 20 * 1024 * 1024-4){if (buffer[j] == 12 && buffer[j + 1] == 0 && buffer[j + 2] == 0 && buffer[j + 3] == 0){//记录emf起始位置_startIndexs.Add(whileCount * (20 * 1024 * 1024) + j + 8);flag = true;}}}}//在上一次循环中,“0C 00 00 00”在数组倒数第二个单位或者倒数第一个单位时//需要判断此次循环读取数组第一个单位或者第二个单位是否是“01 00 00 00”else{flag = false;if (_startIndexs.Count == _emfDataCount.Count){if (!(buffer[j] == 1 && buffer[j + 1] == 0 && buffer[j + 2] == 0 && buffer[j + 3] == 0)){_startIndexs.RemoveAt(_startIndexs.Count - 1);_emfDataCount.RemoveAt(_emfDataCount.Count - 1);}}else{if (flagB){flagB = false;_startIndexs.RemoveAt(_startIndexs.Count - 2);_emfDataCount.RemoveAt(_emfDataCount.Count - 1);}if (!(buffer[j + 4] == 1 && buffer[j + 5] == 0 && buffer[j + 6] == 0 && buffer[j + 7] == 0)){_startIndexs.RemoveAt(_startIndexs.Count - 1);}else{_emfDataCount.Add((buffer[j + 3]) * 256 * 256 * 256 + (buffer[j + 2]) * 256 * 256 + (buffer[j + 1]) * 256 + (buffer[j]));}}}}//如果SPL文件没读完,则继续读第二遍,直到读完i = fsR.Read(buffer, 0, buffer.Length);}}}

(三)将SPL文件转换成EMF文件

代码主要部分,将SPL文件转换成EMF文件

        /// <summary>/// 将一个SPL文件转换成EMF文件,一个SPL文件中可能封装多个EMF文件/// </summary>/// <param name="srcFilePath">参数一是SPL文件路径(包含SPL文件名)</param>/// <param name="dstFilePath">参数二是EMF文件路径(不包含EMF文件名)</param>public static void SplToEmf(string srcFilePath, string dstFilePath){//找到当前SPL文件中所有EMF文件的开始位置和数据大小FindEmf(srcFilePath);//遍历记录EMF文件开始位置的列表,从而读取所有EMF文件for (int j = 0; j < _startIndexs.Count; j++){//读取SPL文件using (FileStream fsR = new FileStream(srcFilePath, FileMode.Open, FileAccess.Read)){//用20M的字节数组作为缓存区读取SPL文件byte[] buffer = new byte[20 * 1024 * 1024];//将读取到的EMF文件数据记录下来using (FileStream fsW = new FileStream(Path.Combine( dstFilePath,Path.GetFileNameWithoutExtension(srcFilePath)+"-"+ j.ToString()+".emf"), FileMode.Create, FileAccess.Write)){int i = fsR.Read(buffer, 0, buffer.Length);int startIndex = _startIndexs[j];int emfDataCount = _emfDataCount[j];int X = startIndex;//remnant记录剩余没读完的EMF数据int remnant = emfDataCount;//remnant剩余数据为0时读完一个EMF文件数据while (remnant > 0){//当EMF文件的起始位置在20M的缓存区内时,开始读取//否则循环读取SPL文件,在下一个缓存中开始找开始位置if (startIndex <= 20 * 1024 * 1024-1){if (remnant > i - X)fsW.Write(buffer, X, i - X);elsefsW.Write(buffer, X, remnant);remnant = remnant - (i - X);i = fsR.Read(buffer, 0, buffer.Length);X = 0;}else{i = fsR.Read(buffer, 0, buffer.Length);startIndex = startIndex - 20 * 1024 * 1024;X = 0;}}}}}}

 代码仅供参考。


本文由本人编写,经验缺乏,尚望各位多多指正,以匡不逮。

更多推荐

C# 如何将SPL文件转换成EMF文件

本文发布于:2024-03-08 06:10:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1720020.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何将   文件转换成   文件   SPL   EMF

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!