Xombie's Puny Picture Previewer

Share your advanced PureBasic knowledge/code with the community.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Xombie's Puny Picture Previewer

Post by Xombie »

Code updated For 5.20+

So there I am, reading some manga (English translated, naturally) when I finally got tired of Microsoft's little picture and fax viewer program. I wanted my mouse wheel to change images! Like Acdsee will do. Simple, right? But I didn't want to use acdsee, either. Much too heavy for what I wanted. So... I took it upon myself to knock this little program out. Took a few hours since I haven't done this kind of thing before.

This is mainly meant for me. It's really basic in it's functionality. You can drag a picture to it (bmp, jpg, png) and it will open that picture using it's directory as the image directory. You can then use the mouse wheel to scroll through the pictures. I have it associated with jpgs & pngs so I just have to double-click the files and it will open the file using it's directory.

You also have a little right-click menu to pick between some basic sizing options and such. If the image is larger than the window you can click down in the image and move it around a little bit.

Hitting the escape key will close the program.

That's it :) I'm really serious when I said this whole thing was done all in one go rather quickly. Nothing that great but maybe like the scrolling text thingie it will provide an example for other code.

Code: Select all

Enumeration
  #WindowMain
EndEnumeration
Enumeration
  ;
  #MenuOptions
  #MenuOpen
  #MenuFitWidth
  #MenuFitHeight
  #MenuFitImage
  #MenuFitActual
  #MenuSmoothResize
  ;
  #MenuEscape
  ;
EndEnumeration
Enumeration
  #ImageMain
EndEnumeration
;- Structures
Structure s_HoldFiles
  Named.s
  File.s
  Extension.s
EndStructure
;- Global Variables
Global fHandleImage
Global fHandlePartial
Global fMainCurrentIndex
Global fMainCurrentDirectory.s
Global NewList fMainImages.s_HoldFiles()
;
Global fMainWidth : Global fMainHeight
;
Global fMainIsClipped.b
Global fMainMouseDown.POINT
Global fMainOffset.POINT
Global FMainDoFitWidth.b
Global fMainDoFitHeight.b
Global fMainDoFitImage.b
Global fMainDoFitActual.b
Global fMainDoSmoothResize.b
;
;- Procedures
Procedure fMainLoadImage(IndexImage, ReLoad.b, ResetOffset.b)
  ;

  ;
  fMainIsClipped = #False
  ;
  IsUsingPartial.b
  ;
  If ResetOffset : fMainOffset\X = 0 : fMainOffset\Y = 0 : EndIf
  ;
  If ListSize(fMainImages()) = 0 : ProcedureReturn : EndIf
  ;
  SelectElement(fMainImages(), fMainCurrentIndex)
  ;
  If ReLoad
    ;
    If fHandleImage : FreeImage(fHandleImage) : EndIf
    ;
    fHandleImage = LoadImage(#PB_Any, fMainCurrentDirectory+fMainImages()\Named)
    ;
  EndIf
  ;
  If fHandleImage
    ;
    ;           UseImage()
    ;
    If FMainDoFitWidth
      ;
      If ImageWidth(fHandleImage) > fMainWidth
        ;
        HoldWidth = fMainWidth
        ;
        HoldHeight = Int(ImageHeight(fHandleImage) / (ImageWidth(fHandleImage) / HoldWidth))
        ;
      Else
        ;
        HoldWidth = ImageWidth(fHandleImage) : HoldHeight = ImageHeight(fHandleImage)
        ;
      EndIf
      ;
      If HoldHeight > fMainHeight : fMainIsClipped = #True : EndIf
      ;
      If fMainDoSmoothResize
        ResizeImage(fHandleImage, HoldWidth, HoldHeight)
      Else
        ResizeImage(fHandleImage, HoldWidth, HoldHeight, #PB_Image_Raw)
      EndIf
      ;
    ElseIf fMainDoFitHeight
      ;
      If ImageHeight(fHandleImage) > fMainHeight
        ;
        HoldHeight = fMainHeight
        ;
        HoldWidth = Int(ImageWidth(fHandleImage) / (ImageHeight(fHandleImage) / HoldHeight))
        ;
      Else
        ;
        HoldWidth = ImageWidth(fHandleImage) : HoldHeight = ImageHeight(fHandleImage)
        ;
      EndIf
      ;
      If HoldWidth > fMainWidth : fMainIsClipped = #True : EndIf
      ;
      If fMainDoSmoothResize
        ResizeImage(fHandleImage, HoldWidth, HoldHeight)
      Else
        ResizeImage(fHandleImage, HoldWidth, HoldHeight, #PB_Image_Raw)
      EndIf
      ;
    ElseIf fMainDoFitImage
      ;
      If ImageWidth(fHandleImage) > fMainWidth Or ImageHeight(fHandleImage) > fMainHeight
        ;
        If fMainDoSmoothResize
          ResizeImage(fHandleImage, HoldWidth, HoldHeight)
        Else
          ResizeImage(fHandleImage, HoldWidth, HoldHeight, #PB_Image_Raw)
        EndIf
        ;
      Else
        ;
        If fMainDoSmoothResize
          ResizeImage(fHandleImage, ImageWidth(fHandleImage), ImageHeight(fHandleImage))
        Else
          ResizeImage(fHandleImage, ImageWidth(fHandleImage), ImageHeight(fHandleImage), #PB_Image_Raw)
        EndIf
        ;
      EndIf
      ;
    ElseIf fMainDoFitActual
      ;
      HoldWidth = ImageWidth(fHandleImage)
      ;
      HoldHeight = ImageHeight(fHandleImage)
      ;
      If HoldHeight > fMainHeight Or HoldWidth > fMainWidth : fMainIsClipped = #True : EndIf
      ;
      If fMainDoSmoothResize
        ResizeImage(fHandleImage, HoldWidth, HoldHeight)
      Else
        ResizeImage(fHandleImage, HoldWidth, HoldHeight, #PB_Image_Raw)
      EndIf
      ;
    EndIf
    ;
    If fMainOffset\X Or fMainOffset\Y
      ;
      IsUsingPartial = #True
      ;
      If fHandlePartial : FreeImage(fHandlePartial) : EndIf
      ;
      fHandlePartial = GrabImage(fHandleImage, #PB_Any, fMainOffset\X, fMainOffset\Y, ImageWidth(fHandleImage) - fMainOffset\X, ImageHeight(fHandleImage) - fMainOffset\Y)
      ;
    EndIf
    ;
    SetGadgetState(#ImageMain, ImageID(fHandleImage))
    ;
    If IsUsingPartial : ImageID(fHandleImage) : EndIf
    ;
    SetWindowTitle(#WindowMain, "Xombie's Puny Picture Previewer - "+fMainCurrentDirectory+fMainImages()\Named)
    ;
    fMainCurrentIndex = ListIndex(fMainImages())
    ;
  EndIf
  ;
EndProcedure
Procedure fMainDisplayParameter(inFile.s)
  ;
  If inFile = ""
    ;
    HoldString.s = LCase(ProgramParameter())
    ;
    HoldString = GetFilePart(HoldString)
    ;
  Else
    ;
    HoldString = LCase(inFile)
    ;
  EndIf
  ;
  If ListSize(fMainImages()) > 0
    ; The passed file must be a valid graphic file in the current directory.
    ResetList(fMainImages())
    ;
    While NextElement(fMainImages())
      ;
      If LCase(fMainImages()\File) = HoldString
        ; The passed file is one we can load.
        fMainCurrentIndex = ListIndex(fMainImages())
        ;
        fMainLoadImage(fMainCurrentIndex, #True, #True)
        ;
        ProcedureReturn
        ;
      EndIf
      ;
    Wend
    ;
  EndIf
  ;
  fMainLoadImage(0, #True, #True)
  ;
EndProcedure
Procedure fMainFillFiles(InDirectory.s)
  ;
  HoldFile.s
  ;

  ;
  HoldExtension.s
  ;
  fMainCurrentIndex = 0
  ;
  ClearList(fMainImages())
  ;
  If ExamineDirectory(0, InDirectory, "*.*")
    ;
    HoldType = NextDirectoryEntry(0)
    ;
    While HoldType
      ;
      HoldFile = DirectoryEntryName(0)
      ;
      If HoldType = 1
        ; Make sure it's a file and not a directory.
        HoldExtension = LCase(GetExtensionPart(DirectoryEntryName(0)))
        ;
        If HoldExtension = "bmp" Or HoldExtension = "jpg" Or HoldExtension = "png"
          ;
          AddElement(fMainImages())
          ;
          fMainImages()\Named = GetFilePart(HoldFile)
          fMainImages()\File = HoldFile
          fMainImages()\Extension = HoldExtension
          ;
        EndIf
        ;
      EndIf
      ;
      HoldType = NextDirectoryEntry(0)
      ;
    Wend
    ;
    If ListSize(fMainImages()) > 1 : SortStructuredList(fMainImages(), 0, 0, #PB_String) : EndIf
    ;
  EndIf
  ;
EndProcedure
;- Callbacks
Procedure WindowCallback(HandleWindow, Message, wParam, lParam)
  ; Main form callback procedure.
  DoRedraw.b
  ;
  IsMouseDown.b
  ;
  HoldPosition.POINT
  ;
  lResult = #PB_ProcessPureBasicEvents
  ;
  If GetAsyncKeyState_(#VK_LBUTTON) = 32768
    IsMouseDown = #True
  Else
    IsMouseDown = #False
    fMainMouseDown\X = 0
    fMainMouseDown\Y = 0
  EndIf
  ;
  If Message = #WM_SETCURSOR
    ;
    If wParam = GadgetID(#ImageMain)
      ;
      If lParam >> 16 & $FFFF = 512
        ;
        If IsMouseDown And fMainIsClipped And fHandleImage
          ;
          GetCursorPos_(@HoldPosition)
          ;
          MapWindowPoints_(0, wParam, @HoldPosition, 1)
          ;
          If HoldPosition\X > fMainMouseDown\X
            ; Pulling the image right.
            If fMainOffset\X > 0
              ;
              If fMainOffset\X > 1 : fMainOffset\X - 2 : Else : fMainOffset\X = 0 : EndIf
              ;
              DoRedraw = #True
              ;
            EndIf
            ;
          ElseIf HoldPosition\X < fMainMouseDown\X
            ; Pulling the image left.
            If fMainOffset\X < ImageWidth(fHandleImage) - fMainWidth
              ;
              If ImageWidth(fHandleImage) - fMainWidth > 1 : fMainOffset\X + 2 : Else : fMainOffset\X = ImageWidth(fHandleImage) - fMainWidth : EndIf
              ;
              DoRedraw = #True
              ;
            EndIf
            ;
          EndIf
          ;
          If HoldPosition\Y > fMainMouseDown\Y
            ; Pulling the image down.
            If fMainOffset\Y > 0
              ;
              If fMainOffset\Y > 1 : fMainOffset\Y - 2 : Else : fMainOffset\Y = 0 : EndIf
              ;
              DoRedraw = #True
              ;
            EndIf
            ;
          ElseIf HoldPosition\Y < fMainMouseDown\Y
            ; Pushing the image up.
            If fMainOffset\Y < ImageHeight(fHandleImage) - fMainHeight
              ;
              If ImageHeight(fHandleImage) - fMainHeight > 1 : fMainOffset\Y + 2 : Else : fMainOffset\Y = ImageHeight(fHandleImage) - fMainHeight : EndIf
              ;
              DoRedraw = #True
              ;
            EndIf
            ;
          EndIf
          ;
          If DoRedraw : fMainLoadImage(fMainCurrentIndex, #False, #False) : fMainMouseDown\X = HoldPosition\X : fMainMouseDown\Y = HoldPosition\Y : EndIf
          ;
        EndIf
        ;
      ElseIf lParam >> 16 & $FFFF = 513
        ; Mouse is down.
        GetCursorPos_(@fMainMouseDown)
        ;
        MapWindowPoints_(0, wParam, @fMainMouseDown, 1)
        ;
      EndIf
      ;
    EndIf
    ;
  ElseIf Message = #WM_MOUSEWHEEL
    ;
    If wParam / 65536 > 0
      ;
      If fMainCurrentIndex > 0
        ;
        fMainCurrentIndex - 1
        ;
        fMainLoadImage(fMainCurrentIndex, #True, #True)
        ;
      EndIf
      ;
    Else
      ;
      If fMainCurrentIndex < ListSize(fMainImages()) - 1
        ; Adjust for 0 based list count.
        fMainCurrentIndex + 1
        ;
        fMainLoadImage(fMainCurrentIndex, #True, #True)
        ;
      EndIf
      ;
    EndIf
    ;
  EndIf
  ;
  ProcedureReturn lResult
  ;
EndProcedure
;- Program Start

; Variable to hold the window message.
DoQuit.b
; Variable to control whether we quit the window or not.  Automatically set to #False.

;
If OpenWindow(#WindowMain, 0, 0, 500, 600, "Xombie's Puny Picture Previewer", #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered | #PB_Window_TitleBar | #PB_Window_SizeGadget)
  ; Create the main window.
  
  ;
  ;           AdvancedGadgetEvents(#True)
  ; Enable advanced gadget events.
  ImageGadget(#ImageMain, 0, 0, WindowWidth(#WindowMain), WindowHeight(#WindowMain), 0)
  ;
  UseJPEGImageDecoder()
  ;
  UsePNGImageDecoder()
  ;
  
  fMainWidth = GadgetWidth(#ImageMain) : fMainHeight = GadgetHeight(#ImageMain)
  ;
  If CreatePopupMenu(#MenuOptions)
    ;
    MenuItem(#MenuOpen, "Open Directory...")
    MenuBar()
    ;
    FMainDoFitWidth = #True
    MenuItem(#MenuFitWidth, "Fit Image To Window Width")
    SetMenuItemState(#MenuOptions, #MenuFitWidth, #True)
    ;
    MenuItem(#MenuFitHeight, "Fit Image To Window Height")
    SetMenuItemState(#MenuOptions, #MenuFitHeight, #False)
    ;
    MenuItem(#MenuFitImage, "Fit Image To Window")
    SetMenuItemState(#MenuOptions, #MenuFitImage, #False)
    ;
    MenuItem(#MenuFitActual, "Display Actual Size")
    SetMenuItemState(#MenuOptions, #MenuFitImage, #False)
    ;
    MenuBar()
    MenuItem(#MenuSmoothResize, "Use Smooth Resize")
    SetMenuItemState(#MenuOptions, #MenuSmoothResize, #False)
    ;
  EndIf
  ;
  AddKeyboardShortcut(#WindowMain, #PB_Shortcut_Escape, #MenuEscape)
  ;
  SetWindowCallback(@WindowCallback())
  ; Set the main window callback.
  HoldString.s = ProgramParameter()
  ;
  If HoldString <> ""
    fMainCurrentDirectory = GetPathPart(HoldString)
    fMainFillFiles(fMainCurrentDirectory)
    fMainDisplayParameter("")
  Else
    HoldString.s = Space(999) : GetModuleFileName_(0, @HoldString, 999) : fMainCurrentDirectory=GetPathPart(HoldString)
    fMainFillFiles(fMainCurrentDirectory)
    fMainLoadImage(0, #True, #True)
  EndIf
  ;
  Repeat
    ;
    ;{ Event Loop
    EventID = WaitWindowEvent()
    ;
    If EventID = #PB_Event_CloseWindow
      ; Close the program.
      DoQuit = #True
      ;
    ElseIf EventID = #PB_Event_SizeWindow
      ;
      ResizeGadget(#ImageMain, 0, 0, WindowWidth(#WindowMain), WindowHeight(#WindowMain))
      ;
      fMainWidth = GadgetWidth(#ImageMain) : fMainHeight = GadgetHeight(#ImageMain)
      ;
      fMainLoadImage(fMainCurrentIndex, #True, #True)
      ;
    ElseIf EventID = #PB_Event_Menu
      ;
      If EventMenu() = #MenuEscape
        DoQuit = #True
      ElseIf EventMenu() = #MenuOpen
        ;
        HoldString.s = OpenFileRequester("Please Select A Directory", "", "Images | *.png;*.jpg;*.bmp", 0)
        ;
        If HoldString <> ""
          ;
          fMainCurrentDirectory = GetPathPart(HoldString)
          ;
          fMainFillFiles(fMainCurrentDirectory)
          ;
          fMainDisplayParameter(GetFilePart(HoldString))
          ;
        EndIf
        ;
      ElseIf EventMenu() = #MenuFitWidth
        ;
        If FMainDoFitWidth = #False
          ;
          FMainDoFitWidth = #True : fMainDoFitHeight = #False : fMainDoFitImage = #False : fMainDoFitActual = #False
          ;
          fMainLoadImage(fMainCurrentIndex, #True, #True)
          ;
        EndIf
        ;
      ElseIf EventMenu() = #MenuFitHeight
        ;
        If fMainDoFitHeight = #False
          ;
          FMainDoFitWidth = #False : fMainDoFitHeight = #True : fMainDoFitImage = #False : fMainDoFitActual = #False
          ;
          fMainLoadImage(fMainCurrentIndex, #True, #True)
          ;
        EndIf
        ;
      ElseIf EventMenu() = #MenuFitImage
        ;
        If fMainDoFitImage = #False
          ;
          FMainDoFitWidth = #False : fMainDoFitHeight = #False : fMainDoFitImage = #True : fMainDoFitActual = #False
          ;
          fMainLoadImage(fMainCurrentIndex, #True, #True)
          ;
        EndIf
        ;
      ElseIf EventMenu() = #MenuFitActual
        ;
        If fMainDoFitActual = #False
          ;
          FMainDoFitWidth = #False : fMainDoFitHeight = #False : fMainDoFitImage = #False : fMainDoFitActual = #True
          ;
          fMainLoadImage(fMainCurrentIndex, #True, #True)
          ;
        EndIf
        ;
      ElseIf EventMenu() = #MenuSmoothResize
        ;
        If fMainDoSmoothResize : fMainDoSmoothResize = #False : Else : fMainDoSmoothResize = #True : EndIf
        ;
        fMainLoadImage(fMainCurrentIndex, #True, #True)
        ;
      EndIf
      ;
    ElseIf EventID = #PB_Event_Gadget
      ; Control Events
      If EventGadget() = #ImageMain
        ;
        If EventType() = #PB_EventType_RightClick
          ;
          SetMenuItemState(#MenuOptions, #MenuFitWidth, FMainDoFitWidth)
          ;
          SetMenuItemState(#MenuOptions, #MenuFitHeight, fMainDoFitHeight)
          ;
          SetMenuItemState(#MenuOptions, #MenuFitImage, fMainDoFitImage)
          ;
          SetMenuItemState(#MenuOptions, #MenuFitActual, fMainDoFitActual)
          ;
          SetMenuItemState(#MenuOptions, #MenuSmoothResize, fMainDoSmoothResize)
          ;
          DisplayPopupMenu(#MenuOptions, WindowID(#WindowMain))
          ;
        EndIf
        ;
      EndIf
      ;
    EndIf
    ;}
    ;
  Until DoQuit = #True
  ;
  If fHandleImage : FreeImage(fHandleImage) : EndIf
  ;
  RemoveKeyboardShortcut(#WindowMain, #PB_Shortcut_Escape)
  ;
  SetWindowCallback(0)
  ; Remove the window callback.
EndIf
Use it if you like. It won't do anything fancy like centering or anything like that. Who knows... maybe later on I can modify it so it looks more presentable. After my two other rather large projects :cry:

:D

As always - have fun ^_^
Intrigued
Enthusiast
Enthusiast
Posts: 501
Joined: Thu Jun 02, 2005 3:55 am
Location: U.S.A.

Post by Intrigued »

Thanks for sharing! I noticed from your post and testing that .gif is not supported yet. That would be a big plus I believe.
Intrigued - Registered PureBasic, lifetime updates user
Blade
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Aug 06, 2003 2:49 pm
Location: Venice - Italy, Japan when possible.
Contact:

Post by Blade »

Works :) Nice job!
I thought pb image functions were slower...
How to call it? PureSee? :)

I've installed Acdsee 8 recently and takes too much seconds to load, really. should go back to version 5.0

A simple question, why do you comment every blank odd line? In my poor 1024x768 monitor you code simply doesn't fit ;)
aaron
Enthusiast
Enthusiast
Posts: 267
Joined: Mon Apr 19, 2004 3:04 am
Location: Canada
Contact:

Post by aaron »

Cool. I typically use CDisplay to do the same thing (http://www.geocities.com/davidayton/CDisplay), but this works pretty good too.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

Yeah, I know. There are quite a few programs out there to do this. In fact, the MS Picture and Fax viewer can easily cycle through the images using the up/down and left/right arrows (something I may add in this little program).

This was really just one of those things where I thought, "I wonder if I can do this?" And then tried it. A programming exercise, you could say.

I've even thought about refining it and slimming it down. Maybe adding in gif reading (there is a library on the forum to easily do that). Who knows? You can kind of consider this example code to use for whatever you like. Maybe you needed an example of how the mouse wheel worked. Or how to load an image. Or how to resize an image... whatever. I didn't really have much thought of extending it beyond what it has currently.

Oh, and I add the comments on each line because it helps me read the code faster. It's harder to make out lines of code if they're all close together. That's all. Same reason I always indent 3 spaces and try to keep the code clean. It's just what I'm used to doing ^_^ And if I ever worked on it seriously I would *have* to name it xView, of course :) xGrid, xSolve, xList, etc... :D
dagcrack
Addict
Addict
Posts: 1868
Joined: Sun Mar 07, 2004 8:47 am
Location: Argentina
Contact:

Post by dagcrack »

I wonder if this guys would mind.. http://www.xview.com/
! Black holes are where God divided by zero !
My little blog!
(Not for the faint hearted!)
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Thanks again.

You just keep posting them and I'll kepp adding to my Tricks and Tips tutorials.

Wonderful way to learn various techniques of the language.

cheers
Intrigued
Enthusiast
Enthusiast
Posts: 501
Joined: Thu Jun 02, 2005 3:55 am
Location: U.S.A.

Post by Intrigued »

Fit Image to Window = crashes program, FWIW.
Intrigued - Registered PureBasic, lifetime updates user
Post Reply