January 15, 2021, 06:33:06 PM

Author Topic: [bmx] Picture Viewer with scoll and zoom by WendellM [ 1+ years ago ]  (Read 464 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : Picture Viewer with scoll and zoom
Author : WendellM
Posted : 1+ years ago

Description : I wrote this as a prototype for a viewer of large (image-based) maps that can be easily scrolled and zoomed via mouse buttons/wheel.  As such, it has several techniques that might be useful when starting a similar project of your own.

It uses <a href="codearcs2404.html?code=1440" target="_blank">Tesuji's routines[/url] to divide a large image file up into smaller tiles to efficiently use video memory.  It also integrates a hooked redraw event within the main type rather than as a stand-alone function.


Code :
Code: BlitzMax
  1. Rem
  2.  
  3.         A sample picture viewer, mostly to explore type-enclosed event handling and
  4.         Tesuji's 256x256 tiled handling of large images.  Also an experiment of
  5.         mouse dragging and right-click popup menu (and mouse wheel) for scaling.
  6.        
  7.         by Wendell Martin, December 27, 2005
  8.  
  9. End Rem
  10.  
  11. Framework BRL.D3D7Max2D
  12. Import BRL.System
  13. Import BRL.FileSystem
  14. Import BRL.Pixmap
  15. Import BRL.MaxGUI
  16. Import BRL.Win32MaxGUI
  17.  
  18. Import BRL.PNGLoader
  19. Import BRL.BMPLoader
  20. Import BRL.JPGLoader
  21.  
  22. SetGraphicsDriver D3D7Max2DDriver()
  23.  
  24. AppTitle = "Picture Viewer (Drag with left mouse, zoom with wheel or right click)"
  25.  
  26.  
  27. ' Load an image and tile in 256x256 chunks:
  28.  
  29. Const FRAGSIZE = 256 ' maximum image fragment size
  30.  
  31. Local imageUrl:String
  32. Local pixmap:TPixmap
  33.  
  34. Local filter$="Picture Files (*.bmp,jpeg,jpg,png):bmp,jpeg,jpg,png;All Files:*"
  35. imageUrl = RequestFile( "Load Picture",filter$, False, CurrentDir()+"/" )
  36. pixmap:TPixmap = LoadPixmap(imageUrl)
  37. If pixmap = Null Then End ' user didn't choose an image, so quit
  38.  
  39. Global img:BigImage = BigImage.Create(pixmap)
  40.  
  41. img.scale = 1
  42.  
  43.  
  44. ' Set up window and viewer:
  45.  
  46. Local winW# = GadgetWidth( Desktop() ) * .75
  47. Local winH# = GadgetHeight( Desktop() ) * .75
  48. Local offsetX# = ( GadgetWidth( Desktop() ) - winW ) / 2.0
  49. Local offsetY# = ( GadgetHeight( Desktop() ) - winH ) / 2.0
  50. Local style = WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_CLIENTCOORDS ' ClientCoords for Maximize
  51.  
  52. Global Win:TGadget=CreateWindow( AppTitle, offsetX,offsetY, WinW,WinH, Null, style)
  53. SetMinWindowSize Win,200,200
  54.  
  55. Local Viewer:TViewer = New TViewer.create( 0,0, winW,winH, Win )
  56.  
  57. Local Quit:Int = False
  58.  
  59.  
  60. ' Main loop:
  61.  
  62. Repeat
  63.         WaitEvent()
  64.         Select EventSource()
  65.                 Case Win
  66.                         Select EventID()
  67.                                 Case EVENT_WINDOWCLOSE
  68.                                         Quit=True
  69.                         End Select
  70.         End Select
  71. Until Quit=True
  72. End
  73.  
  74.  
  75. Type TViewer
  76.  
  77.         Field  can:TGadget
  78.         Global drag
  79.         Global startx, starty
  80.         Global endx, endy
  81.         Field Popup_Gadget:TGadget
  82.         Field Popup_Menu:TGadget
  83.        
  84.         Method Create:TViewer( x,y, w,h, group:TGadget )
  85.                 can = CreateCanvas( x,y, w,h, group )
  86.                 SetGadgetLayout can, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED ' Lock the size
  87.                 Popup_Menu=CreateMenu( "", Null, Popup_Gadget )
  88.                 CreateMenu "10%", 10, popup_menu
  89.                 CreateMenu "25%", 25, popup_menu
  90.                 CreateMenu "50%", 50, popup_menu
  91.                 CreateMenu "75%", 75, popup_menu
  92.                 CreateMenu "100%", 100, popup_menu
  93.                 CreateMenu "150%", 150, popup_menu
  94.                 CreateMenu "200%", 200, popup_menu
  95.                 CreateMenu "400%", 400, popup_menu
  96.                 CreateMenu "1000%", 1000, popup_menu
  97.                 AddHook EmitEventHook, EventHook, Self
  98.                 Return Self
  99.         End Method
  100.        
  101.         Function EventHook:Object( id, data:Object, context:Object )
  102.                 If data <> Null Then Return TViewer(context).EventHandler( TEvent(data) )
  103.         End Function
  104.  
  105.         Method EventHandler:Object ( event:TEvent )
  106.                 If event.source = can And event.id = EVENT_GADGETPAINT Then
  107.                   SetGraphics CanvasGraphics(can)
  108.                   SetViewport 0,0,GadgetWidth(can),GadgetHeight(can)
  109.                 SetBlend maskblend
  110.                   Cls
  111.                         img.render
  112.                   Flip
  113.                 ElseIf event.id = EVENT_MOUSEDOWN
  114.                         If event.data = MOUSE_LEFT Then
  115.                                 drag = True
  116.                                 SetPointer POINTER_HAND
  117.                                 startx = event.x
  118.                                 starty = event.y
  119.                         ElseIf event.data = MOUSE_RIGHT Then
  120.                                 PopupWindowMenu( Win, popup_menu )
  121.                         EndIf
  122.                 ElseIf event.id = EVENT_MOUSEUP Then
  123.                         drag = False
  124.                         SetPointer POINTER_DEFAULT
  125.                 ElseIf drag And (event.id = EVENT_MOUSEMOVE) Then
  126.                         endx = event.x
  127.                         endy = event.y
  128.                         img.x :+ endx  - startx
  129.                         img.y :+ endy - starty
  130.                         startx = endx
  131.                         starty = endy
  132.                         Cls
  133.                         img.render
  134.                         Flip
  135.                 ElseIf event.id = EVENT_MOUSEWHEEL Then
  136.                         If event.data >0 Then
  137.                                 img.scale :* 1.1
  138.                                 If img.scale > 10 Then
  139.                                         img.scale = 10
  140.                                 Else
  141.                                         img.x :* 1.1
  142.                                         img.y :* 1.1
  143.                                 EndIf
  144.                         End If
  145.                         If event.data <0 Then
  146.                                 img.scale :/ 1.1
  147.                                 If img.scale < 0.1 Then
  148.                                         img.scale = 0.1
  149.                                 Else
  150.                                         img.x :/ 1.1
  151.                                         img.y :/ 1.1
  152.                                 EndIf
  153.                         EndIf
  154.                         Cls
  155.                         img.render
  156.                         Flip
  157.                 ElseIf event.id = EVENT_MENUACTION Then
  158.                         Local scale:Float = event.data / 100.0
  159.                         Local deltascale:Float = scale / img.scale
  160.                         img.scale :* deltascale
  161.                         img.x :* deltascale
  162.                         img.y :* deltascale
  163.                         Cls
  164.                         img.render
  165.                         Flip
  166.                 Else
  167.                         Return event ' not handled here, so pass along
  168.                 EndIf
  169.         End Method
  170.                        
  171. End Type
  172.  
  173.  
  174. ' Tesuji's tile functions below:
  175.  
  176. ' =============================
  177. ' Image Fragment
  178. ' =============================
  179.  
  180. Type ImageFragment
  181.  
  182.     Field img:TImage
  183.     Field x,y
  184.     Field rotation:Float = 0
  185.     Field angle:Double
  186.     Field distance:Double
  187.  
  188.     ' ----------------------------------
  189.     ' constructor
  190.     ' ----------------------------------
  191.     Function create:ImageFragment(pmap:TPixmap,x:Float,y:Float,w,h)
  192.    
  193.         Local frag:ImageFragment = New ImageFragment
  194.         frag.img = LoadImage(PixmapWindow(pmap,x,y,w,h),0|FILTEREDIMAGE)
  195.         x = (pmap.width*.5) - x
  196.         y = (pmap.height*.5) - y
  197.         frag.x = x
  198.         frag.y = y
  199.         frag.angle = ATan2(y,x)-180
  200.         frag.distance = Sqr(x*x + y*y)
  201.  
  202.         Return frag
  203.  
  204.     End Function
  205.  
  206.     ' --------------------
  207.     ' Draw individual tile
  208.     ' --------------------
  209.     Method render(scale:Float,xoff:Float=0,yoff:Float=0,rot:Float=0)
  210.  
  211.         SetRotation rot
  212.         Local d:Float = Self.distance*scale
  213.         SetScale(scale,scale)
  214.         DrawImage(Self.img,(Cos(rot+Self.angle)*d)+xoff,(Sin(rot+Self.angle)*d)+yoff )
  215.  
  216.     End Method
  217.  
  218.  
  219. End Type
  220.  
  221.  
  222. ' ==================================
  223. ' Big Image
  224. ' ==================================
  225.  
  226. Type BigImage
  227.  
  228.     Field pixmap:TPixmap
  229.     Field px,py
  230.     Field fragments:TList
  231.     Field scale:Float = 1
  232.     Field width
  233.     Field height
  234.     Field x:Float = 0
  235.     Field y:Float = 0
  236.     Field rotation:Float = 0
  237.  
  238.     ' ----------------------------------
  239.     ' constructor
  240.     ' ----------------------------------
  241.     Function create:BigImage(p:TPixmap)
  242.  
  243.         Local bi:BigImage = New BigImage
  244.         bi.pixmap = p
  245.         bi.width = p.width
  246.         bi.height = p.height
  247.         bi.fragments = CreateList()
  248.         bi.load()
  249.  
  250.         Return bi
  251.  
  252.     End Function
  253.  
  254.     ' -------------------------------------
  255.     ' convert pixmap into image fragments
  256.     ' -------------------------------------
  257.     Method load()
  258.  
  259.         Local px = 0
  260.         Local py = 0
  261.         Local loading = True
  262.  
  263.         While (loading)
  264.  
  265.             'FlushMem
  266.             Local w = FRAGSIZE
  267.             If Self.pixmap.width - px < FRAGSIZE w = Self.pixmap.width - px
  268.             Local h = FRAGSIZE
  269.             If Self.pixmap.height - py < FRAGSIZE h = Self.pixmap.height - py
  270.             Local f1:ImageFragment = ImageFragment.create(Self.pixmap,px,py,w,h)
  271.             ListAddLast Self.fragments,f1
  272.             px:+FRAGSIZE
  273.             If px >= Self.pixmap.width
  274.                 px = 0
  275.                 py:+FRAGSIZE
  276.                 If py >= Self.pixmap.height loading = False
  277.             End If
  278.        
  279.         Wend
  280.  
  281.     End Method
  282.  
  283.     ' -----------------
  284.     ' Draw entire image
  285.     ' -----------------
  286.     Method render()
  287.  
  288.         SetOrigin(GraphicsWidth()*.5,GraphicsHeight()*.5)
  289.         For Local f:ImageFragment = EachIn Self.fragments
  290.             f.render(Self.scale,Self.x,Self.y,Self.rotation)
  291.         Next
  292.         SetOrigin(0,0)
  293.  
  294.     End Method
  295.  
  296. End Type


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal