 |
ActiveDelphi .: O site do programador Delphi! :.
|
| Exibir mensagem anterior :: Exibir próxima mensagem |
| Autor |
Mensagem |
Nysp Novato

Registrado: Terça-Feira, 4 de Mai de 2010 Mensagens: 22
|
Enviada: Qua Abr 24, 2019 8:26 am Assunto: Como imprimir um arquivo PDF diretamente, informando a impre |
|
|
Bom dia a todos,
estou há alguns dias já pesquisando uma maneira de imprimir um arquivo em PDF no qual eu informo a impressora e o arquivo seja impresso sem ser aberto e sem ter nenhum leitor de PDF já instalado no computador (como Adobre Reader ou Foxit, por exemplo).
O grande problema é que, dentre vários exemplos testados, muitos abrem o arquivo antes. Por exemplo, aqui mesmo no forum achei essa thread ( www.activedelphi.com.br/forum/viewtopic.php?t=30397&sid=2ca143582633ad471599ca04ffdbc262 ) e ela funciona bem. Porém, em computadores com Windows 10 que tenham Adobe instalado, ele abre uma instância (vazia) do Adobe, fora que eu preciso utilizar a função de setar a impressora padrão antes e depois voltar a impressora correta do usuário, já que nem sempre a padrão é a que ele quer imprimir.
Pensei em usar o Ghostscript mas, assim como nas pesquisas que citei acima, está bem complicado encontrar uma maneira de apenas impressão. Vejo muitos artigos do Ghostscript ensinando a criar PDF, juntar vários PDF, convertê-lo para extensões de imagem, mas não acho um que apenas imprima o arquivo sem abrí-lo como quero. Pensei em usar a dll "gsdll32.dll" para meu objetivo mas não encontrei nada em exemplos.
Meu grande problema é que os clientes da minha empresa tem ambientes muito variados. Como falei, alguns sequer possui leitor de PDF instalado (usam pelo navegador) e, como já tenho o arquivo PDF no caminho que quero, gostaria apenas de imprimí-lo em impressora pré-determinada em um ini ou configuração de meu sistema sem que o usuário necessite nenhum clique adicional.
Alguém conhece uma maneira?
Me desculpa caso já haja outra thread a respeito, procurei e não encontrei especificamente o que quero.
PS: estou utilizando Delphi 10 Seattle com Fast Report (que, segundo seu suporte, não imprime PDF's não gerado pelo próprio).
Agradeço! |
|
| Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Qui Abr 25, 2019 2:20 am Assunto: |
|
|
com o uso do ghostscript fica mais ou menos assim:
| Código: | const
GS_ARG_ENCODING_LOCAL = 0;
GS_ARG_ENCODING_UTF8 = 1;
e_Quit = -990;
type
Targvs = array of pansichar;
TGSAPIrevision = packed record
product: PChar;
copyright: PChar;
revision: longint;
revisiondat: longint;
end;
PGSAPIrevision = ^TGSAPIrevision;
Pgs_main_instance = Pointer;
PPChar = array of PChar;
{ funções e procedure da dll gsdll32.dll }
function gsapi_new_instance(pinstance: Pgs_main_instance;
caller_handle: Pointer): Integer; stdcall; external 'gsdll32.dll';
function gsapi_init_with_args(pinstance: Pgs_main_instance; argc: Integer;
argv: PPChar): Integer; stdcall; external 'gsdll32.dll';
function gsapi_exit(pinstance: Pgs_main_instance): Integer; stdcall;
external 'gsdll32.dll';
procedure gsapi_delete_instance(pinstance: Pgs_main_instance); stdcall;
external 'gsdll32.dll';
function gsapi_set_arg_encoding(pinstance: Pgs_main_instance; ENCODING: Integer)
: Integer; stdcall; external 'gsdll32.dll';
procedure addArg(var argv: Targvs; value: ansistring);
begin
setlength(argv, length(argv) + 1);
argv[high(argv)] := pansichar(value);
end;
function ImprimirPdf(impressora: string; filename: string): Integer;
var
code, code1, gsargc: Integer;
gsargv: Targvs;
minst: PGSAPIrevision;
begin
addArg(gsargv, 'gs');
addArg(gsargv, '-dPrinted');
addArg(gsargv, '-dNoCancel=true');
addArg(gsargv, '-dBATCH');
addArg(gsargv, '-dNOPAUSE');
addArg(gsargv, '-dNOSAFER');
addArg(gsargv, '-dNumCopies="' + inttostr(1) + '"');
addArg(gsargv, '-sDEVICE=mswinpr2');
addArg(gsargv, '-sOutputFile=%printer%"' + impressora + '"');
addArg(gsargv, '"' + filename + '"');
gsargc := length(gsargv);
code := gsapi_new_instance(@minst, nil);
if (code < 0) then
begin
result := 1;
exit;
end;
code := gsapi_set_arg_encoding(minst, GS_ARG_ENCODING_UTF8);
if (code = 0) then
code := gsapi_init_with_args(minst, gsargc, @gsargv[0]);
code1 := gsapi_exit(minst);
if ((code = 0) or (code = e_Quit)) then
code := code1;
gsapi_delete_instance(minst);
if ((code = 0) or (code = e_Quit)) then
begin
result := 0;
exit;
end;
result := 1;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
ImprimirPdf('nome da impressora aqui', OpenDialog1.filename);
end; |
caso chame a função ImprimirPdf sem informar o nome da impressora o ghostscript vai abrir uma janela de escolha da impressora similar a esta aqui:
caso contrario vai imprimir diratamente na impressora informada.
lembrete não esqueça te de a gsdll32.dll no mesmo diretorio da aplicação ou na pasta sistem32.
não testei com impressora em rede apenas impressora local. _________________ Tudo podemos quando tudo sabemos! |
|
| Voltar ao Topo |
|
 |
Nysp Novato

Registrado: Terça-Feira, 4 de Mai de 2010 Mensagens: 22
|
Enviada: Sex Abr 26, 2019 8:30 am Assunto: |
|
|
Primeiro, quero agradecer o strak2012. Ele me ajudou demais, não só aqui no Forum, mas por Skype também. Realmente, obrigado!
Para quem se interessar, segue o que resultou pra mim. Há poucas mudanças em relação ao que o strak2012, mas há algumas considerações a se fazer. O código final foi esse:
| Código: | unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Printers;
const
GS_ARG_ENCODING_LOCAL = 0;
GS_ARG_ENCODING_UTF8 = 1;
e_Quit = -990;
type
Targvs = array of pansichar;
TGSAPIrevision = packed record
product: PChar;
copyright: PChar;
revision: longint;
revisiondat: longint;
end;
PGSAPIrevision = ^TGSAPIrevision;
Pgs_main_instance = Pointer;
PPChar = array of PChar;
TForm1 = class(TForm)
Button1: TButton;
OpenDialog1: TOpenDialog;
ComboBox1: TComboBox;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
procedure addArg(var argv: Targvs; value: ansistring);
public
{ Public declarations }
function ImprimirPdf(impressora: string; filename: string): Integer;
end;
var
Form1: TForm1;
implementation
{ funções e procedure da dll gsdll32.dll }
function gsapi_new_instance(pinstance: Pgs_main_instance;
caller_handle: Pointer): Integer; stdcall; external 'gsdll32.dll';
function gsapi_init_with_args(pinstance: Pgs_main_instance; argc: Integer;
argv: PPChar): Integer; stdcall; external 'gsdll32.dll';
function gsapi_exit(pinstance: Pgs_main_instance): Integer; stdcall;
external 'gsdll32.dll';
procedure gsapi_delete_instance(pinstance: Pgs_main_instance); stdcall;
external 'gsdll32.dll';
function gsapi_set_arg_encoding(pinstance: Pgs_main_instance; ENCODING: Integer)
: Integer; stdcall; external 'gsdll32.dll';
{$R *.dfm}
{ TForm1 }
procedure TForm1.addArg(var argv: Targvs; value: ansistring);
begin
setlength(argv, length(argv) + 1);
argv[high(argv)] := pansichar(value);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
ImprimirPdf(ComboBox1.Text, OpenDialog1.filename);
end;
procedure TForm1.FormShow(Sender: TObject);
var
i: Integer;
vPrinter: TPrinter;
begin
ComboBox1.Items.Clear;
vPrinter := TPrinter.Create;
for i := 0 to vPrinter.Printers.Count - 1 do
ComboBox1.Items.Add(vPrinter.Printers.Strings[i]);
FreeAndNil(vPrinter);
end;
function TForm1.ImprimirPdf(impressora, filename: string): Integer;
var
code, code1, gsargc: Integer;
gsargv: Targvs;
minst: PGSAPIrevision;
begin
addArg(gsargv, 'gs');
addArg(gsargv, '-dPrinted');
addArg(gsargv, '-dNoCancel=true');
addArg(gsargv, '-dBATCH');
addArg(gsargv, '-dNOPAUSE');
addArg(gsargv, '-dNOSAFER');
addArg(gsargv, '-dNumCopies="' + inttostr(1) + '"');
addArg(gsargv, '-sDEVICE=mswinpr2');
//addArg(gsargv, '-sOutputFile=%printer%"' + impressora + '"');
addArg(gsargv, '-sOutputFile="\\spool\' + impressora + '"');
addArg(gsargv, '"' + filename + '"');
gsargc := length(gsargv);
code := gsapi_new_instance(@minst, nil);
if (code < 0) then
begin
result := 1;
exit;
end;
code := gsapi_set_arg_encoding(minst, GS_ARG_ENCODING_UTF8);
if (code = 0) then
code := gsapi_init_with_args(minst, gsargc, @gsargv[0]);
code1 := gsapi_exit(minst);
if ((code = 0) or (code = e_Quit)) then
code := code1;
gsapi_delete_instance(minst);
if ((code = 0) or (code = e_Quit)) then
begin
result := 0;
exit;
end;
result := 1;
end;
end. |
Importante dizer que, para testar esse exemplo enviando o nome de uma impressora específica, deve-se gerar versão Release e testar diretamente do executável. Usando versões com debug, ao passar pela seguinte linha, aponta um access violation:
| Código: | | code := gsapi_new_instance(@minst, nil); |
Usando diretamente pelo executável e com versão Release, não acontece.
A versão da gsdll32.dll que usei foi a 0.0.9.27. Segundo o strak2012, com ele também funcionou na 0.0.9.23.
Outra alternativa que testamos também foi sem usar o Ghostscript, porém ela requer sempre algum PDf reader na máquina (como Adobe Reader, Foxbit etc). Para quem abre o PDF pelo navegador, ela já não funciona. Estou postando o código caso seja interesse de alguém usar assim, mesmo com a ressalva. A vantagem dela é usar componentes nativos e não necessitar de DLL extra para o funcionamento:
| Código: | procedure TForm1.printFile(AFile: TFileName; APrinter: string);
var
Device: array[0..255] of Char;
Driver: array[0..255] of Char;
Port: array[0..255] of Char;
S: string;
hDeviceMode: THandle;
i: Integer;
vPrinter : TPrinter;
begin
Printer.PrinterIndex := -1;
for i := 0 to Printer.Printers.Count - 1 do
begin
if Printer.printers[i] = APrinter then
begin
vPrinter := TPrinter.Create;
vPrinter.PrinterIndex := i;
vPrinter.GetPrinter(Device,Driver,Port,hDeviceMode);
S := Format('"%s" "%s" "%s"',[Device,Driver,Port]);
ShellExecute(Application.Handle,'printto',PChar(AFile),PChar(S),nil,SW_HIDE);
vPrinter.Free;
end;
end;
end; |
Sobre essa função, é bom observar que o parâmetro enviado para o ShellExecute é 'printto'. Usando somente 'print', pelo menos no meu caso, sempre saía na impressora padrão.
Estou usando Delphi 10 Seattle em um Windows 10 64 bits. Não sei o comportamento em outras plataformas.
Agradeço ao strak2012 novamente!
Abraços |
|
| Voltar ao Topo |
|
 |
|
|
Enviar Mensagens Novas: Proibido. Responder Tópicos Proibido Editar Mensagens: Proibido. Excluir Mensagens: Proibido. Votar em Enquetes: Proibido.
|
|