程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 圖像放大漫游攻略

圖像放大漫游攻略

編輯:Delphi

 我想大家應該都用過 ACDSee 或者 Windows XP,它們都支持圖像的放大和漫游,雖然網上也有相關的資料,但是都不是很全面,今天我給大家介紹一種方法,由於篇幅的關系,主要講如何實現,盡量做到言簡意赅,好了,我們現在就開始。
  說明:
  1.本文使用 Object pascal 進行描述,請讀者自行轉換為相關的代碼,作者盡量做到與代碼無關
  2.涉及到圖像操作,盡量使用 Windows API 和位操作

  
  理論篇:
  關鍵詞:
  繪圖區-即窗口顯示圖像的區域,亦可為全屏幕(在全屏幕下繪圖的效果比一般窗口下好)
  中心點-即要繪圖區顯示的中心點在原始圖像的坐標(聲明:這個概念特別重要)

  先說說圖像的放大,要放大一張圖片,我們一般的做法是直接放大圖像,但本文介紹的方法僅放大我們能夠看到的部分,放大分兩種情況,一種是放大後比繪圖區還要小,這種情況沒什麼好說,當然是顯示全部的圖像;第二種是放大後的圖像比繪圖區大,這才是我們今天要討論的重點話題,這種情況下我們先要確定圖像放大後的大小,然後根據“中心點”計算在原始圖像的位置和大小,最後把截取的圖像放大到繪圖區。
  再說說圖像的漫游,當顯示的圖像超過繪圖區時,我們需要對圖像進行漫游,以便看到全部的圖像。原理是:當鼠標在繪圖區進行單擊時,這時開始漫游,先記錄鼠標的單擊位置,然後檢測鼠標的移動,根據鼠標和上次的位移計算出“中心點”(需要將屏幕坐標轉換為原始圖像坐標),根據在上面放大的原理到原始圖像中取出要顯示的部分,放大顯示到繪圖區。

  算法實現篇:
  1.圖像放大
  變量定義:
  PZoom:放大率(整數:100時為100%,根據需要可以將 100 該為 10000 或者更大些,但不推薦使用浮點數)
  a,b:中心點
  w,h:要截取原始圖像的寬和高
  x,y:要截取的位置(左上角)
  sw,sh:原始圖像的寬和高
  p1,p2:放大比例
  aw,ah:放大後圖像的大小
  pw,ph:繪圖區大小
  vx,vy:在繪圖區顯示的位置(左上角)
  vw,vh:在繪圖區顯示的大小
  ptx,pty:臨時變量

  已知的變量:PZoom,(a,b),(sw,sh),(p1,p2),(aw,ah),(pw,ph)
  要計算的變量:(x,y),(w,h),(vx,vy),(vw,vh)
  開始計算:
  aw=Round(PZoom*sw/100);
  ah=Round(PZoom*sh/100);
  p1=aw/pw
  p2=ah/ph
  // 注:Round 用於取整,如其他語言的Int(),Fix()等
  if p1>1 then w=Round(sw/p1) else w=sw
  if p2>1 then h=Round(sh/p2) else h=sh
  // 注:shr 為右移運算符,可以使用“>>1”、“div 2”、“2”或“Round(w/2)”代替
  x=a-w shr 1
  y=b-h shr 1

  // 注:div 為整除運算符
  ptx=(w*PZoom) div 100
  pty=(h*PZoom) div 100

  // 以下計算在繪圖區顯示的圖像大小和位置
  變量
      Pencent:double;  // 縮放比
      wx:double;       // 寬縮放比
      hx:double;       // 高縮放比

      // 獲得縮放比
      wx:=pw/ptx
      hx:=ph/pty
      if wx>hx then Pencent:=hx
      else          Pencent:=wx;

      // 獲得圖片最後的大小
      vw:=Round(Pencent*ptx);
      vh:=Round(Pencent*pty);

      // 計算出圖片的位置
      vx:=(pw-vw) div 2;
      vy:=(ph-vh) div 2;
  // ------------------------------------

  好了,兩個重要的任務完成(x,y),(w,h),(vx,vy),(vw,vh)已經全部計算得出,下面的工作就是顯示了,我們選擇 Windows API 進行操作
  // 以下顯示圖像 -----------------------
  變量
  sDC 為原始圖片的設備句柄(DC)
  tDC 為臨時設備句柄
  dDC 最終設備句柄

  BitBlt(tDC,0,0,w,h,sDC,0,0,SRCCOPY);
  SetStretchBltMode(dDC,STRETCH_DELETESCANS);
  StretchBlt(dDC,0,0,vw,vh,tDC,0,0,w,h,SRCCOPY);

  最後繪制到顯示的區域即可:
  例如:BitBlt(GetDC(0),vx,vy,vx+vw,xy+vh,dDC,0,0,SRCCOPY);
  // ------------------------------------

  2.圖像漫游
  先定義三個全局變量:
  FBeginDragPoint   :TPoint;         // 記錄鼠標開始拖動的位置
  FBeginDragSBPoint :TPoint;         // 記錄“中心點”位置
  FBeginDrag        :boolean;        // 是否已經開始“拖動”
  a,b               :integer;        // “中心點”位置

  在鼠標左鍵點擊時,記錄鼠標的位置和“中心點”的位置,同時設置 FBeginDrag 為真
  當鼠標右鍵彈起時,設置 FBeginDrag 為假
  鼠標移動時,判斷 FBeginDrag ,如果為假不進行處理,如果為真進行下面處理:
  假設 X,Y 為鼠標當前的位置
  a=FBeginDragPoint.X-((X-FBeginDragPoint.X)*100) div PZoom
  b=FBeginDragPoint.Y-((Y-FBeginDragPoint.Y)*100) div PZoom

  最後使用上面介紹的圖像放大顯示出圖像

  技巧篇:
  1.如果圖像較大,使用 Delphi 的 位圖對象會出現內存溢出錯誤,這時可以進行如下設置:
      bitImage:=TBitmap.Create;
      bitImage.PixelFormat:=pf24bit;
      bitImage.ReleaseHandle;
  2.如果要讓圖像自動適應窗口的大小,參考以下代碼:
  var
      p1,p2       :double;
  begin
      p1:=pw/sw;
      p2:=ph/sw;
      if p1>p2 then PZoom:=Round(p2*100)
      else          PZoom:=Round(p1*100);
      if PZoom=0 then PZoom:=100;
  end;
  3.要想讓圖像的效果好,最好在全屏幕方式下進行
  該方法為“Crazy Marker”所用,如果讀者有興趣可以看看效果

  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved