开发者社区> 科技探索者> 正文

虚拟打印的实现-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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
29209 0
JAVA虚拟机类型转换学习
  Java虚拟机包括血多进行基本类型转换工作的操作码,这些执行转换工作的操作码后面没有操作数,转换的值从栈顶端获得。Java虚拟机从栈顶端弹出一个值,对它进行转换,然后再把转换结果压入栈。进行int、long、float和double类型之间转换的操作码。
657 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20725 0
DEDECMS自定义表单unix时间戳转换成常规时间方法及增加表单添加时间方法
  DEDECMS自定义表单提交的时间给转换成unix时间戳(一段数字),我们管理员在后台需要看到是日期,而不是那一行数字,下面方法可以解决这个问题,dedecms 5.6和5.7都可以,打开dede/templets/diy_list.
912 0
java8中的时间处理7 - 向前兼容(新老类转换)
我们不太可能使用jdk8以后就把原来的代码都改成新api。所以新旧日期类会共存一段时间。 这篇提供他们之间的转换。 public static void main(String[] args) { //Date 转 Instant Instant timestamp = new Date().
1196 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23589 0
5488
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载