КвейдMaratIskКвейд,
буду признателен за пример кода
Я обернул вьювер в наследник от TGraphicControl (T24NSPDFViewer = class(TGraphicControl))
Подключаешь его к форме, инициализируешь контрол, вызываешь LoadFromXXX, страницы крутятся через вызов ScrollBy.
Модуль используется в реальном проекте. Код мой, делайте что угодно.
Необходимо наличие вышеуказанной DLL, она есть в свободном доступе.
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391. 392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405. 406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419. 420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433. 434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447. 448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461. 462. 463. 464. 465. 466. 467. 468. 469. 470. 471. 472. 473. 474. 475. 476. 477. 478. 479. 480. 481. 482. 483. 484. 485. 486. 487. 488. 489. 490. 491. 492. 493. 494. 495. 496. 497. 498. 499. 500. 501. 502. 503. 504. 505. 506. 507. 508. 509. 510. 511. 512. 513. 514. 515. 516. 517. 518. 519. 520. 521. 522. 523. 524. 525. 526. 527. 528. 529. 530. 531. 532. 533. 534. 535. 536. 537. 538. 539. 540. 541. 542. 543. 544. 545. 546. 547. 548. 549. 550. 551. 552. 553. 554. 555. 556. 557. 558. 559. 560. 561. 562. 563. 564. 565. 566. 567. 568. 569. 570. 571. 572. 573. 574. 575. 576. 577. 578. 579. 580. 581. 582. 583. 584. 585. 586. 587. 588. 589. 590. 591. 592. 593. 594. 595. 596. 597. 598. 599. 600. 601. 602. 603. 604. 605. 606. 607. 608. 609. 610. 611. 612. 613. 614. 615. 616. 617. 618. 619. 620. 621. 622. 623. 624. 625. 626. 627. 628. 629. 630. 631. 632. 633. 634. 635. 636. 637. 638. 639. 640. 641. 642. 643. 644. 645. 646. 647. 648. 649. 650. 651. 652. 653. 654. 655. 656. 657. 658. 659. 660. 661. 662. 663. 664. 665. 666. 667. 668. 669. 670. 671. 672. 673. 674. 675. 676. 677. 678. 679. 680. 681. 682. 683. 684. 685. 686. 687. 688. 689. 690. 691. 692. 693. 694. 695. 696. 697. 698. 699. 700. 701. 702. 703. 704. 705. 706. 707. 708. 709. 710. 711. 712. 713. 714. 715. 716. 717. 718. 719. 720. 721. 722. 723. 724. 725. 726. 727. 728. 729. 730. 731. 732. 733. 734. 735. 736. 737. 738. 739. 740. 741. 742.
unit vcl24NSPDFViewer;
interface
uses
System.SysUtils, System.Variants,
System.Classes, System.Types,
System.SyncObjs,
Winapi.Windows, Winapi.Messages,
Vcl.Graphics, Vcl.Controls, Vcl.Forms,
Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
Generics.Collections,
IdComponent, IdHTTP;
const
WM_DONETHREAD = WM_USER + 1;
WM_RENDERBITMAP = WM_USER + 2;
WM_RELEASEBITMAP = WM_USER + 3;
WM_DOWNLOADFILE = WM_USER + 4;
type
TPDFPointer = record end;
TPDFDocument = ^TPDFPointer;
TPDFPage = ^TPDFPointer;
const
PDF_LIBRARY_NAME = 'PDFIUM.DLL';
type
TPDFClosePage = procedure(APage: Pointer); stdcall;
TPDFInitLibrary = procedure; stdcall;
TPDFDestroyLibrary = procedure; stdcall;
TPDFGetPageCount = function(ADocument: Pointer): Integer; stdcall;
TPDFCloseDocument = procedure(ADocument: Pointer); stdcall;
TPDFLoadMemDocument = function(ABuffer: Pointer; ASize: Integer;
APassword: PAnsiChar): Pointer; stdcall;
TPDFGetPageSizeByIndex = function(ADocument: Pointer; APage: Integer;
var AWidth, AHeight: Double): Integer; stdcall;
TPDFGetPageWidth = function(APage: Pointer): Double; stdcall;
TPDFGetPageHeight = function(APage: Pointer): Double; stdcall;
TPDFRenderPage = procedure(ADC: HDC; APage: Pointer;
ALeft, ATop, AWidth, AHeight, ARotate, AFlags: Integer); stdcall;
TPDFLoadPage = function(ADocument: Pointer; APage: Integer): TPDFPage; stdcall;
T24NSDocumentPage = class;
T24NSPDFViewer = class;
T24NSDownloader = class(TIdHTTP);
T24NSHelperThread = class(TThread)
private
FViewer: T24NSPDFViewer;
FMessageLoop: Boolean;
protected
procedure Execute; override;
procedure Invalidate;
procedure RenderBitmap(const AMsg: TMsg);
procedure ReleaseBitmap(const AMsg: TMsg);
public
constructor Create(AViewer: T24NSPDFViewer);
procedure Done;
procedure WaitLooping;
end;
TPDFLibrary = packed record
public
ClosePage: TPDFClosePage;
InitLibrary: TPDFInitLibrary;
RenderPage: TPDFRenderPage;
LoadPage: TPDFLoadPage;
DestroyLibrary: TPDFDestroyLibrary;
GetPageSizeByIndex: TPDFGetPageSizeByIndex;
GetPageCount: TPDFGetPageCount;
CloseDocument: TPDFCloseDocument;
GetPageWidth: TPDFGetPageWidth;
GetPageHeight: TPDFGetPageHeight;
LoadMemDocument: TPDFLoadMemDocument;
end;
T24NSDocumentEngine = class(TObject)
strict private
FPDFLibrary: TPDFLibrary;
FDocument: TPDFDocument;
FMemoryBuffer: TMemoryStream;
FModule: HMODULE;
procedure FreeDocument;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromStream(AStream: TStream);
function Initialized: Boolean; inline;
function PageCount: Integer; inline;
property PDFLibrary: TPDFLibrary read FPDFLibrary;
property Document: TPDFDocument read FDocument;
end;
T24NSDocumentPage = class(TObject)
strict private
FEngine: T24NSDocumentEngine;
FBitmap: TBitmap;
FIndex: Integer;
FWidth: Double;
FHeight: Double;
FBitmapRendered: Boolean;
FTimer: TTimer;
FViewer: T24NSPDFViewer;
FBlendValue: Integer;
procedure TimerTick(Sender: TObject);
procedure UpdatePage;
public
constructor Create(AViewer: T24NSPDFViewer; AIndex: Integer);
destructor Destroy; override;
function RenderedHeight(AWidth: Integer): Integer;
procedure ReleaseBitmap;
procedure RenderBitmap(AWidth: Integer);
procedure ResetTimer; inline;
procedure PrereleaseBitmap; inline;
property BlendValue: Integer read FBlendValue;
property Timer: TTimer read FTimer;
property BitmapRendered: Boolean read FBitmapRendered;
property Width: Double read FWidth;
property Height: Double read FHeight;
property Bitmap: TBitmap read FBitmap;
end;
T24NSDocumentPages = class(TObject)
strict private
FPages: TObjectList<T24NSDocumentPage>;
FEngine: T24NSDocumentEngine;
FPagesHeight: Integer;
FViewer: T24NSPDFViewer;
protected
function GetCount: Integer; inline;
procedure PreparePages;
public
constructor Create(AViewer: T24NSPDFViewer);
destructor Destroy; override;
function Page(AIndex: Integer): T24NSDocumentPage; inline;
function First: T24NSDocumentPage; inline;
function Last: T24NSDocumentPage; inline;
property Count: Integer read GetCount;
property PagesHeight: Integer read FPagesHeight;
end;
T24NSPDFViewer = class(TGraphicControl)
strict private
FEngine: T24NSDocumentEngine;
FPages: T24NSDocumentPages;
FDownloader: T24NSDownloader;
FHelperThread: T24NSHelperThread;
FViewOffset: Integer;
FBlendFunction: TBlendFunction;
FOnReady: TNotifyEvent;
FDocumentLoaded: Boolean;
FDocumentLoading: Boolean;
FDocumentProgress: Integer;
FBeginDocument: Boolean;
FEndDocument: Boolean;
FPainting: Boolean;
protected
procedure ReleaseBitmap(APageIndex: Integer; ABitmap: TBitmap); inline;
procedure RenderBitmap(APageIndex: Integer; ABitmap: TBitmap); inline;
procedure DownloadWork(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
procedure Paint; override;
property Engine: T24NSDocumentEngine read FEngine;
property Pages: T24NSDocumentPages read FPages;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AfterConstruction; override;
procedure ScrollBy(ADelta: Integer);
procedure Ready;
procedure LoadFromFile(const AFileName: string);
procedure LoadFromURL(const AURL: string);
procedure LoadFromStream(AStream: TStream);
property OnReady: TNotifyEvent read FOnReady write FOnReady;
property Painting: Boolean read FPainting;
property EndDocument: Boolean read FEndDocument;
property BeginDocument: Boolean read FBeginDocument;
end;
implementation
resourcestring
RST_PDFIUMNOTLOADED = 'PDFIUM.DLL IS NOT LOADED CORRECTLY';
const
DEF_FONT_SIZE = 38;
DEF_FONT_NAME = 'Impact';
DEF_FONT_COLOR = $DADADA;
DEF_BLENDING_STEP = 32;
DEF_BLENDING_INTERVAL = 32;
{ T24NSDocumentEngine }
constructor T24NSDocumentEngine.Create;
begin
inherited Create;
FMemoryBuffer := nil;
FModule := SafeLoadLibrary(PDF_LIBRARY_NAME);
with FPDFLibrary do
begin
if FModule = 0 then
raise Exception.CreateRes(@RST_PDFIUMNOTLOADED);
InitLibrary := GetProcAddress(FModule, '_FPDF_InitLibrary@0');
DestroyLibrary := GetProcAddress(FModule, '_FPDF_DestroyLibrary@0');
RenderPage := GetProcAddress(FModule, '_FPDF_RenderPage@32');
LoadPage := GetProcAddress(FModule, '_FPDF_LoadPage@8');
GetPageWidth := GetProcAddress(FModule, '_FPDF_GetPageWidth@4');
GetPageHeight := GetProcAddress(FModule, '_FPDF_GetPageHeight@4');
GetPageCount := GetProcAddress(FModule, '_FPDF_GetPageCount@4');
LoadMemDocument := GetProcAddress(FModule, '_FPDF_LoadMemDocument@12');
CloseDocument := GetProcAddress(FModule, '_FPDF_CloseDocument@4');
ClosePage := GetProcAddress(FModule, '_FPDF_ClosePage@4');
GetPageSizeByIndex := GetProcAddress(FModule, '_FPDF_GetPageSizeByIndex@16');
InitLibrary
end
end;
destructor T24NSDocumentEngine.Destroy;
begin
if Initialized then
begin
FreeDocument;
FreeAndNil(FMemoryBuffer);
FPDFLibrary.DestroyLibrary;
FreeLibrary(FModule)
end;
inherited Destroy
end;
procedure T24NSDocumentEngine.FreeDocument;
begin
if FDocument <> nil then
FPDFLibrary.CloseDocument(FDocument);
FDocument := nil;
FreeAndNil(FMemoryBuffer);
FMemoryBuffer := TMemoryStream.Create
end;
function T24NSDocumentEngine.Initialized: Boolean;
begin
Result := FModule <> 0
end;
procedure T24NSDocumentEngine.LoadFromStream(AStream: TStream);
begin
if Initialized then
begin
FreeDocument;
if AStream.Size > 0 then
try
FMemoryBuffer.LoadFromStream(AStream);
with FMemoryBuffer, FPDFLibrary do
FDocument := LoadMemDocument(Memory, Size, nil)
except
FreeDocument
end
end
end;
function T24NSDocumentEngine.PageCount: Integer;
begin
Result := 0;
if Initialized and (FDocument <> nil) then
Result := FPDFLibrary.GetPageCount(FDocument)
end;
{ T24NSPDFViewer }
procedure T24NSPDFViewer.AfterConstruction;
begin
inherited AfterConstruction;
FHelperThread.WaitLooping
end;
constructor T24NSPDFViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FViewOffset := 0;
FBeginDocument := False;
FEndDocument := False;
FDocumentLoaded := False;
FDocumentLoading := False;
FPainting := False;
FDocumentProgress := 0;
FBlendFunction.BlendOp := AC_SRC_OVER;
FBlendFunction.BlendFlags := 0;
FBlendFunction.SourceConstantAlpha := 255;
FBlendFunction.AlphaFormat := 0;
Color := clWhite;
FEngine := T24NSDocumentEngine.Create;
FPages := T24NSDocumentPages.Create(Self);
FHelperThread := T24NSHelperThread.Create(Self);
FDownloader := T24NSDownloader.Create(Self);
FDownloader.AllowCookies := True;
FDownloader.HandleRedirects := True
end;
destructor T24NSPDFViewer.Destroy;
begin
FHelperThread.Done;
FreeAndNil(FHelperThread);
FreeAndNil(FPages);
FreeAndNil(FEngine);
inherited Destroy
end;
procedure T24NSPDFViewer.DownloadWork(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
var
ContentLength: Int64;
begin
ContentLength := FDownloader.Response.ContentLength;
FDocumentProgress := 100 * AWorkCount div ContentLength;
TWinControl(Owner).Repaint
end;
procedure T24NSPDFViewer.LoadFromFile(const AFileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream)
finally
FreeAndNil(Stream)
end
end;
procedure T24NSPDFViewer.LoadFromStream(AStream: TStream);
begin
try
if AStream.Size = 0 then
Abort;
AStream.Position := 0;
FEngine.LoadFromStream(AStream);
FPages.PreparePages;
Ready;
Repaint
except
FDocumentLoaded := False
end
end;
procedure T24NSPDFViewer.LoadFromURL(const AURL: string);
var
Stream: TStream;
begin
Stream := TMemoryStream.Create;
FDocumentLoading := True;
try
FDownloader.OnWork := DownloadWork;
FDocumentLoaded := False;
TWinControl(Owner).Repaint;
try
FDownloader.Get(AURL, Stream);
FDocumentLoading := False;
LoadFromStream(Stream)
except
Ready
end
finally
FDownloader.OnWork := nil;
FDocumentProgress := 0;
FreeAndNil(Stream)
end
end;
procedure T24NSPDFViewer.Paint;
var
X, Y: Integer;
R: TRect;
RealHeight: Integer;
I: Integer;
Progress: string;
Size: TSize;
begin
FPainting := True;
try
with Canvas do
begin
Brush.Style := bsSolid;
Brush.Color := Color;
FillRect(ClientRect)
end;
if FDocumentLoading then
begin
Progress := Concat(FDocumentProgress.ToString, '%');
with Canvas.Font do
begin
Name := DEF_FONT_NAME;
Size := DEF_FONT_SIZE;
Color := DEF_FONT_COLOR
end;
Size := Canvas.TextExtent(Progress);
X := (ClientWidth - Size.Width) div 2;
Y := (ClientHeight - Size.Height) div 2;
Canvas.TextOut(X, Y, Progress)
end;
if FDocumentLoaded then
begin
X := 0;
Y := 0;
Dec(Y, FViewOffset);
for I := 0 to Pred(FPages.Count) do
begin
RealHeight := FPages.Page(I).RenderedHeight(ClientWidth);
if ((Y + RealHeight) > 0) and (Y < ClientHeight) then
begin
if not FPages.Page(I).BitmapRendered then
RenderBitmap(I, nil)
else
begin
R := Rect(X, Y, ClientWidth, Y + RealHeight);
if FPages.Page(I).Timer.Enabled then
begin
FBlendFunction.SourceConstantAlpha := FPages.Page(I).BlendValue;
AlphaBlend(Canvas.Handle, X, Y, ClientWidth, RealHeight,
FPages.Page(I).Bitmap.Canvas.Handle,
0, 0, ClientWidth, RealHeight, FBlendFunction)
end
else
BitBlt(Canvas.Handle, X, Y, ClientWidth, RealHeight,
FPages.Page(I).Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
end
end
else
begin
if FPages.Page(I).BitmapRendered then
begin
FPages.Page(I).PrereleaseBitmap;
ReleaseBitmap(I, FPages.Page(I).Bitmap)
end;
end;
Inc(Y, RealHeight)
end;
{$IFDEF 24NSDEBUG}
Canvas.TextOut(0, 0, FViewOffset.ToString)
{$ENDIF}
end
finally
FPainting := False
end
end;
procedure T24NSPDFViewer.Ready;
begin
FDocumentLoading := False;
FDocumentLoaded := True;
FBeginDocument := True;
FEndDocument := False;
FViewOffset := 0;
if Assigned(FOnReady) then
FOnReady(Self);
Invalidate
end;
procedure T24NSPDFViewer.ReleaseBitmap(APageIndex: Integer; ABitmap: TBitmap);
begin
PostThreadMessage(FHelperThread.ThreadID, WM_RELEASEBITMAP, WPARAM(APageIndex), LPARAM(ABitmap))
end;
procedure T24NSPDFViewer.RenderBitmap(APageIndex: Integer; ABitmap: TBitmap);
begin
PostThreadMessage(FHelperThread.ThreadID, WM_RENDERBITMAP, WPARAM(APageIndex), LPARAM(ClientWidth))
end;
procedure T24NSPDFViewer.ScrollBy(ADelta: Integer);
var
Y: Integer;
begin
FBeginDocument := False;
FEndDocument := False;
if FDocumentLoaded then
begin
Inc(FViewOffset, ADelta);
if FViewOffset <= 0 then
FViewOffset := 0;
Y := Pages.PagesHeight - ClientHeight;
if Y < 0 then
Y := 0;
if FViewOffset > Y then
FViewOffset := Y;
FBeginDocument := FViewOffset = 0;
FEndDocument := FViewOffset = Y;
Invalidate
end
end;
{ T24NSDocumentPages }
constructor T24NSDocumentPages.Create(AViewer: T24NSPDFViewer);
begin
inherited Create;
FViewer := AViewer;
FEngine := AViewer.Engine;
FPagesHeight := 0;
FPages := TObjectList<T24NSDocumentPage>.Create(True)
end;
destructor T24NSDocumentPages.Destroy;
begin
FreeAndNil(FPages);
inherited Destroy
end;
function T24NSDocumentPages.GetCount: Integer;
begin
Result := FPages.Count
end;
function T24NSDocumentPages.First: T24NSDocumentPage;
begin
if Count = 0 then
Exit(nil);
Exit(Page(0))
end;
function T24NSDocumentPages.Last: T24NSDocumentPage;
begin
if Count = 0 then
Exit(nil);
Exit(Page(Pred(Count)))
end;
procedure T24NSDocumentPages.PreparePages;
var
Page: T24NSDocumentPage;
I: Integer;
X: Integer;
begin
FPagesHeight := 0;
FPages.Clear;
X := FViewer.ClientWidth;
for I := 0 to Pred(FEngine.PageCount) do
begin
Page := T24NSDocumentPage.Create(FViewer, I);
FPages.Add(Page);
FPagesHeight := FPagesHeight + Page.RenderedHeight(X)
end
end;
function T24NSDocumentPages.Page(AIndex: Integer): T24NSDocumentPage;
begin
Result := FPages.List[AIndex]
end;
{ T24NSDocumentPage }
constructor T24NSDocumentPage.Create(AViewer: T24NSPDFViewer; AIndex: Integer);
begin
inherited Create;
FBitmap := nil;
FViewer := AViewer;
FIndex := AIndex;
FBitmapRendered := False;
FBlendValue := 0;
FEngine := AViewer.Engine;
FTimer := TTimer.Create(nil);
FTimer.OnTimer := TimerTick;
FTimer.Enabled := False;
FTimer.Interval := DEF_BLENDING_INTERVAL;
UpdatePage;
ReleaseBitmap
end;
destructor T24NSDocumentPage.Destroy;
begin
FreeAndNil(FTimer);
FreeAndNil(FBitmap);
inherited Destroy
end;
procedure T24NSDocumentPage.PrereleaseBitmap;
begin
ResetTimer;
FBitmapRendered := False
end;
procedure T24NSDocumentPage.UpdatePage;
begin
with FEngine, FEngine.PDFLibrary do
GetPageSizeByIndex(Document, FIndex, FWidth, FHeight)
end;
procedure T24NSDocumentPage.ReleaseBitmap;
begin
FBitmapRendered := False;
FreeAndNil(FBitmap);
FBitmap := TBitmap.Create
end;
procedure T24NSDocumentPage.RenderBitmap(AWidth: Integer);
var
DisplayWidth: Integer;
DisplayHeight: Integer;
Page: TPDFPage;
begin
if not FBitmapRendered then
begin
Page := FEngine.PDFLibrary.LoadPage(FEngine.Document, FIndex);
try
FBitmap.Canvas.Lock;
try
DisplayWidth := AWidth;
DisplayHeight := RenderedHeight(DisplayWidth);
FBitmap.SetSize(DisplayWidth, DisplayHeight);
FEngine.PDFLibrary.RenderPage(FBitmap.Canvas.Handle,
Page, 0, 0, DisplayWidth, DisplayHeight, 0, 0)
finally
FBitmap.Canvas.Unlock
end;
FBlendValue := 0;
FBitmapRendered := True;
Timer.Enabled := True
finally
FEngine.PDFLibrary.ClosePage(Page)
end
end
end;
function T24NSDocumentPage.RenderedHeight(AWidth: Integer): Integer;
begin
Result := Round(Height * (AWidth / Width))
end;
procedure T24NSDocumentPage.ResetTimer;
begin
FTimer.Enabled := False;
FBlendValue := 0
end;
procedure T24NSDocumentPage.TimerTick(Sender: TObject);
begin
Inc(FBlendValue, DEF_BLENDING_STEP);
if FBlendValue >= 255 then
ResetTimer;
FViewer.Invalidate
end;
{ T24NSHelperThread }
constructor T24NSHelperThread.Create(AViewer: T24NSPDFViewer);
begin
inherited Create(False);
Priority := tpLowest;
FViewer := AViewer;
FreeOnTerminate := False
end;
procedure T24NSHelperThread.WaitLooping;
begin
while not FMessageLoop do
SwitchToThread
end;
procedure T24NSHelperThread.Execute;
var
Msg: TMsg;
function HandleMessage: Boolean; near;
function NeedHandleMessage: Boolean; near;
begin
Result := (Msg.Message >= WM_DONETHREAD)
and (Msg.Message <= WM_DOWNLOADFILE)
end;
begin
Result := NeedHandleMessage;
if Result then
case Msg.Message of
WM_DONETHREAD:
Terminate;
WM_RELEASEBITMAP:
ReleaseBitmap(Msg);
WM_RENDERBITMAP:
RenderBitmap(Msg)
end
end;
function ProcessMessage: Boolean; near;
begin
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
Result := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
if Result then
begin
if not HandleMessage then
if not Terminated then
begin
TranslateMessage(Msg);
DispatchMessage(Msg)
end
end
end
else
Result := False
end;
begin
FMessageLoop := True;
try
while not Terminated do
if not ProcessMessage then
WaitMessage
finally
FMessageLoop := False
end
end;
procedure T24NSHelperThread.Invalidate;
begin
if FViewer.Owner is TWinControl then
TWinControl(FViewer.Owner).Invalidate
end;
procedure T24NSHelperThread.ReleaseBitmap;
begin
FViewer.Pages.Page(AMsg.wParam).ReleaseBitmap
end;
procedure T24NSHelperThread.RenderBitmap;
begin
while FViewer.Painting do
SwitchToThread;
FViewer.Pages.Page(AMsg.wParam).RenderBitmap(AMsg.lParam)
end;
procedure T24NSHelperThread.Done;
begin
if not Suspended and not Terminated then
PostThreadMessage(ThreadID, WM_DONETHREAD, 0, 0)
end;
end.
вот что получилось для Д7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391. 392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405. 406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419. 420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433. 434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447. 448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461. 462. 463. 464. 465. 466. 467. 468. 469. 470. 471. 472. 473. 474. 475. 476. 477. 478. 479. 480. 481. 482. 483. 484. 485. 486. 487. 488. 489. 490. 491. 492. 493. 494. 495. 496. 497. 498. 499. 500. 501. 502. 503. 504. 505. 506. 507. 508. 509. 510. 511. 512. 513. 514. 515. 516. 517. 518. 519. 520. 521. 522. 523. 524. 525. 526. 527. 528. 529. 530. 531. 532. 533. 534. 535. 536. 537. 538. 539. 540. 541. 542. 543. 544. 545. 546. 547. 548. 549. 550. 551. 552. 553. 554. 555. 556. 557. 558. 559. 560. 561. 562. 563. 564. 565. 566. 567. 568. 569. 570. 571. 572. 573. 574. 575. 576. 577. 578. 579. 580. 581. 582. 583. 584. 585. 586. 587. 588. 589. 590. 591. 592. 593. 594. 595. 596. 597. 598. 599. 600. 601. 602. 603. 604. 605. 606. 607. 608. 609. 610. 611. 612. 613. 614. 615. 616. 617. 618. 619. 620. 621. 622. 623. 624. 625. 626. 627. 628. 629. 630. 631. 632. 633. 634. 635. 636. 637. 638. 639. 640. 641. 642. 643. 644. 645. 646. 647. 648. 649. 650. 651. 652. 653. 654. 655. 656. 657. 658. 659. 660. 661. 662. 663. 664. 665. 666. 667. 668. 669. 670. 671. 672. 673. 674. 675. 676. 677. 678. 679. 680. 681. 682. 683. 684. 685. 686. 687. 688. 689. 690. 691. 692. 693. 694. 695. 696. 697. 698. 699. 700. 701. 702. 703. 704. 705. 706. 707. 708. 709. 710. 711. 712. 713. 714. 715. 716. 717. 718. 719. 720. 721. 722. 723. 724. 725. 726. 727. 728. 729. 730. 731. 732. 733. 734. 735. 736. 737. 738. 739. 740. 741. 742. 743. 744. 745. 746. 747. 748. 749. 750. 751. 752. 753. 754. 755. 756. 757. 758. 759. 760. 761. 762. 763. 764. 765. 766. 767.
unit vcl24NSPDFViewer;
interface
uses
SysUtils, Variants,
Classes, Types,
SyncObjs,
Windows, Messages,
Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,
// , Collections,
IdComponent, IdHTTP;
const
WM_DONETHREAD = WM_USER + 1;
WM_RENDERBITMAP = WM_USER + 2;
WM_RELEASEBITMAP = WM_USER + 3;
WM_DOWNLOADFILE = WM_USER + 4;
type
TPDFPointer = record end;
TPDFDocument = ^TPDFPointer;
TPDFPage = ^TPDFPointer;
const
PDF_LIBRARY_NAME = 'PDFIUM.DLL';
type
TPDFClosePage = procedure(APage: Pointer); stdcall;
TPDFInitLibrary = procedure; stdcall;
TPDFDestroyLibrary = procedure; stdcall;
TPDFGetPageCount = function(ADocument: Pointer): Integer; stdcall;
TPDFCloseDocument = procedure(ADocument: Pointer); stdcall;
TPDFLoadMemDocument = function(ABuffer: Pointer; ASize: Integer;
APassword: PAnsiChar): Pointer; stdcall;
TPDFGetPageSizeByIndex = function(ADocument: Pointer; APage: Integer;
var AWidth, AHeight: Double): Integer; stdcall;
TPDFGetPageWidth = function(APage: Pointer): Double; stdcall;
TPDFGetPageHeight = function(APage: Pointer): Double; stdcall;
TPDFRenderPage = procedure(ADC: HDC; APage: Pointer;
ALeft, ATop, AWidth, AHeight, ARotate, AFlags: Integer); stdcall;
TPDFLoadPage = function(ADocument: Pointer; APage: Integer): TPDFPage; stdcall;
T24NSDocumentPage = class;
T24NSPDFViewer = class;
TArr24NSDocumentPage = array of T24NSDocumentPage;
T24NSDownloader = class(TIdHTTP);
T24NSHelperThread = class(TThread)
private
FViewer: T24NSPDFViewer;
FMessageLoop: Boolean;
protected
procedure Execute; override;
procedure Invalidate;
procedure RenderBitmap(const AMsg: TMsg);
procedure ReleaseBitmap(const AMsg: TMsg);
public
constructor Create(AViewer: T24NSPDFViewer);
procedure Done;
procedure WaitLooping;
end;
TPDFLibrary = class
public
ClosePage: TPDFClosePage;
InitLibrary: TPDFInitLibrary;
RenderPage: TPDFRenderPage;
LoadPage: TPDFLoadPage;
DestroyLibrary: TPDFDestroyLibrary;
GetPageSizeByIndex: TPDFGetPageSizeByIndex;
GetPageCount: TPDFGetPageCount;
CloseDocument: TPDFCloseDocument;
GetPageWidth: TPDFGetPageWidth;
GetPageHeight: TPDFGetPageHeight;
LoadMemDocument: TPDFLoadMemDocument;
end;
T24NSDocumentEngine = class(TObject)
private
FPDFLibrary: TPDFLibrary;
FDocument: TPDFDocument;
FMemoryBuffer: TMemoryStream;
FModule: HMODULE;
procedure FreeDocument;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromStream(AStream: TStream);
function Initialized: Boolean;
function PageCount: Integer;
property PDFLibrary: TPDFLibrary read FPDFLibrary;
property Document: TPDFDocument read FDocument;
end;
T24NSDocumentPage = class(TObject)
private
FEngine: T24NSDocumentEngine;
FBitmap: TBitmap;
FIndex: Integer;
FWidth: Double;
FHeight: Double;
FBitmapRendered: Boolean;
FTimer: TTimer;
FViewer: T24NSPDFViewer;
FBlendValue: Integer;
procedure TimerTick(Sender: TObject);
procedure UpdatePage;
public
constructor Create(AViewer: T24NSPDFViewer; AIndex: Integer);
destructor Destroy; override;
function RenderedHeight(AWidth: Integer): Integer;
procedure ReleaseBitmap;
procedure RenderBitmap(AWidth: Integer);
procedure ResetTimer;
procedure PrereleaseBitmap;
property BlendValue: Integer read FBlendValue;
property Timer: TTimer read FTimer;
property BitmapRendered: Boolean read FBitmapRendered;
property Width: Double read FWidth;
property Height: Double read FHeight;
property Bitmap: TBitmap read FBitmap;
end;
T24NSDocumentPages = class(TObject)
private
//FPages: TObjectList<T24NSDocumentPage>;
FPages: TArr24NSDocumentPage;
FEngine: T24NSDocumentEngine;
FPagesHeight: Integer;
FViewer: T24NSPDFViewer;
protected
function GetCount: Integer;
procedure PreparePages;
public
constructor Create(AViewer: T24NSPDFViewer);
destructor Destroy; override;
function Page(AIndex: Integer): T24NSDocumentPage;
function First: T24NSDocumentPage;
function Last: T24NSDocumentPage;
property Count: Integer read GetCount;
property PagesHeight: Integer read FPagesHeight;
end;
T24NSPDFViewer = class(TGraphicControl)
private
FEngine: T24NSDocumentEngine;
FPages: T24NSDocumentPages;
FDownloader: T24NSDownloader;
FHelperThread: T24NSHelperThread;
FViewOffset: Integer;
FBlendFunction: TBlendFunction;
FOnReady: TNotifyEvent;
FDocumentLoaded: Boolean;
FDocumentLoading: Boolean;
FDocumentProgress: Integer;
FBeginDocument: Boolean;
FEndDocument: Boolean;
FPainting: Boolean;
protected
procedure ReleaseBitmap(APageIndex: Integer; ABitmap: TBitmap);
procedure RenderBitmap(APageIndex: Integer; ABitmap: TBitmap);
procedure DownloadWork(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
procedure Paint; override;
property Engine: T24NSDocumentEngine read FEngine;
property Pages: T24NSDocumentPages read FPages;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AfterConstruction; override;
procedure ScrollBy(ADelta: Integer);
procedure Ready;
procedure LoadFromFile(const AFileName: string);
procedure LoadFromURL(const AURL: string);
procedure LoadFromStream(AStream: TStream);
property OnReady: TNotifyEvent read FOnReady write FOnReady;
property Painting: Boolean read FPainting;
property EndDocument: Boolean read FEndDocument;
property BeginDocument: Boolean read FBeginDocument;
end;
implementation
resourcestring
RST_PDFIUMNOTLOADED = 'PDFIUM.DLL IS NOT LOADED CORRECTLY';
const
DEF_FONT_SIZE = 38;
DEF_FONT_NAME = 'Impact';
DEF_FONT_COLOR = $DADADA;
DEF_BLENDING_STEP = 32;
DEF_BLENDING_INTERVAL = 32;
{ T24NSDocumentEngine }
constructor T24NSDocumentEngine.Create;
begin
inherited Create;
FMemoryBuffer := nil;
FModule := SafeLoadLibrary(PDF_LIBRARY_NAME);
FPDFLibrary := TPDFLibrary.Create; // 27-11-2018
with FPDFLibrary do
begin
if FModule = 0 then
raise Exception.CreateRes(@RST_PDFIUMNOTLOADED);
InitLibrary := GetProcAddress(FModule, '_FPDF_InitLibrary@0');
DestroyLibrary := GetProcAddress(FModule, '_FPDF_DestroyLibrary@0');
RenderPage := GetProcAddress(FModule, '_FPDF_RenderPage@32');
LoadPage := GetProcAddress(FModule, '_FPDF_LoadPage@8');
GetPageWidth := GetProcAddress(FModule, '_FPDF_GetPageWidth@4');
GetPageHeight := GetProcAddress(FModule, '_FPDF_GetPageHeight@4');
GetPageCount := GetProcAddress(FModule, '_FPDF_GetPageCount@4');
LoadMemDocument := GetProcAddress(FModule, '_FPDF_LoadMemDocument@12');
CloseDocument := GetProcAddress(FModule, '_FPDF_CloseDocument@4');
ClosePage := GetProcAddress(FModule, '_FPDF_ClosePage@4');
GetPageSizeByIndex := GetProcAddress(FModule, '_FPDF_GetPageSizeByIndex@16');
InitLibrary;
end
end;
destructor T24NSDocumentEngine.Destroy;
begin
if Initialized then
begin
FreeDocument;
FreeAndNil(FMemoryBuffer);
FPDFLibrary.DestroyLibrary;
FreeLibrary(FModule)
end;
inherited Destroy
end;
procedure T24NSDocumentEngine.FreeDocument;
begin
if FDocument <> nil then
FPDFLibrary.CloseDocument(FDocument);
FDocument := nil;
FreeAndNil(FMemoryBuffer);
FMemoryBuffer := TMemoryStream.Create
end;
function T24NSDocumentEngine.Initialized: Boolean;
begin
Result := FModule <> 0
end;
procedure T24NSDocumentEngine.LoadFromStream(AStream: TStream);
begin
if Initialized then
begin
FreeDocument;
if AStream.Size > 0 then
try
FMemoryBuffer.LoadFromStream(AStream);
with FMemoryBuffer, FPDFLibrary do
FDocument := LoadMemDocument(Memory, Size, nil)
except
FreeDocument
end
end
end;
function T24NSDocumentEngine.PageCount: Integer;
begin
Result := 0;
if Initialized and (FDocument <> nil) then
Result := FPDFLibrary.GetPageCount(FDocument)
end;
{ T24NSPDFViewer }
procedure T24NSPDFViewer.AfterConstruction;
begin
inherited AfterConstruction;
FHelperThread.WaitLooping
end;
constructor T24NSPDFViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FViewOffset := 0;
FBeginDocument := False;
FEndDocument := False;
FDocumentLoaded := False;
FDocumentLoading := False;
FPainting := False;
FDocumentProgress := 0;
FBlendFunction.BlendOp := AC_SRC_OVER;
FBlendFunction.BlendFlags := 0;
FBlendFunction.SourceConstantAlpha := 255;
FBlendFunction.AlphaFormat := 0;
Color := clWhite;
FEngine := T24NSDocumentEngine.Create;
FPages := T24NSDocumentPages.Create(Self);
FHelperThread := T24NSHelperThread.Create(Self);
FDownloader := T24NSDownloader.Create(Self);
FDownloader.AllowCookies := True;
FDownloader.HandleRedirects := True
end;
destructor T24NSPDFViewer.Destroy;
begin
FHelperThread.Done;
FreeAndNil(FHelperThread);
FreeAndNil(FPages);
FreeAndNil(FEngine);
inherited Destroy
end;
procedure T24NSPDFViewer.DownloadWork(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
var
ContentLength: Int64;
begin
ContentLength := FDownloader.Response.ContentLength;
FDocumentProgress := 100 * AWorkCount div ContentLength;
TWinControl(Owner).Repaint;
end;
procedure T24NSPDFViewer.LoadFromFile(const AFileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream)
finally
FreeAndNil(Stream)
end
end;
procedure T24NSPDFViewer.LoadFromStream(AStream: TStream);
begin
try
if AStream.Size = 0 then
Abort;
AStream.Position := 0;
FEngine.LoadFromStream(AStream);
FPages.PreparePages;
Ready;
Repaint
except
FDocumentLoaded := False
end
end;
procedure T24NSPDFViewer.LoadFromURL(const AURL: string);
var
Stream: TStream;
begin
Stream := TMemoryStream.Create;
FDocumentLoading := True;
try
FDownloader.OnWork := DownloadWork;
FDocumentLoaded := False;
TWinControl(Owner).Repaint;
try
FDownloader.Get(AURL, Stream);
FDocumentLoading := False;
LoadFromStream(Stream)
except
Ready
end
finally
FDownloader.OnWork := nil;
FDocumentProgress := 0;
FreeAndNil(Stream)
end
end;
procedure T24NSPDFViewer.Paint;
var
X, Y: Integer;
R: TRect;
RealHeight: Integer;
I: Integer;
Progress: string;
Size: TSize;
begin
FPainting := True;
try
with Canvas do
begin
Brush.Style := bsSolid;
Brush.Color := Color;
FillRect(ClientRect)
end;
if FDocumentLoading then
begin
//Progress := Concat(FDocumentProgress.ToString, '%');
Progress := INttostr(FDocumentProgress) + '%';
with Canvas.Font do
begin
Name := DEF_FONT_NAME;
Size := DEF_FONT_SIZE;
Color := DEF_FONT_COLOR
end;
Size := Canvas.TextExtent(Progress);
//X := (ClientWidth - Size.Width) div 2;
//Y := (ClientHeight - Size.Height) div 2;
X := (ClientWidth - Size.cx) div 2;
Y := (ClientHeight - Size.cy) div 2;
Canvas.TextOut(X, Y, Progress)
end;
if FDocumentLoaded then
begin
X := 0;
Y := 0;
Dec(Y, FViewOffset);
for I := 0 to Pred(FPages.Count) do
begin
RealHeight := FPages.Page(I).RenderedHeight(ClientWidth);
if ((Y + RealHeight) > 0) and (Y < ClientHeight) then
begin
if not FPages.Page(I).BitmapRendered then
RenderBitmap(I, nil)
else
begin
R := Rect(X, Y, ClientWidth, Y + RealHeight);
if FPages.Page(I).Timer.Enabled then
begin
FBlendFunction.SourceConstantAlpha := FPages.Page(I).BlendValue;
AlphaBlend(Canvas.Handle, X, Y, ClientWidth, RealHeight,
FPages.Page(I).Bitmap.Canvas.Handle,
0, 0, ClientWidth, RealHeight, FBlendFunction)
end
else
BitBlt(Canvas.Handle, X, Y, ClientWidth, RealHeight,
FPages.Page(I).Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
end
end
else
begin
if FPages.Page(I).BitmapRendered then
begin
FPages.Page(I).PrereleaseBitmap;
ReleaseBitmap(I, FPages.Page(I).Bitmap)
end;
end;
Inc(Y, RealHeight)
end;
{$IFDEF 24NSDEBUG}
Canvas.TextOut(0, 0, FViewOffset.ToString)
{$ENDIF}
end
finally
FPainting := False
end
end;
procedure T24NSPDFViewer.Ready;
begin
FDocumentLoading := False;
FDocumentLoaded := True;
FBeginDocument := True;
FEndDocument := False;
FViewOffset := 0;
if Assigned(FOnReady) then
FOnReady(Self);
Invalidate
end;
procedure T24NSPDFViewer.ReleaseBitmap(APageIndex: Integer; ABitmap: TBitmap);
begin
PostThreadMessage(FHelperThread.ThreadID, WM_RELEASEBITMAP, WPARAM(APageIndex), LPARAM(ABitmap))
end;
procedure T24NSPDFViewer.RenderBitmap(APageIndex: Integer; ABitmap: TBitmap);
begin
PostThreadMessage(FHelperThread.ThreadID, WM_RENDERBITMAP, WPARAM(APageIndex), LPARAM(ClientWidth))
end;
procedure T24NSPDFViewer.ScrollBy(ADelta: Integer);
var
Y: Integer;
begin
FBeginDocument := False;
FEndDocument := False;
if FDocumentLoaded then
begin
Inc(FViewOffset, ADelta);
if FViewOffset <= 0 then
FViewOffset := 0;
Y := Pages.PagesHeight - ClientHeight;
if Y < 0 then
Y := 0;
if FViewOffset > Y then
FViewOffset := Y;
FBeginDocument := FViewOffset = 0;
FEndDocument := FViewOffset = Y;
Invalidate
end
end;
{ T24NSDocumentPages }
constructor T24NSDocumentPages.Create(AViewer: T24NSPDFViewer);
begin
inherited Create;
FViewer := AViewer;
FEngine := AViewer.Engine;
FPagesHeight := 0;
//FPages := TObjectList<T24NSDocumentPage>.Create(True)
SetLength(FPages, 0);
end;
destructor T24NSDocumentPages.Destroy;
begin
SetLength(FPages, 0); // äîðàáîòàòü î÷èñòêó ñòðàíèö
// FreeAndNil(FPages);
inherited Destroy
end;
function T24NSDocumentPages.GetCount: Integer;
begin
//Result := FPages.Count
Result := length(FPages);
end;
function T24NSDocumentPages.First: T24NSDocumentPage;
begin
if Count = 0 then
begin
result := nil;
end else
begin
result := FPages[0];
end;
end;
function T24NSDocumentPages.Last: T24NSDocumentPage;
begin
if Count = 0 then
begin
result := nil;
end else
begin
result := FPages[length(FPages)-1];
end;
end;
procedure T24NSDocumentPages.PreparePages;
var
Page: T24NSDocumentPage;
I: Integer;
X: Integer;
begin
FPagesHeight := 0;
//FPages.Clear;
SetLength(FPages, 0);
SetLength(FPages, Pred(FEngine.PageCount)+1);
X := FViewer.ClientWidth;
for I := 0 to Pred(FEngine.PageCount) do
begin
Page := T24NSDocumentPage.Create(FViewer, I);
//FPages.Add(Page);
FPages[i] := Page;
FPagesHeight := FPagesHeight + Page.RenderedHeight(X)
end
end;
function T24NSDocumentPages.Page(AIndex: Integer): T24NSDocumentPage;
begin
//Result := FPages.List[AIndex]
Result := FPages[AIndex];
end;
{ T24NSDocumentPage }
constructor T24NSDocumentPage.Create(AViewer: T24NSPDFViewer; AIndex: Integer);
begin
inherited Create;
FBitmap := nil;
FViewer := AViewer;
FIndex := AIndex;
FBitmapRendered := False;
FBlendValue := 0;
FEngine := AViewer.Engine;
FTimer := TTimer.Create(nil);
FTimer.OnTimer := TimerTick;
FTimer.Enabled := False;
FTimer.Interval := DEF_BLENDING_INTERVAL;
UpdatePage;
ReleaseBitmap
end;
destructor T24NSDocumentPage.Destroy;
begin
FreeAndNil(FTimer);
FreeAndNil(FBitmap);
inherited Destroy
end;
procedure T24NSDocumentPage.PrereleaseBitmap;
begin
ResetTimer;
FBitmapRendered := False
end;
procedure T24NSDocumentPage.UpdatePage;
begin
with FEngine, FEngine.PDFLibrary do
GetPageSizeByIndex(Document, FIndex, FWidth, FHeight)
end;
procedure T24NSDocumentPage.ReleaseBitmap;
begin
FBitmapRendered := False;
FreeAndNil(FBitmap);
FBitmap := TBitmap.Create
end;
procedure T24NSDocumentPage.RenderBitmap(AWidth: Integer);
var
DisplayWidth: Integer;
DisplayHeight: Integer;
Page: TPDFPage;
begin
if not FBitmapRendered then
begin
Page := FEngine.PDFLibrary.LoadPage(FEngine.Document, FIndex);
try
FBitmap.Canvas.Lock;
try
DisplayWidth := AWidth;
DisplayHeight := RenderedHeight(DisplayWidth);
//FBitmap.SetSize(DisplayWidth, DisplayHeight);
FBitmap.Width := DisplayWidth;
FBitmap.Height := DisplayHeight;
FEngine.PDFLibrary.RenderPage(FBitmap.Canvas.Handle,
Page, 0, 0, DisplayWidth, DisplayHeight, 0, 0)
finally
FBitmap.Canvas.Unlock
end;
FBlendValue := 0;
FBitmapRendered := True;
Timer.Enabled := True
finally
FEngine.PDFLibrary.ClosePage(Page)
end
end
end;
function T24NSDocumentPage.RenderedHeight(AWidth: Integer): Integer;
begin
Result := Round(Height * (AWidth / Width))
end;
procedure T24NSDocumentPage.ResetTimer;
begin
FTimer.Enabled := False;
FBlendValue := 0
end;
procedure T24NSDocumentPage.TimerTick(Sender: TObject);
begin
Inc(FBlendValue, DEF_BLENDING_STEP);
if FBlendValue >= 255 then
ResetTimer;
FViewer.Invalidate
end;
{ T24NSHelperThread }
constructor T24NSHelperThread.Create(AViewer: T24NSPDFViewer);
begin
inherited Create(False);
Priority := tpLowest;
FViewer := AViewer;
FreeOnTerminate := False
end;
procedure T24NSHelperThread.WaitLooping;
begin
while not FMessageLoop do
SwitchToThread
end;
procedure T24NSHelperThread.Execute;
var
Msg: TMsg;
function HandleMessage: Boolean; near;
function NeedHandleMessage: Boolean; near;
begin
Result := (Msg.Message >= WM_DONETHREAD)
and (Msg.Message <= WM_DOWNLOADFILE)
end;
begin
Result := NeedHandleMessage;
if Result then
case Msg.Message of
WM_DONETHREAD:
Terminate;
WM_RELEASEBITMAP:
ReleaseBitmap(Msg);
WM_RENDERBITMAP:
RenderBitmap(Msg)
end
end;
function ProcessMessage: Boolean; near;
begin
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
Result := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
if Result then
begin
if not HandleMessage then
if not Terminated then
begin
TranslateMessage(Msg);
DispatchMessage(Msg)
end
end
end
else
Result := False
end;
begin
FMessageLoop := True;
try
while not Terminated do
if not ProcessMessage then
WaitMessage
finally
FMessageLoop := False
end
end;
procedure T24NSHelperThread.Invalidate;
begin
if FViewer.Owner is TWinControl then
TWinControl(FViewer.Owner).Invalidate
end;
procedure T24NSHelperThread.ReleaseBitmap;
begin
FViewer.Pages.Page(AMsg.wParam).ReleaseBitmap
end;
procedure T24NSHelperThread.RenderBitmap;
begin
while FViewer.Painting do
SwitchToThread;
FViewer.Pages.Page(AMsg.wParam).RenderBitmap(AMsg.lParam)
end;
procedure T24NSHelperThread.Done;
begin
if not Suspended and not Terminated then
PostThreadMessage(ThreadID, WM_DONETHREAD, 0, 0)
end;
end.
|