I am aiming to convert a PDF to JPEG, so I can show it in an image viewer that is embedded in my Delphi program. Here is the code for my function:
function TAnexo.loadFilePdf(AFile:String): Boolean;
Var FPicture:TPDFImage;
FStream: TMemoryStream;
PdfExist: Boolean;
jpeg: TJPEGImage;
begin
result := false;
PdfExist := fileExists(AFile);
if PdfExist then
begin
fResultFileNameBmp := AFile + '.jpg';
FPicture:=TPDFImage.Create;
Try
//set resolution and page before load so the first requested page is loaded
FPicture.Resolution:=300;
FPicture.PixelFormat := pf24bit;
FPicture.CurrentPage:=1;
FPicture.LoadFromFile(AFile);
jpeg := TJPEGImage.Create;
try
jpeg.CompressionQuality := 100;
jpeg.PixelFormat := jf24Bit;
jpeg.Scale := jsFullSize;
jpeg.Performance := jpBestQuality;
jpeg.GrayScale := False; {Apenas tons de cinza}
jpeg.ProgressiveDisplay := False; {Display Progressivo}
jpeg.Assign(FPicture);
jpeg.SaveToFile(fResultFileNameBmp);
finally
jpeg.Free;
end;
self.loadFileToBinary(fResultFileNameBmp);
finally
FPicture.Free;
DeleteFile(fResultFileNameBmp);
DeleteFile(AFile);
end;
end;
end;
But when the function reaches the line "FPicture.LoadFromFile(AFile);", it shows a screen requesting that I choose between the available printers to print the PDF and, no matter what I choose, the rest of the function will not execute.
printer screen
What could be the solution? My intention is not to print the PDF, but only to make de PDF-JPEG conversion behind the scenes so I can visualize it in the image viewer whenever I would like.
Edit: Aparently there's another line responsible for making the printer dialog show up in my program. I have an instance of TChromium calling the PrintToPdf() function before my custom function executes, but I still don't know how to make my instance of TChromium save the PDF without bringing up the printer dialog. Here's the code where it executes:
procedure TfrmDarfOnline.actConfirmarExecute(Sender: TObject);
begin
Self.fDarfAvulso.FilePdf := ArquivoPDF{my PDF file's path};
Self.fDarfAvulso.Chrome.PrintToPDF(Self.fDarfAvulso.FilePdf,'DARF',Self.Chrome.Browser.MainFrame.GetURL);
sleep(2000);
Chrome.ClearCache;
Chrome.DeleteCookies('http://www31.receita.fazenda.gov.br');
inherited;
ModalResult := mrOk;
end;
I am a beginner in Delphi (I use Delphi 2010 because of school) and I am trying to get an output textfile with a list of pastes that a pastebin user has created, but I am not exactly sure how to do it. On Pastebin.com (PastebinAPI), they explain how the API works, but I can't get it working on Delphi.
Here is what I have coded so far (I blurred out my details):
procedure TfrmLogin.imgLoginButtonClick(Sender: TObject);
var
sSource, sAPI_Dev_Key, sAPI_User_Key, sAPI_Results_Limit, sAPI_Option,
sListPasteLink: String;
begin
sSource := 'https://pastebin.com/api/api_post.php/';
sAPI_Dev_Key := 'xxxxxxxxxxxxxxxxxxxxxxxx/';
sAPI_User_Key := 'xxxxxxxxxxxxxxxxxxxxxxx/';
sAPI_Results_Limit := '1000/';
sAPI_Option := 'list';
sListPasteLink := sSource + sAPI_Dev_Key + sAPI_User_Key +
sAPI_Results_Limit + sAPI_Option;
end;
I am not sure what to do after this, how do I POST this generated link in Delphi to get the list of pastes created?
I tried copying the generated link and pasting it in my web browser, but Pastebin says This page has been removed!
Any help would be appreciated, thank you
Here is an example. Drop a TButton, a TMemo, a TIdHTTP and a TIdSSLIOHandlerSocketOpenSSL on a form. You will also need to copy libeay32.dll and ssleay32.dll into your application directory (they are provided somehere in the directory where Delphi was installed).
procedure TForm1.Button1Click(Sender: TObject);
var
Params: TStringList;
begin
Params := TStringList.Create;
Params.Add('api_dev_key=*****');
Params.Add('api_user_key=*****');
Params.Add('api_option=list');
try
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2];
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
Memo1.Text := IdHTTP1.Post('https://pastebin.com/api/api_post.php', Params);
finally
Params.Free;
end;
end;
I'm using Gnostice PDF Toolkit v5.0.0.457, and it works fine to operate with PDF files (merge files, split files, insert blank pages, insert text watermarks, insert image watermarks, print files, ...).
But I always have big memory leaks that prevent me to use it on the server side.
Am I doing something wrong in this code (it simply adds a text watermark to a PDF file) ? :
implementation
{$R *.dfm}
uses gtCstPDFDoc, gtPDFDoc;
procedure TTestForm.btnTestWatermarkClick(Sender: TObject);
var PDFDoc: TgtPDFDocument;
txtWatermark: TgtTextWatermarkTemplate;
begin
PDFDoc := TgtPDFDocument.Create(nil);
txtWatermark := TgtTextWatermarkTemplate.Create;
try
PDFDoc.LoadFromFile('C:\Temp\Test.pdf');
txtWatermark.FontEncoding := feWinAnsiEncoding ;
txtWatermark.Text := 'Hello World';
txtWatermark.Font.Name := 'Arial';
txtWatermark.Font.Size := 12;
txtWatermark.Font.Color := clBlack;
txtWatermark.X := 150;
txtWatermark.Y := 150;
txtWatermark.HorizPos := hpCustom;
txtWatermark.VertPos := vpCustom;
txtWatermark.Overlay := True;
PDFDoc.InsertWatermark(txtWatermark, '1');
PDFDoc.SaveToFile('C:\Temp\TestOutput.pdf');
finally
PDFDoc.Reset;
PDFDoc.Free;
txtWatermark.Free;
end;
end;
This simple example already generates important memory leaks.
PS: I know that the best place to get support is the manufacturer itself, but my subscription ended a year ago.
Thank you
Update: We have re-subscribed with Gnostice, and the current version has the memory leaks solved. Thanks to all.
With many thanks to f.i. TLama I could set up a workaround for opening a file, replacing some fields and store the result to pdf using Delphi 2007. I have a document opened in OpenOffice like this:
FileParams := VarArrayCreate([0, 0], varVariant);
FileProperty := StarOffice.Bridge_GetStruct ('com.sun.star.beans.PropertyValue');
FileProperty.Name := 'Hidden';
FileProperty.Value := true;
FileParams[0] := FileProperty;
StarDocument := StarDesktop.LoadComponentFromURL(AFileURL, '_blank', 0, FileParams);
Where AFileURL is the full pathname starting with 'file:///'
Later I replace the fields in this document with the option I discovered elsewhere on this site:
FileReplace := StarDocument.CreateReplaceDescriptor;
FileReplace.SearchCaseSensitive := False;
FileReplace.SetSearchString(zoekstring);
FileReplace.SetReplaceString(vervang);
StarDocument.ReplaceAll(FileReplace);
And then store the document to pdf.
Actually the file is a doc-file simply copied to a file with extension odt.
Everything is working fine if I first load the document in OpenOffice and save as Openoffice odt-document, but I want to do that programmaticly.
So, before being able to replace the WORD-fields (like «11») I want to store the odt-file as a proper OpenOffice document, because like this Open Office does not recognize the fields to replace.
I tried:
if StarDocument.hasLocation then
try
StarDocument.Store();
except
showmessage('unable to save');
end;
Reading OpenOffice documentation gave me the idea that this might work, but it does not.
I also tried:
function CreateProperty(const AName: AnsiString; AValue: Variant): Variant;
begin
Result := StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
Result.Name := AName;
Result.Value := AValue;
end;
FilterParams := VarArrayCreate([0, 0], varVariant);
FilterParams[0] := CreateProperty('FilterName', 'Text');
StarDocument.StoreAsURL(AFileURL,FilterParams);
Does not work either. I get a Fatal Error from Open Office. Who knows what I am missing?
Assuming I have the Delphi IDE open, how can I open a .pas file selected in another app and open it in the Delphi IDE, as well as positioning it to a specific line number?
I've seen some editing tools do this.
I'm not sure if it's just an option to a normal file open (eg., using default file association), or a command-line option, or you need DDE or COM or something entirely different.
Note that I don't want to close the project and reopen a new or fake project.
Also, I don't want the file added to the project. I just want to open it.
For example, When you <ctrl>-click on a varible or type, the IDE will open the file containing that symbol and go to the line where that symbol is declared. That's all I want to do -- but from an external app. (I'm not looking for a symbol, just a line.)
I'm using Delphi XE5 at the moment, so I'm interested in newer Delphi versions, not pre-XE2 or so.
(Part of the question is, how do I ensure that if the IDE is already open, the the file is opened in anew tab inside of the current IDE rather than in another instance of the IDE?)
The code below (for D7) shows how this can be done by way of an IDE add-in .Dpk compiled
into a Bpl. It started as just a "proof of concept", but it does actually work.
It comprises a "sender" application which uses WM_COPYDATA to send the FileName, LineNo & Column to a receiver hosted in the .Bpl file.
The sender sends the receiver a string like
Filename=d:\aaad7\ota\dskfilesu.pas
Line=8
Col=12
Comment=(* some comment or other*)
The Comment line is optional.
In the .Bpl, the receiver uses OTA services to open the requested file and positions the editor caret, then inserts the comment, if any.
The trickiest thing was to find out how to handle one particular complication, the case where the named file to be opened is one with an associated form. If so, in D7 (and, I assume, other IDE versions with the floating designer option enabled) when the IDE
opens the .Pas file, it also opens the .Dfm, and left to its own devices, that would leave the form editor in front of the code editor. Calling the IOTASourceEditor.Show for the .Pas file at least puts the IDE code editor in front of the .Dfm form, but that didn't satisfy me, because by now my curiosity was piqued - how do you get a form the IDE is displaying off the screen?
I spent a lot of time exploring various blind alleys, because the OTA + NTA services don't seem to provide any way to explicitly close an IOTAEditor or any of its descendants. In the end it turned out that the thing to do is simply get a reference to the form and just send it a WM_CLOSE(!) - see comments in the code.
Fwiw, being a novice at OTA, at first (before I found out how IOTAModules work) I found that far and away the most difficult part of this was discovering how to get hold of the IEditView interface needed to set the editor caret position, but as usual with these interfacey things, once you get the "magic spell" exactly right, it all works.
Good luck! And thanks for the fascinating challenge!
unit Receiveru;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ToolsAPI;
type
TOTAEditPosnForm = class(TForm)
Memo1: TMemo;
private
FEdLine: Integer;
FEdCol: Integer;
FEditorFileName: String;
FEditorInsert: String;
procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA;
procedure HandleCopyDataString(CopyDataStruct : PCopyDataStruct);
procedure OpenInIDEEditor;
property EditorFileName : String read FEditorFileName write FEditorFileName;
property EdLine : Integer read FEdLine write FEdLine;
property EdCol : Integer read FEdCol write FEdCol;
property EditorInsert : String read FEditorInsert write FEditorInsert;
end;
var
OTAEditPosnForm: TOTAEditPosnForm;
procedure Register;
implementation
{$R *.dfm}
procedure MonitorFiles;
begin
OTAEditPosnForm := TOTAEditPosnForm.Create(Nil);
OTAEditPosnForm.Show;
end;
procedure Register;
begin
MonitorFiles;
end;
procedure TOTAEditPosnForm.OpenInIDEEditor;
var
IServices : IOTAServices;
IActionServices : IOTAActionServices;
IModuleServices : IOTAModuleServices;
IEditorServices : IOTAEditorServices60;
IModule : IOTAModule;
i : Integer;
IEditor : IOTAEditor;
ISourceEditor : IOTASourceEditor;
IFormEditor : IOTAFormEditor;
IComponent : IOTAComponent;
INTAComp : INTAComponent;
AForm : TForm;
IEditView : IOTAEditView;
CursorPos : TOTAEditPos;
IEditWriter : IOTAEditWriter;
CharPos : TOTACharPos;
InsertPos : Longint;
FileName : String;
begin
IServices := BorlandIDEServices as IOTAServices;
Assert(Assigned(IServices), 'IOTAServices not available');
IServices.QueryInterface(IOTAACtionServices, IActionServices);
if IActionServices <> Nil then begin
IServices.QueryInterface(IOTAModuleServices, IModuleServices);
Assert(IModuleServices <> Nil);
// Close all files open in the IDE
IModuleServices.CloseAll;
if IActionServices.OpenFile(EditorFileName) then begin
// At this point, if the named file has an associated .DFM and
// we stopped here, the form designer would be in front of the
// code editor.
IModule := IModuleServices.Modules[0];
// IModule is the one holding our .Pas file and its .Dfm, if any
// So, iterate the IModule's editors until we find the one
// for the .Pas file and then call .Show on it. This will
// bring the code editor in front of the form editor.
ISourceEditor := Nil;
for i := 0 to IModule.ModuleFileCount - 1 do begin
IEditor := IModule.ModuleFileEditors[i];
FileName := IEditor.FileName;
Memo1.Lines.Add(Format('%d %s', [i, FileName]));
if CompareText(ExtractFileExt(IEditor.FileName), '.Pas') = 0 then begin
if ISourceEditor = Nil then begin
IEditor.QueryInterface(IOTASourceEditor, ISourceEditor);
IEditor.Show;
end
end
else begin
// Maybe the editor is a Form Editor. If it is
// close the form (the counterpart to the .Pas, that is}
IEditor.QueryInterface(IOTAFormEditor, IFormEditor);
if IFormEditor <> Nil then begin
IComponent := IFormEditor.GetRootComponent;
IComponent.QueryInterface(INTAComponent, INTAComp);
AForm := TForm(INTAComp.GetComponent);
//AForm.Close; < this does NOT close the on-screen form
// IActionServices.CloseFile(IEditor.FileName); <- neither does this
SendMessage(AForm.Handle, WM_Close, 0, 0); // But this does !
end;
end;
end;
// Next, place the editor caret where we want it ...
IServices.QueryInterface(IOTAEditorServices, IEditorServices);
Assert(IEditorServices <> Nil);
IEditView := IEditorServices.TopView;
Assert(IEditView <> Nil);
CursorPos.Line := edLine;
CursorPos.Col := edCol;
IEditView.SetCursorPos(CursorPos);
// and scroll the IEditView to the caret
IEditView.MoveViewToCursor;
// Finally, insert the comment, if any
if EditorInsert <> '' then begin
Assert(ISourceEditor <> Nil);
IEditView.ConvertPos(True, CursorPos, CharPos);
InsertPos := IEditView.CharPosToPos(CharPos);
IEditWriter := ISourceEditor.CreateUndoableWriter;
Assert(IEditWriter <> Nil, 'IEditWriter');
IEditWriter.CopyTo(InsertPos);
IEditWriter.Insert(PChar(EditorInsert));
IEditWriter := Nil;
end;
end;
end;
end;
procedure TOTAEditPosnForm.HandleCopyDataString(
CopyDataStruct: PCopyDataStruct);
begin
Memo1.Lines.Text := PChar(CopyDataStruct.lpData);
EditorFileName := Memo1.Lines.Values['FileName'];
edLine := StrToInt(Memo1.Lines.Values['Line']);
edCol := StrToInt(Memo1.Lines.Values['Col']);
EditorInsert := Trim(Memo1.Lines.Values['Comment']);
if EditorFileName <> '' then
OpenInIDEEditor;
end;
procedure TOTAEditPosnForm.WMCopyData(var Msg: TWMCopyData);
begin
HandleCopyDataString(Msg.CopyDataStruct);
msg.Result := Length(Memo1.Lines.Text);
end;
initialization
finalization
if Assigned(OTAEditPosnForm) then begin
OTAEditPosnForm.Close;
FreeAndNil(OTAEditPosnForm);
end;
end.
Code for sender:
procedure TSenderMainForm.btnSendClick(Sender: TObject);
begin
SendMemo;
end;
procedure TSenderMainForm.SendData(
CopyDataStruct: TCopyDataStruct);
var
HReceiver : THandle;
Res : integer;
begin
HReceiver := FindWindow(PChar('TOTAEditPosnForm'),PChar('OTAEditPosnForm'));
if HReceiver = 0 then begin
Caption := 'CopyData Receiver NOT found!';
end
else begin
Res := SendMessage(HReceiver, WM_COPYDATA, Integer(Handle), Integer(#CopyDataStruct));
if Res > 0 then
Caption := Format('Received %d characters', [Res]);
end;
end;
procedure TSenderMainForm.SendMemo;
var
MS : TMemoryStream;
CopyDataStruct : TCopyDataStruct;
S : String;
begin
MS := TMemoryStream.Create;
try
S := Memo1.Lines.Text + #0;
MS.Write(S[1], Length(S));
CopyDataStruct.dwData := 1;
CopyDataStruct.cbData := MS.Size;
CopyDataStruct.lpData := MS.Memory;
SendData(CopyDataStruct);
finally
MS.Free;
end;
end;