虚拟打印的实现-SPL转换成EMF

简介:
上次写到如何编写一个虚拟打印机的驱动部分。系统在打印一个任务时是先将这个任务生成为一个SPL文件,然后才发送给打印机。我们可以使用上次写的DLL程序,将系统生成SPL文件,在还没有发送给打印机的时候,将这个SPL文件转换成一个EMF文件。一旦生成了EMF文件以后,我们就可以随意的将它转换成任意的格式。下面的代码的功能就是将一个SPL文件转换成一个EMF文件。
 
function SPLToEMF(): Boolean;stdcall;export;//SPL类型转换为EMF文件
var
  reg       : TRegistry;
  SearchRes : TSearchRec;// 查找文件的结构
  nGaugeCounter,         // makes nice gauge
  nFound, i : Integer;   // # of files found (when searching)
  strTemp : string[8];   // filename: <number>.emf
  strCnt : string;       // <full path> + <emf-file>
  strSpoolDir : string;  // spool-directory (NT only)
  strOldFile, strNewFile : string; // filename (NT: spool file)
  m_strTempVar : string; // registry entry holding destination dir for print jobs
  strDestDir : string;   // 保存EMF文件的路径
  strSHDFile : string;   // instruction file
  lpszTempDir : PChar;   // %TEMP%的路径名称(仅用于95 or NT)%TEMP% dir (w95 & nt)
  lpszSpoolDir : PChar;  // 打印处理器的路径名称(仅用于NT or 2K)spool dir (nt only)
  IsEnd:Boolean;
  label Res;             // 定义返回的goto变量
 
begin
  IsEnd:=false;
  nGaugeCounter := 0;
  //初始化lpszTempDirlpszSpoolDir
  GetMem(lpszTempDir, 255);
  GetMem(lpszSpoolDir, 255);
  if (GetEnvironmentVariable('temp', lpszTempDir, 255) = 0) then
  begin
    MsgError('Environment Variable %temp% not set!' + #13 +
               'Either install driver properly or' + #13 + 'define a %temp% environment variable.');
    FreeMem(lpszTempDir);
    goto Res;
  end;
  strTempDir := string(lpszTempDir);
  FreeMem(lpszTempDir);
  //从注册表中得到EMF文件的目的路径
  reg:=TRegistry.Create;
  reg.RootKey:=HKEY_LOCAL_MACHINE;
  if reg.OpenKey(PMON_KEY,TRUE) then
  begin
    m_strTempVar := reg.ReadString('Temp');
  end;
  reg.CloseKey;
  reg.Free;
  if (m_strTempVar = '') then
  begin
    strTempDir:='C:\TEMP';
    MsgError('您的打印目的没有选择,文件将保存在C:\TEMP');
  end
  else
  begin
    strTempDir := m_strTempVar;
  end;
  if (strTempDir[Length(strTempDir)] <> '\') then
  begin
    strTempDir := Concat(strTempDir, '\');
  end;
  nFileCounter := 1;
  //得到系统版本
  strOSVer := GetOSName;
  //根据版本处理
  {对于NT 和其高版本的操作系统}
  if (strOSVer = 'Windows NT') or (strOSVer = 'Windows 2000') or (strOSVer = 'Windows XP') then
  begin
    //得到spool的路径
    GetEnvironmentVariable('windir', lpszSpoolDir, 255);
    strSpoolDir := string(lpszSpoolDir) + '\system32\spool\PRINTERS\';
    FreeMem(lpszSpoolDir);
  end;
  //在临时文件夹中删除旧的emf文件和spl文件
  nFound := FindFirst(strTempDir + '*.emf', faAnyFile, SearchRes);
  while nFound = 0 do
  begin
    DeleteFile(PChar(strTempDir + SearchRes.Name));
    nFound := FindNext(SearchRes);
  end;
  FindClose(SearchRes);
  {对于NT以下的操作系统}
  if (strOSVer = 'Windows 95') or (strOSVer = 'Windows98') or (strOSVer = 'Windows 98SE') or (strOSVer = 'Windows ME') then
  begin
    MsgError('此虚拟打印暂时不支持低版本系统。');
  end
  else
  begin
    StringList := TStringList.Create;
    //在打印机的临时文件夹中查找临时文件
    nFound := FindFirst(strSpoolDir + '*.SPL', faAnyFile, SearchRes);
    while nFound = 0 do
    begin
      Inc(nGaugeCounter);
      nFound := FindNext(SearchRes);
    end;
    FindClose(SearchRes);
    nFileCounter := 0;
    nFound := FindFirst(strSpoolDir+ '*.SPL', faAnyFile, SearchRes);
    if nFound = 0 then
    begin
      {$I-}
      DateSeparator := '-';
      TimeSeparator := '-';
      //重新编写EMF的目的路径
      strDestDir := strTempDir;
      //创建文件夹
      if IOResult <> 0 then
      begin
        raise Exception.Create('不能创建文件夹 ' + strDestDir + ': ' + IntToStr(IOResult))
      end;
    end;
    while nFound = 0 do
    begin
      strOldFile := strSpoolDir + SearchRes.Name;
      strSHDFile := StringReplace(strOldFile, '.SPL', '.SHD', [rfIgnoreCase]);
      strNewFile := strDestDir + '\' + SearchRes.Name;
      StringList.Add(strNewFile);
      if not FileExists(strOldFile) then
      begin
        raise Exception.Create('SPOOL文件没有找到: ' + strOldFile)
      end
      else
      begin
        if not CopyFile(PChar(strOldFile), PChar(strNewFile), False) then
        begin
          raise Exception.Create('不能拷贝文件: ' + strOldFile);
        end;
      end;
      nFound := FindNext(SearchRes);
      Inc(nFileCounter);
      strCnt := '';
      strTemp := '';
    end;
    FindClose(SearchRes);
    for i:=0 to nFileCounter-1 do
    begin
      ReadBinaryDataFile(StringList.Strings[i], strDestDir + '\');
    end;
  end;
  nFound := FindFirst(strSpoolDir + '*.spl', faAnyFile, SearchRes);
  while nFound = 0 do
  begin
    DeleteFile(PChar(strSpoolDir + SearchRes.Name));
    nFound := FindNext(SearchRes);
  end;
  FindClose(SearchRes);
 
  nFound := FindFirst(strSpoolDir + '*.shd', faAnyFile, SearchRes);
  while nFound = 0 do
  begin
    DeleteFile(PChar(strSpoolDir + SearchRes.Name));
    nFound := FindNext(SearchRes);
  end;
  FindClose(SearchRes);
  IsEnd:=true;
Res:
  Result:=IsEnd;
end;
 
 
 
上面的函数中使用到的一些结构EMFheader结构如下定义
type EMFheader = record
         Signature: Integer;
         EMFsize: Integer;
       end;
  const EMFheaderSignature = $0C;
 
使用到的ReadBinaryDataFile函数如下实现。
 
//读出一个NT下的 *.spl文件并将其转换为一个*.EMF文件
//参数说明 strFilename:*.spl文件的文件名称 strDestDir需要转换成为*.emf文件的文件明成
procedure ReadBinaryDataFile(strFilename : string; strDestDir : string);
var
  fFromF, fToF           : file;  //定义输入和输出文件
  strEMFFileName, strTmp : string;
  nRead, nWritten, i, nReadTotal, nNextFilePos : Integer;
  Buf                    : array[1..2048] of Char; //定义一个读取EMF文件的buffer
  nPixFound, test        : Integer;
  PosList                : TStringList;
  strHeaderBytes         : string; //从函数fDetectHeaderBytes读出的6字节长的emf文件头
begin
  if not FileExists(strFileName) then
  begin
    raise Exception.Create('不能读文件: ' + strFileName)
  end
  else
  begin
    strHeaderBytes := fDetectHeaderBytes(strFileName);
    AssignFile(fFromF, strFileName);
  end;
  Reset(fFromF, 1);
  PosList := TStringList.Create;
  nPixFound := 0;
  nReadTotal := 0;
  repeat
    //注意strHeaderBytes的含义
    BlockRead(fFromF, Buf, SizeOf(Buf), nRead);
    test := Pos(strHeaderBytes, Buf);
    if (test > 0) then
    begin
      Inc(nPixFound);
      if test<>0 then PosList.Add(IntToStr(test + nReadTotal));
    end;
    Inc(nReadTotal, nRead);
  until (nRead = 0) ;
  for i:=1 to nPixFound do
  begin
    strTmp := IntToStr(i);
    while Length(strTmp)< 8 do
    begin
      Insert('0', strTmp, 1);
    end;
    strEMFFileName := Concat(strDestDir, strTmp,'.EMF');
    AssignFile(fToF, strEMFFileName);
    Rewrite(fToF, 1);
    try
      Seek(fFromf, StrToInt(PosList.Strings[i-1])-1);
      repeat
        BlockRead(fFromF, Buf, SizeOf(Buf), nRead);
        BlockWrite(fToF, Buf, nRead, nWritten);
        if i<nPixFound then
          nNextFilePos := StrToInt(PosList.Strings[i])
        else
          nNextFilePos := FileSize(fFromF);
      until (FilePos(fFromF)>=nNextFilePos);
    except
      on EInOutError do MsgError('读文件错误');
    end;
    CloseFile(fToF);
  end;
  CloseFile(fFromF);
  PosList.Free;
  DeleteFile(strFilename);
end;
 
上面的代码希望对大家有所帮助,下次我将会把我的代码中如何将一个EMF文件转换成一个BMP文件贴出。
本文转自狗窝博客51CTO博客,原文链接http://blog.51cto.com/fxh7622/48833如需转载请自行联系原作者

fxh7622
相关文章
|
9月前
|
存储 C语言 索引
ENVI IDL:熟悉IDL语法+输出多幅TIFF影像的MAX文件和MEAN文件
ENVI IDL:熟悉IDL语法+输出多幅TIFF影像的MAX文件和MEAN文件
202 0
|
9月前
ENVI_IDL:(批量处理)如何对HDF5文件进行GLT文件的创建并进行几何校正最终输出为IMG格式?
ENVI_IDL:(批量处理)如何对HDF5文件进行GLT文件的创建并进行几何校正最终输出为IMG格式?
99 0
|
9月前
|
C语言 Python
ENVI_IDL基础:常用数据类型_创建数组_类型转换_print输出_基本运算_关系运算
ENVI_IDL基础:常用数据类型_创建数组_类型转换_print输出_基本运算_关系运算
304 0
|
9月前
|
存储 编解码 Python
ENVI_IDL:对于书写和创建GEOTIFF结构体?
ENVI_IDL:对于书写和创建GEOTIFF结构体?
73 0
|
9月前
成信大ENVI_IDL第一周实验测试:数组的简单运算+详细解析
成信大ENVI_IDL第一周实验测试:数组的简单运算+详细解析
51 0
fastq文件转换成fasta文件
fastq文件转换成fasta文件
215 0
|
存储
LyScript 计算片段Hash并写出Excel
本案例将学习运用LyScript计算特定程序中特定某些片段的Hash特征值,并通过xlsxwriter这个第三方模块将计算到的hash值存储成一个excel表格,本例中的知识点可以说已经具备了简单的表格输出能力,如果时间充裕完全可以实现自动化报告生成。
177 0
LyScript 计算片段Hash并写出Excel
如何将wrf文件转换成wmv格式
如何将wrf文件转换成wmv格式
113 0
如何将wrf文件转换成wmv格式
|
Serverless 文件存储 容器
开发函数计算的正确姿势——借助 LibreOffice 将 Word 转换成 PDF
前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute):函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。
3629 0
|
Serverless Shell 容器
开发函数计算的正确姿势——借助 Ghostscript 将 PDF 转换成 JPG
前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute):函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。
2478 0