Recent

Author Topic: PrintViewer  (Read 15213 times)

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: PrintViewer
« Reply #30 on: September 09, 2016, 04:42:21 am »
Rick, it is delightful to see that image. Thanks for sharing.

I tested this with an inline image. It showed the image, but there still isn't a way to save the image with the file.

I suggest that you create another thread if you are still looking for a solution to save/load the images with files.

It basically needs an interface. Specifically IRichEditOleCallback interface. You pass an instance to the rich edit using EM_SETOLECALLBACK message.

For reading images it needs two functions implemented GetNewStorage and QueryInsertObject. One is to allocate space for the parsed images, while the other is to ask if you want to show the image. The rest of the interface functions can return E_NOTIMPL.

As for writing, I just tested EM_STREAMOUT. It embedded the image in the file successfully.
« Last Edit: September 09, 2016, 05:25:53 am by engkin »

rick2691

  • Sr. Member
  • ****
  • Posts: 375
Re: PrintViewer
« Reply #31 on: September 09, 2016, 03:41:50 pm »
engkin,

Thanks for the information. It should get me started. I will start a new post after I have worked with it a little.

Currently, I have have employed a more flexible method for accessing pages. I build a PageMap at the start. It is a string that has encoded markers. I am an old LISP programmer.

I have also switched to TBitBtn's and a panel that can be shifted to center page when zooming. As is, everything is pretty much worked out, except for printing by page selection.

Code: Pascal  [Select]
  1. // globals
  2. var cpMin, PixH, PixW: longint;
  3.     ViewScale: double;
  4.     dc: THandle;
  5.     fr: TFormatRange;
  6.     ox, oy, w, h: LongInt;
  7.     MorePages: boolean;
  8.     PageMap: widestring;
  9.     PgCnt, PgSum: integer;
  10.  
  11. function XPixToTwips(px: integer): integer;
  12. var
  13.   dc: THandle;
  14. begin
  15.   dc:= GetDC(HWND_DESKTOP);
  16.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSX));
  17.   ReleaseDC(HWND_DESKTOP, dc);
  18. end;
  19.  
  20. function YPixToTwips(px: integer): integer;
  21. var
  22.   dc: THandle;
  23. begin
  24.   dc:= GetDC(HWND_DESKTOP);
  25.   Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSY));
  26.   ReleaseDC(HWND_DESKTOP, dc);
  27. end;
  28.  
  29. procedure TCmdForm.SetupViewPage(BegPos, EndPos: longint);
  30. begin
  31.   // clear the image canvas
  32.   TextArea.Canvas.Brush.Color:= clWindow;
  33.   TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
  34.   TextArea.Canvas.MoveTo(0, 0);
  35.  
  36.   // set the printing metrics
  37.   dc:= TextArea.Canvas.Handle;
  38.   ox:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETX);
  39.   oy:= 0;  //GetDeviceCaps(dc, PHYSICALOFFSETY);
  40.   w:= XPixToTwips(Round(PixW * ViewScale));  //GetDeviceCaps(dc, PHYSICALWIDTH);
  41.   h:= YPixToTwips(Round(PixH * ViewScale));  //GetDeviceCaps(dc, PHYSICALHEIGHT);
  42.   FillChar(fr, SizeOf(TFormatRange), 0);
  43.   fr.hdc:= dc;       // fr._hdc:= dc; **on some systems**
  44.   fr.hdcTarget:= dc;
  45.   fr.rc.Left:= ox;
  46.   fr.rc.Right:= ox+w;
  47.   fr.rc.Top:= oy;
  48.   fr.rc.Bottom:= oy+h;
  49.   fr.chrg.cpMin:= BegPos; // set to 0 for start of document
  50.   fr.chrg.cpMax:= EndPos; // set to -1 for end of document
  51.  
  52.   // get document content
  53.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  54.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
  55.   SendMessage(PageMemo.Handle, EM_SETSEL, BegPos, EndPos);  // select to end of document
  56.   SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg));  // copy selection
  57.   SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0);  // reset to no selection
  58.   SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
  59. end;
  60.  
  61. procedure TCmdForm.CountPages;
  62. var x,p: longint;
  63. begin
  64. // get total page count
  65.   SetupViewPage(0, -1);
  66.   cpMin:= 0; PgSum:= 0; p:= 0; MorePages:= true; PageMap:= '';
  67.   while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
  68.         begin
  69.         SetupViewPage(cpMin, -1);
  70.         p:= p + 1;
  71.         PageMap:= '#'+IntToStr(p)+':'+IntToStr(cpMin)+','+PageMap;
  72.         cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  73.         SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  74.         fr.chrg.cpMin:= cpMin;
  75.         PgSum:= PgSum + 1;
  76.         if (fr.chrg.cpMin=fr.chrg.cpMax)
  77.            then MorePages:= false;
  78.         end;
  79.   PageMap:= '*'+IntToStr(p)+':'+IntToStr(cpMin)+','+PageMap; // end + 1
  80.   for x:=1 to PgSum do ViewPageList.Items.Add(IntToStr(x));
  81. end;
  82.  
  83. procedure TCmdForm.ConfigureView;
  84. var
  85.   PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH: double;
  86. begin
  87.   // define paper size... these 6 can be global for paper size and display
  88.   PgWide:= 8.5; PgHigh:= 11.0;  // US Letter Size
  89.   PgLft:= 1.0; PgRht:= 1.0;
  90.   PgTop:= 1.0; PgBtm:= 1.0;
  91.  
  92.   // setup the PaperArea metrics
  93.   PaperArea.top:= 0;  // 0 or 40 fits my layout
  94.   PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
  95.   PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
  96.   PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2);  // centering view page
  97.   if PaperArea.left<0 then PaperArea.left:= 0;
  98.  
  99.   // setup the TextArea metrics
  100.   InchH:= PgHigh - PgTop - PgBtm;
  101.   InchW:= PgWide - PgLft - PgRht;
  102.   PixH:= Round(InchH * Screen.PixelsPerInch / ViewScale);
  103.   PixW:= Round(InchW * Screen.PixelsPerInch / ViewScale);
  104.  
  105.   // setup the TextArea position
  106.   TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
  107.   TextArea.height:= PixH;
  108.   TextArea.width:= PixW;
  109.   TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
  110.   TextArea.Picture.Bitmap.SetSize(Round(PixW * ViewScale), Round(PixH * ViewScale));
  111. end;
  112.  
  113. procedure TCmdForm.GetPageMap;
  114. var PgSel,GetStr: string;
  115.     x,s: integer;
  116. begin
  117.   PgSel:= IntToStr(PgCnt);
  118.   GetStr:= '#'+PgSel+':';
  119.   x:= pos(GetStr,PageMap);
  120.   s:= length(PageMap);
  121.   if x>0 then
  122.      begin
  123.      GetStr:= copy(PageMap,x,s-x+1);
  124.      x:= pos(':',GetStr);
  125.      delete(GetStr,1,x);
  126.      x:= pos(',',GetStr);
  127.      GetStr:= copy(GetStr,1,x-1);
  128.      cpMin:= StrToInt(GetStr);
  129.      end;
  130. end;
  131.  
  132. procedure TCmdForm.btnViewPagesClick(Sender: TObject);
  133. begin
  134.   PaperArea.visible:= true;
  135.   ScrollView.visible:= true;
  136.   SetupViewPage(0, -1);
  137.   PostFirstPage;
  138. end;
  139.  
  140. procedure TCmdForm.btnViewZoomClick(Sender: TObject);
  141. begin
  142.   if ViewScale>1.5           // zoom toggle between full and half
  143.      then ViewScale:= 1.0
  144.      else ViewScale:= 2.0;
  145.   ConfigureView;
  146.   NavPanel.left:= Round((PaperArea.width - NavPanel.width) / 2);
  147. end;
  148.  
  149. procedure TCmdForm.btnViewBegClick(Sender: TObject);
  150. var PgSel,GetStr: string;
  151.     x,s: integer;
  152. begin
  153.   PgCnt:= 1;
  154.   GetPageMap;
  155.   PostNewPage;
  156. end;
  157.  
  158. procedure TCmdForm.btnViewEndClick(Sender: TObject);
  159. var PgSel,GetStr: string;
  160.     x,s: integer;
  161. begin
  162.   PgCnt:= PgSum;
  163.   GetPageMap;
  164.   PostNewPage;
  165. end;
  166.  
  167. procedure TCmdForm.btnViewPrtClick(Sender: TObject);
  168. begin
  169.   // no built
  170. end;
  171.  
  172. procedure TCmdForm.btnViewBckClick(Sender: TObject);
  173. var PgSel,GetStr: string;
  174.     x,s: integer;
  175. begin
  176.   PgCnt:= PgCnt - 1;
  177.   if PgCnt<1 then PgCnt:= 1;
  178.   GetPageMap;
  179.   PostNewPage;
  180. end;
  181.  
  182. procedure TCmdForm.btnViewNxtClick(Sender: TObject);
  183.  
  184. begin
  185.   PgCnt:= PgCnt + 1;
  186.   if PgCnt>PgSum then PgCnt:= PgSum;
  187.   GetPageMap;
  188.   PostNewPage;
  189. end;
  190.  
  191. procedure TCmdForm.btnViewQuitClick(Sender: TObject);
  192. begin
  193.   // clean up
  194.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  195.   if MorePages
  196.      then EndDoc(fr.hdc) // close EM_FORMATRANGE
  197.      else AbortDoc(fr.hdc);
  198.   TextArea.Picture.Bitmap.Canvas.Changed;  // reset image event
  199.   PaperArea.visible:= false;
  200.   ScrollView.visible:= false;
  201. end;
  202.  
  203. procedure TCmdForm.ViewPageListEditingDone(Sender: TObject);
  204. begin
  205.   ViewPageListSelect(self)
  206. end;
  207.  
  208. procedure TCmdForm.ViewPageListSelect(Sender: TObject);
  209. var PgSel,GetStr: string;
  210.     x,s,p: integer;
  211. begin
  212.   PgSel:= ViewPageList.Text;
  213.   PgCnt:= StrToInt(PgSel);
  214.   GetPageMap;
  215.   PostNewPage;
  216. end;
  217.  
  218. procedure TCmdForm.PostNewPage;
  219. var PgStr: string;
  220. begin
  221.   SetupViewPage(cpMin, -1);
  222.   cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  223.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  224.   fr.chrg.cpMin:= cpMin;
  225.  
  226.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  227.   PgStr:= PgStr+IntToStr(PgSum);
  228.   PageMonitor.caption:= PgStr;
  229. end;
  230.  
  231. procedure TCmdForm.PostFirstPage;
  232. var
  233.   PgStr: string;
  234. begin
  235.   ViewScale:= 2.0; // display size: 0.5=double, 1.0=full, 2.0=half
  236.   ConfigureView;
  237.   CountPages;
  238.  
  239.   MorePages:= true;
  240.   cpMin:= 0;
  241.   SetupViewPage(cpMin, -1);
  242.   cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
  243.   SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
  244.   fr.chrg.cpMin:= cpMin;  // set to start of next page
  245.  
  246.   PgCnt:= 1;
  247.   PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
  248.   PgStr:= PgStr+IntToStr(PgSum);
  249.   PageMonitor.caption:= PgStr;
  250.   ViewPageList.Text:= '1';
  251. end;
  252.  

Thanks for all your help, and the same to others who have contributed.

Rick
Windows 10, LAZ 1.6.4, FPC 3.0.2, SVN 54278, i386-win32-win32/win64, forms use windows unit