Новичок
Профиль
Группа: Участник
Сообщений: 9
Регистрация: 8.11.2011
Репутация: 3 Всего: 3
|
На одном из дружественных форумов наткнулся на программу-обёртку от Кроик Семёна для чтения из Delphi многостраничных документов в формате PDF. Построено на базе известной pdf.dll от Crome. Кое-что переделал-упростил в этой весьма полезной оболочке, так что получился самостоятельный pas-модуль для работы с pdf + небольшая демо-программка для сохранения прочитанного файла в Tiff, Jpeg или BMP. Текст этого вспомогательного модуля приведён ниже, хотя он есть и в составе проекта - по ссылке для скачивания. Весь Delphi-проект прилагаю : PDF2TIFF . Там необходимая DLL тоже внутри имеется. Тестировал под Win10 64bit. Собирал в Tokyo 10.2.2, но указанная DLL нормально подключится только при компиляции под 32bit . Надеюсь, кому-то будет полезно при работе с файлами *.pdf. Код | // Delphi wrapper for Google Chrome's "pdf.dll" // with GetPDFPageSizeByIndex // Based on Simon Kroik, 06.2013-03.2018 >> Version 2.0 << // Tested with Delphi Tokyo 10.2.2, 32bit unit MyChromePDFRender;
interface uses Windows, Classes, Graphics, Types, SysUtils, UITypes, Dialogs;
type TMyChromePDFRender = class(TPersistent) // Private Declarations private FBuffer : PChar; FBufferSize : Int64; FPagesCount : Integer; FMaxPageWidthCm : Single; FFullFileName : string; LoadedDLL: Boolean; procedure RaiseIfPageNumberWrong(APageNumber: Integer); procedure Clear; function RenderPDFToDC(ADC: HDC; ARectLeft, ARectTop, ARectWidth, ARectHeight, APageNumber, ADpiX, ADpiY: Integer; ADoFitToBounds, ADoStretchToBounds, ADoKeepAspectRatio, ADoCenterInBounds, ADoAutoRotate: Boolean): Boolean; function LoadPDFFromStream(AStream: TStream; ALength: Int64 =0 ): Boolean; // Public Declarations public constructor Create; destructor Destroy; override; function LoadPDFFromFile(const APDFFile: TFileName): Boolean; function GetPageSizeInPixel(APageNumber, ADpiX, ADpiY: Integer; var AWidth, AHeight: Integer): Boolean; function RenderPDFToBitmap( ABitmap: Graphics.TBitmap; APageNumber, ADpiX, ADpiY: Integer; ADoAutoRotate, ADoCenterInBounds, ADoAutoSizeBitmap: Boolean): Boolean; property MaxPageWidthCm: Single read FMaxPageWidthCm; property FullFileName: string read FFullFileName; property PagesCount: Integer read FPagesCount; property SizeInBytes: int64 read FBufferSize; end; //===================================================================== implementation
const LibName = 'pdf.dll';
var GetPDFDocInfo : procedure( pdf_buffer : PChar; buffer_size : Integer; page_count : PInt; max_page_width : PDouble); cdecl;
GetPDFPageSizeByIndex : function( pdf_buffer : PChar; buffer_size : Integer; page_number : Integer; width : PDouble; height : PDouble): Boolean; cdecl;
RenderPDFPageToDC : function( pdf_buffer : PChar; buffer_size : Integer; page_number : Integer; dc : HDC; dpi_x : Integer; dpi_y : Integer; bounds_origin_x : Integer; bounds_origin_y : Integer; bounds_width : Integer; bounds_height : Integer; fit_to_bounds : Boolean; stretch_to_bounds : Boolean; keep_aspect_ratio : Boolean; center_in_bounds : Boolean; autorotate : Boolean): Boolean; cdecl;
var internal_hLib: THandle;
/////////////////////////////////////////////////////////////////////// function InchToCm(AInch: Single): Single; begin Result := AInch * 2.54; end;
//--------------------------------------------------------------------- procedure MyException(const ExceptMessage: String); begin MessageDlg(ExceptMessage, mtError, [mbAbort], 0); raise EAbort.Create(''); // Silent end;
//--------------------------------------------------------------------- procedure FreeLib; begin If internal_hLib <> 0 then try FreeLibrary(internal_hLib); finally internal_hLib := 0; end; end;
//--------------------------------------------------------------------- procedure LoadFun(var Fun: Pointer; const FunName: WideString); begin Fun := nil; Fun := GetProcAddress(internal_hLib, PWideChar(FunName)); If Fun = nil then MyException('Library "' + LibName + '" is not correct loaded.' + #13#10 + 'function "' + FunName + '" is not found.'); end;
//##################################################################### { TMyChromePDFRender } //##################################################################### constructor TMyChromePDFRender.Create; var iLastErr: DWord; begin LoadedDLL := False; Try internal_hLib := LoadLibrary(LibName); iLastErr := GetLastError; If internal_hLib = 0 then MyException('Library "' + LibName + '" is not correct loaded.' + #13#10 + SysErrorMessage(iLastErr)); //..................................................................... LoadFun(@GetPDFDocInfo, 'GetPDFDocInfo'); LoadFun(@GetPDFPageSizeByIndex, 'GetPDFPageSizeByIndex'); LoadFun(@RenderPDFPageToDC, 'RenderPDFPageToDC'); LoadedDLL := True; except FreeLib; end; end;
//--------------------------------------------------------------------- procedure TMyChromePDFRender.Clear; begin inherited; FreeMem(FBuffer); FBuffer := nil; FFullFileName := ''; FBufferSize := 0; FPagesCount := 0; FMaxPageWidthCm := 0; end;
//--------------------------------------------------------------------- function TMyChromePDFRender.LoadPDFFromStream(AStream: TStream; ALength: Int64): Boolean; var iPDFSize: Int64; fMaxPageWidthPix72dpi: Double; begin Result := False; If LoadedDLL then try If ALength > 0 then begin iPDFSize := ALength; If AStream.Position + iPDFSize > AStream.Size then MyException('Length-Parameter is over the stream size'); end else iPDFSize := AStream.Size - AStream.Position; If iPDFSize > High(Int64) then MyException('PDF is too big: ' + IntToStr(iPDFSize div (1024*1024)) + ' MB'); Clear; FBufferSize := iPDFSize; //............................................ GetMem(FBuffer, FBufferSize); AStream.ReadBuffer(FBuffer^, FBufferSize); //............................................ GetPDFDocInfo( FBuffer, FBufferSize, @FPagesCount, @fMaxPageWidthPix72dpi); FMaxPageWidthCm := InchToCm(fMaxPageWidthPix72dpi / 72.0); Result := True; except Clear; end; end;
//--------------------------------------------------------------------- function TMyChromePDFRender.GetPageSizeInPixel(APageNumber, ADpiX, ADpiY: Integer; var AWidth, AHeight: Integer): Boolean; var fWidthPix72dpi , fHeightPix72dpi : Double; begin Result := False; If LoadedDLL then try RaiseIfPageNumberWrong(APageNumber); Result := GetPDFPageSizeByIndex( FBuffer, // pdf_buffer FBufferSize, // buffer_size APageNumber - 1, // page_number @fWidthPix72dpi, // width @fHeightPix72dpi); // height AWidth := Round(fWidthPix72dpi / 72.0 * ADpiX); AHeight := Round(fHeightPix72dpi / 72.0 * ADpiY); finally end; end;
//--------------------------------------------------------------------- function TMyChromePDFRender.RenderPDFToDC(ADC: HDC; ARectLeft, ARectTop, ARectWidth, ARectHeight, APageNumber, ADpiX, ADpiY: Integer; ADoFitToBounds, ADoStretchToBounds, ADoKeepAspectRatio, ADoCenterInBounds, ADoAutoRotate: Boolean): Boolean; begin Result := False; If LoadedDLL then try RaiseIfPageNumberWrong(APageNumber); // From: https://chromium.googlesource.com/chromium/src/+/master/pdf/pdf.h // // |pdf_buffer| is the buffer that contains the entire PDF document to be // rendered. // |buffer_size| is the size of |pdf_buffer| in bytes. // |page_number| is the 0-based index of the page to be rendered. // |dc| is the device context to render into. // |dpi_x| and |dpi_y| are the x and y resolutions respectively. If either // value is -1, the dpi from the DC will be used. // |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height| // specify a bounds rectangle within the DC in which to render the PDF // page. // |fit_to_bounds| specifies whether the output should be shrunk to fit the // supplied bounds if the page size is larger than the bounds in any // dimension. If this is false, parts of the PDF page that lie outside // the bounds will be clipped. // |stretch_to_bounds| specifies whether the output should be stretched to fit // the supplied bounds if the page size is smaller than the bounds in any // dimension. // If both |fit_to_bounds| and |stretch_to_bounds| are true, then // |fit_to_bounds| is honored first. // |keep_aspect_ratio| If any scaling is to be done is true, this flag // specifies whether the original aspect ratio of the page should be // preserved while scaling. // |center_in_bounds| specifies whether the final image (after any scaling is // done) should be centered within the given bounds. // |autorotate| specifies whether the final image should be rotated to match // the output bound. // Returns false if the document or the page number are not valid. Result := RenderPDFPageToDC( FBuffer, // pdf_buffer FBufferSize, // buffer_size APageNumber - 1, // page_number ADC, // dc ADpiX, // dpi_x ADpiY, // dpi_y ARectLeft, // bounds_origin_x ARectTop, // bounds_origin_y ARectWidth, // bounds_width ARectHeight, // bounds_height ADoFitToBounds, // fit_to_bounds ADoStretchToBounds, // stretch_to_bounds ADoKeepAspectRatio, // keep_aspect_ratio ADoCenterInBounds, // center_in_bounds ADoAutoRotate); // autorotate finally end; end;
//--------------------------------------------------------------------- function TMyChromePDFRender.RenderPDFToBitmap( ABitmap: Graphics.TBitmap; APageNumber, ADpiX, ADpiY: Integer; ADoAutoRotate, ADoCenterInBounds, ADoAutoSizeBitmap: Boolean): Boolean; var iW, iH: Integer; begin Result := False; If not LoadedDLL then Exit; // Если функции из DLL не были загружены If ADoAutoSizeBitmap then begin If not GetPageSizeInPixel(APageNumber, ADpiX, ADpiY, iW, iH) then Exit; ABitmap.Width := iW; ABitmap.Height := iH; end; //..................................................................... ABitmap.Canvas.Brush.Style := bsSolid; ABitmap.Canvas.Brush.Color := clWhite; ABitmap.Canvas.FillRect(Rect(0,0,iW, iH)); //..................................................................... Result := RenderPDFToDC( ABitmap.Canvas.Handle, // ADC 0, // ARectLeft 0, // ARectTop ABitmap.Width, // ARectWidth ABitmap.Height, // ARectHeight APageNumber, // APageNumber ADpiX, // ADpiX ADpiY, // ADpiY not ADoAutoSizeBitmap, // ADoFitToBounds false, // ADoStretchToBounds true, // ADoKeepAspectRatio ADoCenterInBounds, // ADoCenterInBounds ADoAutoRotate ); // ADoAutoRotate end;
//--------------------------------------------------------------------- function TMyChromePDFRender.LoadPDFFromFile( const APDFFile: TFileName): Boolean; var FStr: TFileStream; begin If LoadedDLL and (Trim(APDFFile) <> '') then begin FStr := TFileStream.Create(APDFFile, fmOpenRead or fmShareDenyNone); Result := LoadPDFFromStream(FStr); If Result then FFullFileName := APDFFile; FreeAndNil(FStr); end else Result := False; end;
//--------------------------------------------------------------------- procedure TMyChromePDFRender.RaiseIfPageNumberWrong( APageNumber: Integer); begin If FPagesCount < 1 then MyException('There are 0 pageses in document') else if (APageNumber < 1) or (APageNumber > FPagesCount) then MyException('Page-Number "' + IntToStr(APageNumber) + '" is out of range [1..' + IntToStr(FPagesCount) + ']'); end;
//--------------------------------------------------------------------- destructor TMyChromePDFRender.Destroy; begin Clear; FreeLib; inherited; end;
end.
|
Это сообщение отредактировал(а) Prok12 - 30.4.2018, 08:52
|