Page 1 of 1

Image gallery - with PanelGadget() and ImageGadget()

Posted: Fri Nov 15, 2024 7:01 pm
by Jacobus
Hello,
I propose a program to easily create an image gallery and view them. There are already applications and codes of this kind, but here I have favored the use of PanelGadget() and ImageGadget() to display the thumbnails. This allows more possibilities for managing actions/events.
2025/04/24 : Updated code with some additional functions
Tested : Windows11 pro, PB 621 B6, x86 and x64
A short video of how this image viewer works ici Video of Image Viewer

Code: Select all

;-Entête
;{
;=================================
; Create an image gallery simply 
; Committed by Jacobus, 2024/11/15
; With the involuntary complicity of Wilbert, Sparkie, Oryaaaaa, And LSI
; --------------------------------
; updated code : 2025/04/24
; --------------------------------
; FEATURES / FONCTIONNALITES:
; --------------------------------
; - Double-left-clicking on an image displays it in the viewing area / un double clic gauche sur une image l'affiche dans la zone de visualisation
; - Right-clicking on an image in the gallery displays a context menu / un clic droit sur une image de la galerie affiche un menu contextuel
;
; - [Amended] : The limit of 100 images uploaded to the gallery has been increased to approximately 400 by reducing the size of the thumbnails
;               La limite de 100 images chargées dans la galerie a été augmentée à plus ou moins 400 en réduisant la taille des imagettes
;
; - [Amended] : Each image loaded into the gallery (left) is displayed in an "ImageGadget()"
;               Chaque image chargée dans la galerie (à gauche) est affichée dans un « ImageGadget() »
;
; - [Amended] : Removed empty space from gallery scrollarea which was initial space when window was created and not used when loading images.
;               Suppression de l'espace vide de la scrollarea de la galerie qui était l'espace initial lors de la création de la fenêtre et non utilisé lors du chargement des images.
;
; - [Added] : A progress bar has been added to show the loading of images in the gallery
;             Une barre de progression a été ajoutée permettant de matérialiser le chargement des images dans la galerie
;
; - [Added] : Each gallery image that is opened and displayed in the central area is also displayed in a thumbnail on the right, along with its information, in a PanelGadget(). These are defined as recently viewed/opened images.
;             It is then possible to open the image in your default viewer from this thumbnail or to remove the thumbnail and associated gadgets from the list.
;             Chaque image de la galerie qui est ouverte et affichée dans la zone centrale, est également affichée dans une imagette à droite, avec ses informations, dans un PanelGadget(). Elles sont définies comme images récemment vues/ouvertes.
;             Il est alors possible d'ouvrir l'image dans votre visionneuse par défaut depuis cette imagette ou de supprimer l'imagette et les gadgets associés de la liste.
;
; - [Added] : In addition to the Exif data, basic information such as size, weight and dates of each displayed image is added.
;             En plus des données Exif, sont ajoutées les informations de base telles que taille, poids et dates, de chaque image affichées.
;
; - [Added] : If an image displayed in the viewing area is later reopened, it is not recreated as the image viewed in the right gallery. This prevents duplicates in recently viewed images.
;             Si une image affichée dans la zone de visualisation est rouverte ultérieurement, elle n'est pas recréée comme image vue dans la galerie de droite. Cela évite les doublons dans les images vues récemment.
;
; - [Added] : Each recently viewed image can be reopened by double-left-clicking on it.
;             Chaque image récemment visualisée peut être rouverte en double-cliquant dessus avec le bouton gauche de la souris.
; --------------------------------
; Errors found and solved/not solved:
; --------------------------------
; 1/Using a 'thread' to load the gallery means that after loading, which is done correctly, all the images/panel disappear ??
; --------------------------------
; Since gadgets should not be created in a Thread, the main window is disabled while images are loading. 
; This means that you should Not move the window during loading To avoid freezing it. 
; If the window freezes, this will have no effect on loading, which will Continue To happen.
;
; Puisqu'il ne faut pas créer de gadgets dans un Thread, la fenêtre principale est désactivée pendant le chargement des images. 
; Cela implique de ne pas déplacer la fenêtre pendant le chargement pour ne pas la figer. 
; Si malgré tout la fenêtre se fige, cela reste sans conséquence sur le chargement qui Continue néanmoins à se faire.
; --------------------------------
; 2/If hundreds of images are loaded into the gallery, the last ones in the series are not displayed correctly in the scrollarea.
; --------------------------------
; The problem is partially solved by reducing the number of thumbnails created when loading the gallery
;
; Le problème est partiellement résolu par la réduction des imagettes créées lors du chargement de la galerie
;}
;=================================
;-ImagePlugin
UseJPEGImageDecoder() 
UseJPEGImageEncoder()
UseTGAImageDecoder() 
UsePNGImageDecoder()
UsePNGImageEncoder() 
UseTIFFImageDecoder()
UseGIFImageDecoder()

;-CONSTANTES
Enumeration
  #WinViewer
EndEnumeration

Enumeration
  ;{
  #PhotoLoad 
  #DirectoryImages
  #Photo
  #ReadExif
  #RedimImage
  
  #Txt_scroll_Galerie
  #scroll_Galerie
  
  #Txt_scroll_image
  #scroll_image
  #PhotoView
  
  #Txt_scroll_Viewed
  #scroll_Viewed
  
  #LoadingProgress
  
  ;-ToolBarMain
  #ToolBarMain 
  #Tbar_btn_OpenFolder
  #Tbar_btn_CloseImage
  #Tbar_btn_Redim
  #Tbar_btn_ActualSize
  #Tbar_btn_ZoomIn
  #Tbar_btn_ZoomOut
  #Tbar_btn_ZoomPercent
  ;-PopUpMenu Sizes
  #MenuSizes
  #Menu_SizeDiv2
  #Menu_SizeDiv4
  #Menu_SizeDiv6
  #Menu_SizeDiv8
  #Menu_SizeMult2
  #Menu_SizeMult4
  #Menu_SizeMult6
  #Menu_SizeMult8
  
  #MenuPercentZoom
   #ZoomIn_10
   #ZoomIn_20
   #ZoomIn_30
   #ZoomIn_40
   #ZoomIn_50
   #ZoomIn_60
   #ZoomIn_70
   #ZoomIn_80
   #ZoomIn_90    
   #ZoomIn_100
   #ZoomIn_120
   #ZoomIn_140
   #ZoomIn_150
   #ZoomIn_160
   #ZoomIn_180
   #ZoomIn_200
   #ZoomIn_220
   #ZoomIn_240
   #ZoomIn_260
   #ZoomIn_280
   #ZoomIn_300
   #ZoomIn_320
   #ZoomIn_340
   #ZoomIn_360
   #ZoomIn_380
   #ZoomIn_400
   
   #ZoomOut_10
   #ZoomOut_20
   #ZoomOut_30
   #ZoomOut_40
   #ZoomOut_50
   #ZoomOut_60
   #ZoomOut_70
   #ZoomOut_80
   #ZoomOut_90
  
  ;-PopUp ActualSize
  #PopUp_ActualSize
  #DisplaySizeImage
  #DisplayActualSize
  ;-PopUp Galery
  #PopUp_Galerie
  #Menu_Galerie_OpenFile
  #Menu_Galerie_FileProperty
  
  #StatusViewer
  ;}
EndEnumeration

;-===============================
;-VARIABLES
Global Quitter = 0
Global BackColor = RGB(86, 96, 101)
Global ForeColor = RGB(222, 205, 62)
Global FontID1   = LoadFont(0, "Bahnschrift Semibold Condensed", 10,#PB_Font_HighQuality)
Global ChInitial$

Global yImg.l = 2     ; scrollarea gallery
Global PosyImg.l = 2  ; scrollarea recently viewed

;Determines the current directory without error
Global curdir.s, AppliDir$
curdir.s = Space(#MAX_PATH)
GetModuleFileName_(GetModuleHandle_(0), @curdir, #MAX_PATH)
AppliDir$ = GetPathPart(curdir)

; Global ThreadGalerie.l = 0, EndThreadGalerie.l = 0     ; à décommenter/commenter en cas d'utilisation ou non d'un thread
Global ImagesDir$
Global ImageName$
Global NomPhoto$, PhotoGalerie$
Global Result_Photo
Global mult.f = 1.0

;-DPI
;Necessary for large screens
CompilerIf #PB_Compiler_DPIAware = 1
  
  Global dpix.d = DesktopResolutionX()
  Global dpiy.d = DesktopResolutionY()
  
CompilerElse
  
  Global dpix.d = 1.00
  Global dpiy.d = 1.00
  
CompilerEndIf

;-===============================
;-DONNEES EXIF
;Endian procs by wilbert
;Original code by Sparkie
;Modif GetCameraModel by oryaaaaa
Procedure.w xchEndianW(e.w) 
  ProcedureReturn (e & $FF) << 8 + (e >> 8) & $FF 
EndProcedure 
Procedure xchEndianL(e.i) 
  ProcedureReturn (e & $FF) << 24 + (e & $FF00) << 8 + (e >> 8) & $FF00 + (e >> 24) & $FF 
EndProcedure 
Procedure GetCameraModel(imageAdress.i,ExifEditor.i) 
  Protected OffsetField.i = imageAdress +3 
  Protected Header.b, wordOrder.i, tifFormat.i, ifd1.i, nFields.i, currentTag.i, flg.b 
  Protected fieldType.i, fieldLength.i, fieldValue.i, currentloc.i, cam$ 
  If PeekB(OffsetField) &$FF = $E1 
    Header = 12 
  Else 
    Header = 30 
  EndIf 
  OffsetField = imageAdress + Header 
  wordOrder = PeekW(OffsetField) 
  OffsetField + 2 
  If wordOrder = $4949 Or wordOrder = $4D4D 
    If wordOrder = $4949 
      tifFormat = PeekW(OffsetField) 
    Else 
      tifFormat = xchEndianW(PeekW(OffsetField)) 
    EndIf 
    OffsetField + 2 
    If tifFormat = $2A 
      If wordOrder = $4949 
        ifd1 = PeekL(OffsetField) 
      Else 
        ifd1 = xchEndianL(PeekL(OffsetField) ) 
      EndIf 
      OffsetField + 4 
      OffsetField = imageAdress + ifd1 + Header 
      If wordOrder = $4949 
        nFields = PeekW(OffsetField) 
      Else 
        nFields = xchEndianW(PeekW(OffsetField)) 
      EndIf 
      OffsetField + 2 
      For i = 1 To nFields 
        If wordOrder = $4949 
          currentTag = PeekW(OffsetField) 
        Else 
          currentTag = xchEndianW(PeekW(OffsetField)) 
        EndIf 
        OffsetField + 2 
        flg=#True 
        Select currentTag 
          Case 271 
            cam$ = " Fabricant: " 
          Case 272 
            cam$ = " Modèle: " 
          Case 305 
            cam$ = " Appareil: " 
          Case 306 
            cam$ = " Date prise de vue: " 
          Case 315 
            cam$ = " Auteur: " 
          Default 
            flg=#False 
        EndSelect 
        If flg=#True 
          If wordOrder = $4949 
            fieldType = PeekW(OffsetField) 
          Else 
            fieldType = xchEndianW(PeekW(OffsetField)) 
          EndIf 
          OffsetField + 2 
          fieldLength = PeekL(OffsetField) 
          OffsetField + 4 
          If fieldLength <= 4 
            currentloc = OffsetField 
            AddGadgetItem(ExifEditor, -1, PeekS(OffsetField,0, #PB_Ascii)) 
            OffsetField + 4 
          Else 
            currentloc = OffsetField 
            If wordOrder = $4949 
              fieldValue = PeekL(OffsetField) 
            Else 
              fieldValue = xchEndianL(PeekL(OffsetField)) 
            EndIf 
            OffsetField = imageAdress + fieldValue + Header 
            AddGadgetItem(ExifEditor, -1, cam$ + PeekS(OffsetField, 255, #PB_Ascii)) 
            OffsetField = currentloc + 4 
          EndIf 
        Else 
           OffsetField +10 
        EndIf 
      Next 
    EndIf 
  EndIf 
EndProcedure 

;-===============================
;-STRUCTURE LIST
; Image gallery
Structure ImageGalerie ;{
  ShowImage.i
  NewImg.i
  PathImg.s
  ImgName.s ;}
EndStructure
Global NewList ScrollShowImage.ImageGalerie()
;Procedure for releasing the gallery before loading other images
Procedure FreeGalerie()
  ;Removing an image and associated gadgets from the gallery
  For i = 0 To ListSize(ScrollShowImage.ImageGalerie())-1
    ShowImage = SelectElement(ScrollShowImage(), i) ;ImageGadget()
    NewImg    = SelectElement(ScrollShowImage(), i) ;The displayed thumbnail image
    PathImg   = SelectElement(ScrollShowImage(), i) ;The location of the image on disk
    ImgName   = SelectElement(ScrollShowImage(), i) 
    ;We release the 1 "Gadget" type elements on the 5 elements :
    FreeGadget(ScrollShowImage()\ShowImage)  
  Next
  yImg = 2 ;reset y position to restart display at the beginning of the ScrollareaGadget
EndProcedure

; Recently viewed images
Structure ImageViewed ;{
  Panel.i
  ViewImage.i
  CopyImg.i
  DirFile.s
  FileName.s 
  BtnOpen.i
  BtnRemove.i 
  ;}
EndStructure
Global NewList ScrollViewed.ImageViewed()
Procedure FreeViewedImages()
  ;Removing an image and associated gadgets from the gallery
  For i = 0 To ListSize(ScrollViewed.ImageViewed())-1
    Panel     = SelectElement(ScrollViewed(), i) ;PanelGadget() receiving the ImageGadget()
    ViewImage = SelectElement(ScrollViewed(), i) ;ImageGadget()
    CopyImg   = SelectElement(ScrollViewed(), i) ;The displayed thumbnail image
    DirFile   = SelectElement(ScrollViewed(), i) ;The location of the image on disk
    FileName  = SelectElement(ScrollViewed(), i) ;The FileName of the image on disk
    BtnOpen   = SelectElement(ScrollViewed(), i) ;The button to open in Windows image viewer
    BtnRemove = SelectElement(ScrollViewed(), i) ;The button to remove of th list
    ;We release the 4 "Gadget" type elements on the 7 elements :
    FreeGadget(ScrollViewed()\ViewImage)
    FreeGadget(ScrollViewed()\BtnOpen)
    FreeGadget(ScrollViewed()\BtnRemove)
    FreeGadget(ScrollViewed()\Panel)
  Next
  yImg = 2 ;reset y position to restart display at the beginning of the ScrollareaGadget
EndProcedure

;-===============================
;-PROCEDURES GENERALES
Procedure FileProperty(File$)
  verb$ = "properties" 
  SEI.SHELLEXECUTEINFO 
  SEI\cbSize = SizeOf(SHELLEXECUTEINFO) 
  SEI\fMask = #SEE_MASK_NOCLOSEPROCESS | #SEE_MASK_INVOKEIDLIST | #SEE_MASK_FLAG_NO_UI 
  SEI\lpVerb = @verb$ 
  ;File$ = SelFile$
  SEI\lpFile = @File$ 
  ShellExecuteEx_(@SEI)
EndProcedure
 Structure Characters 
  c.c[0] 
EndStructure
Procedure.s GetDirectoryPart(FileName.s) ;by LSI 
  Protected Directory.s, i.i 
  Protected *Directory.Characters 
  Directory = GetPathPart(FileName) 
  If Directory 
    i = Len(Directory) - 2 
    *Directory = @Directory  
    While i >= 0 And *Directory\c[i] <> '/' And *Directory\c[i] <> '\' 
      i - 1 
    Wend  
    i + 2 
    Directory = Mid(Directory, i, Len(Directory) - i) 
  EndIf 
  ProcedureReturn Directory 
EndProcedure
Procedure.s DisplaySize(Taille.q, Unite.l = -1, NbDecimals.l = 0);by LSI 
	; Taille = taille du lecteur
	; Unite = unité de la taille, 0 = Octect, 1 = Ko, 2 = Mo, 3 = Go. Si = -1, Le choix de l'unité et du nombre de décimal sera automatique
	; NbDecimals = nombre de chiffre après la virgule.
	
	Protected Val.q, Txt.s
	
	If Unite = -1
		NbDecimals = 0 : Unite = 0
		If Taille >= 1000 : Unite = 1 : NbDecimals = 2 : EndIf
		If Taille >= 10000 : Unite = 1 : NbDecimals = 1 : EndIf
		If Taille >= 1000000 : Unite = 2 : NbDecimals = 2 : EndIf
		If Taille >= 10000000 : Unite = 2 : NbDecimals = 1 : EndIf
		If Taille >= 1000000000 : Unite = 3 : NbDecimals = 2 : EndIf
		If Taille >= 10000000000 : Unite = 3 : NbDecimals = 1 : EndIf
	EndIf
	Select Unite
		Case 0 : Val = 1 : Txt = " octets"
		Case 1 : Val = 1024 : Txt = " Ko"
		Case 2 : Val = 1024 * 1024 : Txt = " Mo"
		Case 3 : Val = 1024 * 1024 * 1024 : Txt = " Go"
	EndSelect
	ProcedureReturn StrF(Taille / Val, NbDecimals) + Txt
	
EndProcedure

;-===============================
;-CREATION OF GALLERIES
Procedure.l CountImagesGallery(ImagesDir$)
  ;Allows you to count the images that will be in the gallery and adapt the progressbar
  ;Permet de compter les images qui seront dans la galerie et d'adapter la progressbar
  nbimg.l = 0
  If ExamineDirectory(#DirectoryImages, ImagesDir$, "*.*") <> 0 
    While NextDirectoryEntry(#DirectoryImages)
      If DirectoryEntryType(#DirectoryImages) = #PB_DirectoryEntry_File
        ImageName$ = DirectoryEntryName(#DirectoryImages)
        ImageExt$  = GetExtensionPart(ImageName$)
        If LCase(ImageExt$) = "bmp" Or LCase(ImageExt$) = "jpeg" Or LCase(ImageExt$) = "jpg" Or LCase(ImageExt$) = "png" Or LCase(ImageExt$) = "gif" Or LCase(ImageExt$) = "tif" Or LCase(ImageExt$) = "tga"
          nbimg + 1
        EndIf 
      EndIf 
    Wend
    ProcedureReturn nbimg
  Else 
    ProcedureReturn 0
  EndIf 
  
EndProcedure
;This is the procedure that does all the work of displaying the gallery
Procedure CreateGallery(ImagesDir$)
  ; Reduced the size of the scroll area to avoid having an empty part/Réduction de la taille de la scrollarea pour éviter d'avoir une partie vide
  SetGadgetAttribute(#scroll_Galerie, #PB_ScrollArea_InnerHeight,2) 
  SetGadgetAttribute(#scroll_Galerie, #PB_ScrollArea_Y, 0) ; reset  
  SetGadgetAttribute(#scroll_Galerie, #PB_ScrollArea_X, 0) ; for a display at the beginning 
  DisableWindow(#WinViewer, #True)
  
  MaxImages = CountImagesGallery(ImagesDir$)
  If MaxImages <> 0
    SetGadgetAttribute(#LoadingProgress, #PB_ProgressBar_Maximum, MaxImages)
  EndIf 
  
  If ExamineDirectory(#DirectoryImages, ImagesDir$, "*.*") <> 0  :  n = 0
    SetWindowTitle(#WinViewer, "Image Viewer (Loading images into the gallery...)") 
    StatusBarText(#StatusViewer, 0, "Gallery : "+GetDirectoryPart(ImagesDir$))   
    While NextDirectoryEntry(#DirectoryImages)      
      If DirectoryEntryType(#DirectoryImages) = #PB_DirectoryEntry_File 
        ImageName$ = DirectoryEntryName(#DirectoryImages)
        ImageExt$  = GetExtensionPart(ImageName$)
        If LCase(ImageExt$) = "bmp" Or LCase(ImageExt$) = "jpeg" Or LCase(ImageExt$) = "jpg" Or LCase(ImageExt$) = "png" Or LCase(ImageExt$) = "gif" Or LCase(ImageExt$) = "tif" Or LCase(ImageExt$) = "tga"      
          PhotoSelect = LoadImage(#Photo, ImagesDir$+ImageName$)         
          If PhotoSelect
            n+1
            StatusBarText(#StatusViewer, 1, Str(n)+" files")
            SetGadgetState(#LoadingProgress, n)
            
            OpenGadgetList(#scroll_Galerie) 
              NewImg = CopyImage(#Photo,#PB_Any)
              ResizeImage(NewImg,75*dpix,50*dpiy,#PB_Image_Smooth)
              ShowImage = ImageGadget(#PB_Any,5,yImg,75*dpix,50*dpiy,ImageID(NewImg),#PB_Image_Border)
              *Element.ImageGalerie = AddElement(ScrollShowImage())
              If *Element<>0
                *Element\ShowImage = ShowImage
                *Element\NewImg    = NewImg
                *Element\PathImg   = ImagesDir$
                *Element\ImgName   = ImageName$
              EndIf
            CloseGadgetList()           
            
            yImg = yImg + 62  ; 62 = 50 + 12 --> hauteur image + espace entre images
            InHeight = GetGadgetAttribute(#scroll_Galerie, #PB_ScrollArea_InnerHeight)            
            SetGadgetAttribute(#scroll_Galerie, #PB_ScrollArea_InnerHeight, InHeight+62)
          EndIf            
        EndIf         
      EndIf
      Delay(1)
      RedrawWindow_(WindowID(#WinViewer), #Null, #Null, #RDW_UPDATENOW)
    Wend   
    FinishDirectory(#DirectoryImages) 
  EndIf 
  SetWindowTitle(#WinViewer, "Image Viewer") 
  SetGadgetState(#LoadingProgress, 0)
  DisableWindow(#WinViewer, #False)     
EndProcedure

Procedure RecentlyViewedImages(ImagesDir$,ImageName$)
  
  Protected Exist.l = 0, Pan.l
  ; Check that the image has not already been opened/ Vérification que l'image n'a pas déjà été ouverte
  ; if this is the case we do not recreate it a second time in the images seen recently./si c'est le cas on ne la recrée pas une seconde fois dans les images vues récemment.
  If ListIndex(ScrollViewed())<>-1    
    For Pan = 0 To ListSize(ScrollViewed.ImageViewed())-1     
      SelectElement(ScrollViewed(),Pan)         
      If ScrollViewed()\FileName <> ImageName$ 
        Exist = 0
      ElseIf ScrollViewed()\FileName = ImageName$
        Exist = 1 : Break 
      EndIf      
    Next   
  ElseIf ListIndex(ScrollViewed())=-1 ; if the list is empty we move to the beginning of the scroll area/si la liste est vide on se place au début de la scrollarea
    SetGadgetAttribute(#scroll_Viewed, #PB_ScrollArea_InnerHeight,2) ; ... 
    SetGadgetAttribute(#scroll_Viewed, #PB_ScrollArea_Y, 0) ; reset  
    SetGadgetAttribute(#scroll_Viewed, #PB_ScrollArea_X, 0) ; for a display at the beginning 
  EndIf
  
  ; only if the image has not already been opened, we create the panel and the thumbnail on the right
  If Exist = 0 ; seulement si l'image n'a pas déjà été ouverte, on crée le panel et l'imagette à droite
    ;{
    If FileSize(ImagesDir$+ImageName$)<>-1 ; we still check that the file exists/on contrôle quand même que le fichier existe bien             
      If LoadImage(#Photo, ImagesDir$+ImageName$)
        Largeur = ImageWidth(#Photo)
        Hauteur = ImageHeight(#Photo)
        
        OpenGadgetList(#scroll_Viewed) 
        Panel = PanelGadget(#PB_Any, 0, PosyImg, 200, 100)             
        AddGadgetItem(Panel,0,ImageName$)                             ; first element that will receive the ImageGadget()            
        WidthPanel.d  = GetGadgetAttribute(Panel, #PB_Panel_ItemWidth)  ; usable width for ImageGadget()
        HeightPanel.d = GetGadgetAttribute(Panel, #PB_Panel_ItemHeight) ; usable height for ImageGadget()           
        
        CopyImg = CopyImage(#Photo,#PB_Any)
        ResizeImage(CopyImg,100*dpix,67*dpiy,#PB_Image_Smooth)
        ViewImage = ImageGadget(#PB_Any,5,0,100*dpix,67*dpiy,ImageID(CopyImg),#PB_Image_Border) ;creating the ImageGadget() with image           
        BtnOpen   = ButtonGadget(#PB_Any,120,5,60,25,"Open") ; To open the image with the default Windows viewer                               
        BtnRemove = ButtonGadget(#PB_Any,120,35,60,25,"Remove") ; To remove the image from the list and recently opened images
        GadgetToolTip(BtnOpen,"Open the image with the default Windows viewer")
        GadgetToolTip(BtnRemove,"Remove the image from the list and recently opened images")
        
        ; added the thumbnail to the list of viewed images/ajout de l'imagette dans la liste des images vues
        *Element.ImageViewed = AddElement(ScrollViewed())
        If *Element<>0
          *Element\Panel     = Panel
          *Element\ViewImage = ViewImage
          *Element\CopyImg   = CopyImg
          *Element\DirFile   = ImagesDir$
          *Element\FileName  = ImageName$
          *Element\BtnOpen   = BtnOpen
          *Element\BtnRemove = BtnRemove
        EndIf
    
        AddGadgetItem(Panel,1,"Info",ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",171))
        TextExif = EditorGadget(#PB_Any,0,0,WidthPanel,HeightPanel,#PB_Editor_ReadOnly|#PB_Editor_WordWrap)
        SetGadgetFont(TextExif,FontID1) : SetGadgetColor(TextExif,#PB_Gadget_BackColor,BackColor) : SetGadgetColor(TextExif,#PB_Gadget_FrontColor,RGB(255, 255, 255))
        
        ;information about the image to display in the panel/info sur l'image à afficher dans le panel
        AddGadgetItem(TextExif, -1, " Hauteur : "+Str(Hauteur)+" pixels")
        AddGadgetItem(TextExif, -1, " Largeur  : "+Str(Largeur)+" pixels")
        AddGadgetItem(TextExif, -1, " Taille image : "+StrF((Largeur*Hauteur)/1024/1024,2)+" MP") 
        AddGadgetItem(TextExif, -1, " Taille fichier: "+DisplaySize(FileSize(ImagesDir$+ImageName$)))    
        AddGadgetItem(TextExif, -1, " Fichier créé le : "+FormatDate("%dd/%mm/%yyyy",GetFileDate(ImagesDir$+ImageName$,  #PB_Date_Created)))
        AddGadgetItem(TextExif, -1, " Fichier modifié le : "+FormatDate("%dd/%mm/%yyyy",GetFileDate(ImagesDir$+ImageName$, #PB_Date_Modified)))
        AddGadgetItem(TextExif, -1, " Dernier accès le : "+FormatDate("%dd/%mm/%yyyy",GetFileDate(ImagesDir$+ImageName$, #PB_Date_Accessed)))
        SelectFileExt$ = GetExtensionPart(ImagesDir$+ImageName$)     
        If LCase(SelectFileExt$) = "jpg" Or LCase(SelectFileExt$) = "jpeg" ;Or LCase(SelectFileExt$) = "jp2"
          If ReadFile(#ReadExif, ImagesDir$+ImageName$)                    ;Reads image data
            *BufferImg = AllocateMemory(Lof(#ReadExif))                    ;Allocates a memory area 
            ReadData(#ReadExif, *BufferImg, Lof(#ReadExif))                ;places the read data into memory
            CloseFile(#ReadExif) 
            GetCameraModel(*BufferImg,TextExif) ; Retrieves data from memory that is processed by the procedure and displayed in the editor
          EndIf
          FreeMemory(*BufferImg)
        EndIf 
        
        CloseGadgetList() ; closed the panel
        CloseGadgetList() ; closed the scrollarea
        
        PosyImg = PosyImg + 102 ;GetGadgetAttribute(Panel, #PB_Panel_ItemHeight)+GetGadgetAttribute(Panel, #PB_Panel_TabHeight)+2
        InHeight = GetGadgetAttribute(#scroll_Viewed, #PB_ScrollArea_InnerHeight)            
        SetGadgetAttribute(#scroll_Viewed, #PB_ScrollArea_InnerHeight, InHeight+102)
      EndIf 
    EndIf
    ;}
  EndIf
  
EndProcedure
;Procedure to display an image from the gallery in the viewing area
Procedure OpenImageGalerie(PhotoGalerie$) 
  
  If PhotoGalerie$ <> "" 
    Result_Photo = LoadImage(#PhotoLoad, PhotoGalerie$)
    If Result_Photo     
      Hauteur = ImageHeight(#PhotoLoad) : ValeurH$ = Str(Hauteur)  
      Largeur = ImageWidth(#PhotoLoad)  : ValeurL$ = Str(Largeur)
      SetMenuItemText(#PopUp_ActualSize,#DisplayActualSize,"Show actual dimensions : "+ValeurL$+" x "+ValeurH$)     
      ;if the image is larger than the display area, it is reduced to display the entire image  
      If Largeur > 575 
        NL = Largeur/4
        NH = Hauteur/4
        Result_Photo = ResizeImage(#PhotoLoad,NL,NH,#PB_Image_Smooth)
      ElseIf Largeur <= 575
        NL = Largeur
        NH = Hauteur
      EndIf
      SetMenuItemText(#PopUp_ActualSize,#DisplaySizeImage,"Dimensions of displayed image : "+Str(NL)+" x "+Str(NH))
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, NL);Changes the width of the inner scrollarea area based on the width of the image. 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, NH);Changes the height of the inner area of ​​the scrollarea based on the height of the image. 
      SetGadgetState(#PhotoView, Result_Photo) 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_Y, 0)
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_X, 0)
      ImageName$ = GetFilePart(PhotoGalerie$) 
      StatusBarText(#StatusViewer, 2, "View : "+ImageName$,#PB_StatusBar_Center)             
      StatusBarText(#StatusViewer, 3, "Dimensions : "+ValeurL$+" x "+ValeurH$+" | "+StrF((Largeur*Hauteur)/1024/1024,2)+" MP")  
      StatusBarText(#StatusViewer, 4, "Size : "+DisplaySize(FileSize(PhotoGalerie$))) 
      
      ImagesDir$ = GetPathPart(PhotoGalerie$)      
      RecentlyViewedImages(ImagesDir$,ImageName$)
    EndIf       
  EndIf 
  
EndProcedure
Procedure RedimImageSize_Div(divi.l) 
  If IsImage(#PhotoLoad) <> 0
    If LoadImage(#PhotoLoad,NomPhoto$); if the image is reloaded, the new dimensions are applied to the original image
      Timgx = ImageWidth(#PhotoLoad)  : ValImgX$ = Str(Timgx/divi); we divide the image size by two 
      Timgy = ImageHeight(#PhotoLoad) : ValImgY$ = Str(Timgy/divi)       
      SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValImgX$) ,Val(ValImgY$),#PB_Image_Smooth)); then we resize the image immediately with the new values     
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Val(ValImgX$))     ;  we adapt the scrollarea according to the new dimensions 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Val(ValImgY$)) 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_Y, 0)
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_X, 0)
    EndIf 
  EndIf 
EndProcedure
Procedure RedimImageSize_Mult(multi.l)
  If IsImage(#PhotoLoad) <> 0
    If LoadImage(#PhotoLoad,NomPhoto$) 
      Timgx = ImageWidth(#PhotoLoad)  : ValImgX$ = Str(Timgx*multi)
      Timgy = ImageHeight(#PhotoLoad) : ValImgY$ = Str(Timgy*multi) 
      SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValImgX$) ,Val(ValImgY$),#PB_Image_Smooth))
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Val(ValImgX$))
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Val(ValImgY$)) 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_Y, 0)
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_X, 0)
    EndIf 
  EndIf 
EndProcedure
Procedure ZoomInImage(zoom$)
  Protected Zmult.f
  If IsImage(#PhotoLoad) 
    If LoadImage(#PhotoLoad,NomPhoto$) ;we reload the image for better quality when resizing
      Select zoom$
        Case "+10 %"  : Zmult = 1.1
        Case "+20 %"  : Zmult = 1.2
        Case "+30 %"  : Zmult = 1.3
        Case "+40 %"  : Zmult = 1.4
        Case "+50 %"  : Zmult = 1.5
        Case "+60 %"  : Zmult = 1.6
        Case "+70 %"  : Zmult = 1.7
        Case "+80 %"  : Zmult = 1.8
        Case "+90 %"  : Zmult = 1.9    
        Case "+100 %" : Zmult = 2
        Case "+120 %" : Zmult = 2.2
        Case "+140 %" : Zmult = 2.4
        Case "+150 %" : Zmult = 2.2
        Case "+160 %" : Zmult = 2.6
        Case "+180 %" : Zmult = 2.8
        Case "+200 %" : Zmult = 3
        Case "+220 %" : Zmult = 3.2
        Case "+240 %" : Zmult = 3.4
        Case "+260 %" : Zmult = 3.6
        Case "+280 %" : Zmult = 3.8
        Case "+300 %" : Zmult = 4
        Case "+320 %" : Zmult = 4.2
        Case "+340 %" : Zmult = 4.4
        Case "+360 %" : Zmult = 4.6
        Case "+380 %" : Zmult = 4.8
        Case "+400 %" : Zmult = 5   
      EndSelect
      Timgx = ImageWidth(#PhotoLoad)  
      Timgy = ImageHeight(#PhotoLoad)
      ValImgX$ = Str(Timgx*Zmult)
      ValImgY$ = Str(Timgy*Zmult)
      SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValImgX$) ,Val(ValImgY$),#PB_Image_Smooth))
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Val(ValImgX$))   
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Val(ValImgY$)) 
    EndIf 
  EndIf 
EndProcedure
Procedure ZoomOutImage(zoom$)
  Protected Zmult.f
  If IsImage(#PhotoLoad)<>0
    If LoadImage(#PhotoLoad,NomPhoto$)
      Select zoom$
        Case "-10 %" : Zmult = 0.9
        Case "-20 %" : Zmult = 0.8
        Case "-30 %" : Zmult = 0.7
        Case "-40 %" : Zmult = 0.6
        Case "-50 %" : Zmult = 0.5
        Case "-60 %" : Zmult = 0.4
        Case "-70 %" : Zmult = 0.3
        Case "-80 %" : Zmult = 0.2
        Case "-90 %" : Zmult = 0.1      
      EndSelect
      Timgx = ImageWidth(#PhotoLoad)  
      Timgy = ImageHeight(#PhotoLoad)
      ValImgX$ = Str(Timgx*Zmult)
      ValImgY$ = Str(Timgy*Zmult)
      SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValImgX$) ,Val(ValImgY$),#PB_Image_Smooth)) 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Val(ValImgX$))      
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Val(ValImgY$)) 
    EndIf 
  EndIf 
EndProcedure
Procedure ZoomAuto(mult.f) 
  If IsImage(#PhotoLoad)<>0           ;if an image is displayed
    Wimg = ImageWidth(#PhotoLoad)     ;we recover its width
    Himg = ImageHeight(#PhotoLoad)    ;we recover its height             
    ValImgX$ = StrF(Wimg*mult,1)
    ValImgY$ = StrF(Himg*mult,1)     
    If LoadImage(#PhotoLoad,NomPhoto$) ;we reload the image for better quality otherwise it degrades as ResizeImage() is used
      SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValImgX$) ,Val(ValImgY$),#PB_Image_Smooth))
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Val(ValImgX$)) 
      SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Val(ValImgY$))
    EndIf  
  EndIf
EndProcedure
Procedure ResizeImageViewer()
  
  Protected WinWidth.l, WinHeight.l
  WinWidth  = WindowWidth(#WinViewer,#PB_Window_InnerCoordinate)
  WinHeight = WindowHeight(#WinViewer,#PB_Window_InnerCoordinate)   
  ResizeGadget(#scroll_Galerie, #PB_Ignore,#PB_Ignore,#PB_Ignore,WinHeight-120) 
  If IsImage(#PhotoLoad)
    Hauteur = ImageHeight(#PhotoLoad)*dpix  
    Largeur = ImageWidth(#PhotoLoad)*dpiy 
    SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, Largeur)
    SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, Hauteur)
  EndIf  
  ResizeGadget(#scroll_image,#PB_Ignore,#PB_Ignore,WinWidth-359,WinHeight-120) ; 205,75,575,WinHeight-120  
  ResizeGadget(#Txt_scroll_Viewed,WinWidth-230,#PB_Ignore,#PB_Ignore,#PB_Ignore)
  ResizeGadget(#scroll_Viewed, WinWidth-230,#PB_Ignore,#PB_Ignore,WinHeight-120)  
  ResizeGadget(#LoadingProgress,#PB_Ignore,WinHeight-40,WinWidth-4,#PB_Ignore) 
  UpdateWindow_(WindowID(#WinViewer))
  
EndProcedure
;-===============================
;-Fenêtre 
If OpenWindow(#WinViewer ,0,0, 1014, 718, "Image Viewer", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget |#PB_Window_TitleBar) 
  WindowBounds(#WinViewer, 1014, 718, #PB_Ignore, #PB_Ignore)
  WinWidth  = WindowWidth(#WinViewer,#PB_Window_InnerCoordinate)
  WinHeight = WindowHeight(#WinViewer,#PB_Window_InnerCoordinate)   
  SetWindowColor(#WinViewer, BackColor)
  ;-Toolbar Main   
  If CreateToolBar(#ToolBarMain, WindowID(#WinViewer),#PB_ToolBar_Large|#PB_ToolBar_Text) ;{ 
    ToolBarSeparator()
    ToolBarImageButton(#Tbar_btn_OpenFolder,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",318),#PB_ToolBar_Normal,"Images")    
    ToolBarImageButton(#Tbar_btn_CloseImage,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",219),#PB_ToolBar_Normal,"Close")
    ToolBarSeparator()
    ToolBarImageButton(#Tbar_btn_ActualSize,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",245),#PB_ToolBar_Normal,"Actual")
    ToolBarImageButton(#Tbar_btn_Redim,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",192),#PB_ToolBar_Normal,"Resize")
    ToolBarSeparator()
    ToolBarImageButton(#Tbar_btn_ZoomIn,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",246),#PB_ToolBar_Normal,"+10%")
    ToolBarImageButton(#Tbar_btn_ZoomOut,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",247),#PB_ToolBar_Normal,"-10%")
    ToolBarImageButton(#Tbar_btn_ZoomPercent,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",263),#PB_ToolBar_Normal,"Other")
    ToolBarSeparator()
    
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_OpenFolder, "Select and load an image gallery")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_CloseImage, "Close the displayed image")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_ActualSize, "Show image at actual size")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_Redim, "Resize the image")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_ZoomIn, "Zoom in image +10%")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_ZoomOut, "Zoom out image -10%")
    ToolBarToolTip(#ToolBarMain, #Tbar_btn_ZoomPercent, "Zoom in or out the image in %")
    ;}
  EndIf 
  ;-MenuSizes
  If CreatePopupMenu(#MenuSizes) ;{
    OpenSubMenu("Reduce")
    MenuItem(#Menu_SizeDiv2,"Image/2")
    MenuItem(#Menu_SizeDiv4,"Image/4")
    MenuItem(#Menu_SizeDiv6,"Image/6")
    MenuItem(#Menu_SizeDiv8,"Image/8")
    CloseSubMenu()
    MenuBar()
    OpenSubMenu("Enlarge")
    MenuItem(#Menu_SizeMult2,"Image x2")
    MenuItem(#Menu_SizeMult4,"Image x4")
    MenuItem(#Menu_SizeMult6,"Image x6")
    MenuItem(#Menu_SizeMult8,"Image x8")
    CloseSubMenu()
    ;}
  EndIf  
  ;-MenuPercentZoom
  If CreatePopupMenu(#MenuPercentZoom) ;{
    OpenSubMenu("% Zoom +")
    MenuItem(#ZoomIn_10,"Actual Size +10 %")
    MenuItem(#ZoomIn_20,"Actual Size +20 %")
    MenuItem(#ZoomIn_30,"Actual Size +30 %")
    MenuItem(#ZoomIn_40,"Actual Size +40 %")
    MenuItem(#ZoomIn_50,"Actual Size +50 %")
    MenuItem(#ZoomIn_60,"Actual Size +60 %")
    MenuItem(#ZoomIn_70,"Actual Size +70 %")
    MenuItem(#ZoomIn_80,"Actual Size +80 %")
    MenuItem(#ZoomIn_90,"Actual Size +90 %")    
    MenuItem(#ZoomIn_100,"Actual Size +100 %")
    MenuItem(#ZoomIn_120,"Actual Size +120 %")
    MenuItem(#ZoomIn_140,"Actual Size +140 %")
    MenuItem(#ZoomIn_150,"Actual Size +150 %")
    MenuItem(#ZoomIn_160,"Actual Size +160 %")
    MenuItem(#ZoomIn_180,"Actual Size +180 %")
    MenuItem(#ZoomIn_200,"Actual Size +200 %")
    MenuItem(#ZoomIn_220,"Actual Size +220 %")
    MenuItem(#ZoomIn_240,"Actual Size +240 %")
    MenuItem(#ZoomIn_260,"Actual Size +260 %")
    MenuItem(#ZoomIn_280,"Actual Size +280 %")
    MenuItem(#ZoomIn_300,"Actual Size +300 %")
    MenuItem(#ZoomIn_320,"Actual Size +320 %")
    MenuItem(#ZoomIn_340,"Actual Size +340 %")
    MenuItem(#ZoomIn_360,"Actual Size +360 %")
    MenuItem(#ZoomIn_380,"Actual Size +380 %")
    MenuItem(#ZoomIn_400,"Actual Size +400 %")
    CloseSubMenu()
    MenuBar()
    OpenSubMenu("% Zoom -")
    MenuItem(#ZoomOut_10,"Actual Size -10 %")
    MenuItem(#ZoomOut_20,"Actual Size -20 %")
    MenuItem(#ZoomOut_30,"Actual Size -30 %")
    MenuItem(#ZoomOut_40,"Actual Size -40 %")
    MenuItem(#ZoomOut_50,"Actual Size -50 %")
    MenuItem(#ZoomOut_60,"Actual Size -60 %")
    MenuItem(#ZoomOut_70,"Actual Size -70 %")
    MenuItem(#ZoomOut_80,"Actual Size -80 %")
    MenuItem(#ZoomOut_90,"Actual Size -90 %")
    CloseSubMenu()
    ;}
  EndIf
  ;-PopUp_ActualSize
  If CreatePopupMenu(#PopUp_ActualSize) ;{
    MenuItem(#DisplaySizeImage,"Dimensions of displayed image :")
    MenuItem(#DisplayActualSize,"Show actual dimensions :")
    ;}
  EndIf
  ;-PopUpMenu_Galerie    
  If CreatePopupMenu(#PopUp_Galerie) ;{
    MenuItem(#Menu_Galerie_OpenFile,     "Open with default application")  ;,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",264))
    MenuBar()
    MenuItem(#Menu_Galerie_FileProperty, "Image properties")  ;,ExtractIcon_(GetModuleHandle_(#Null), "Shell32.dll",171))
    ;}
  EndIf
  
  ;-ScrollArea Galerie d'images (left)
  TextGadget(#Txt_scroll_Galerie,2,55,200,15,"Image Gallery")
  SetGadgetFont(#Txt_scroll_Galerie,FontID1) : SetGadgetColor(#Txt_scroll_Galerie,#PB_Gadget_BackColor,BackColor) : SetGadgetColor(#Txt_scroll_Galerie,#PB_Gadget_FrontColor,ForeColor)
  ScrollAreaGadget(#scroll_Galerie, 2,75,120,WinHeight-120, 90, WinHeight-120, 100,#PB_ScrollArea_Center) 
  SetGadgetColor(#scroll_Galerie, #PB_Gadget_BackColor, BackColor)
  CloseGadgetList()
  ShowScrollBar_(GadgetID(#scroll_Galerie), #SB_HORZ, 0) ;keep the horizontal scrollbar always hidden
   
  ;-ScrollArea de visionnage d'image (middle)
  TextGadget(#Txt_scroll_image,125,55,200,15,"Viewing area")
  SetGadgetFont(#Txt_scroll_image,FontID1) : SetGadgetColor(#Txt_scroll_image,#PB_Gadget_BackColor,BackColor) : SetGadgetColor(#Txt_scroll_image,#PB_Gadget_FrontColor,ForeColor)
  ScrollAreaGadget(#scroll_image, 125,75,655,WinHeight-120, 655, 500, 30,#PB_ScrollArea_Center)  
  SetGadgetColor(#scroll_image, #PB_Gadget_BackColor, BackColor)
  ImageGadget(#PhotoView,0,0,0,0,0)  ;initialisé à zéro 
  CloseGadgetList() 
  
  ;-ScrollArea d'images récemment ouvertes (right)
  TextGadget(#Txt_scroll_Viewed,WinWidth-230,55,220,15,"Recently viewed images")
  SetGadgetFont(#Txt_scroll_Viewed,FontID1) : SetGadgetColor(#Txt_scroll_Viewed,#PB_Gadget_BackColor,BackColor) : SetGadgetColor(#Txt_scroll_Viewed,#PB_Gadget_FrontColor,ForeColor)
  ScrollAreaGadget(#scroll_Viewed, WinWidth-230,75,225,WinHeight-120, 220, WinHeight-120, 100);,#PB_ScrollArea_Center) 
  SetGadgetColor(#scroll_Viewed, #PB_Gadget_BackColor, BackColor)
  ShowScrollBar_(GadgetID(#scroll_Viewed), #SB_HORZ, 0) ;keep the horizontal scrollbar always hidden
  CloseGadgetList()
  
  ProgressBarGadget(#LoadingProgress,2,WinHeight-40,WinWidth-4,12,0,100)
  
  ;-Statusbar  
  If CreateStatusBar(#StatusViewer,WindowID(#WinViewer)) ;{
    AddStatusBarField(#PB_Ignore)
    AddStatusBarField(70)
    AddStatusBarField(#PB_Ignore)
    AddStatusBarField(#PB_Ignore)
    AddStatusBarField(80)
    AddStatusBarField(75)
    AddStatusBarField(75)
    ;AddStatusBarField(#PB_Ignore)
    StatusBarText(#StatusViewer, 0, "Galery : ")
    StatusBarText(#StatusViewer, 1, "Files : ")
    StatusBarText(#StatusViewer, 2, "View : ")
    StatusBarText(#StatusViewer, 3, "Dimensions :")
    StatusBarText(#StatusViewer, 4, "Size : ") 
    StatusBarText(#StatusViewer, 5, "PosX")
    StatusBarText(#StatusViewer, 6, "PosY")
    ;}
  EndIf 

  BindEvent(#PB_Event_SizeWindow, @ResizeImageViewer())
EndIf

;-===========================
;-Programme 
Repeat 
  Event = WaitWindowEvent() 
  ;Cursor position on the image :   
  If Event ;{
    GetCursorPos_(@cp.point)
    GetWindowRect_(GadgetID(#PhotoView),gr.RECT)
    If PtInRect_(@gr,PeekQ(@cp))
      MapWindowPoints_(#Null, GadgetID(#PhotoView),cp,1) 
      StatusBarText(#StatusViewer, 5, "PosX: "+Str(cp\x))
      StatusBarText(#StatusViewer, 6, "PosY: "+Str(cp\y))
    Else 
      StatusBarText(#StatusViewer, 5, "PosX:")
      StatusBarText(#StatusViewer, 6, "PosY:")
    EndIf ;}
  EndIf
  
  ;Image gadget selection in list/gallery and actions :
  For i = 0 To ListSize(ScrollShowImage.ImageGalerie())-1 ;{  
    ShowImage = SelectElement(ScrollShowImage(), i)       ;ImageGadget()
    NewImg    = SelectElement(ScrollShowImage(), i)       ;The displayed thumbnail image
    PathImg   = SelectElement(ScrollShowImage(), i)       ;The location of the image on disk
    ImgName   = SelectElement(ScrollShowImage(), i)       ;The name of file
    Select Event
      Case #PB_Event_Gadget 
        Select EventGadget()  
          Case ScrollShowImage()\ShowImage ; l'ImageGadget()
            Select EventType()
              Case #PB_EventType_LeftDoubleClick
                PhotoGalerie$ = ScrollShowImage()\PathImg + ScrollShowImage()\ImgName
                OpenImageGalerie(PhotoGalerie$)
                NomPhoto$ = PhotoGalerie$               
              Case #PB_EventType_RightClick
                PhotoGalerie$ = ScrollShowImage()\PathImg + ScrollShowImage()\ImgName
                DisplayPopupMenu(#PopUp_Galerie,WindowID(#WinViewer))               
            EndSelect
        EndSelect         
    EndSelect ;}
  Next
  ;Recently viewed images = Panel/Image gadget selection in list and displaying :  
  For j = 0 To ListSize(ScrollViewed.ImageViewed())-1 ;{
    Panel     = SelectElement(ScrollViewed(), j)  ;PanelGadget() receiving the ImageGadget()    
    ViewImage = SelectElement(ScrollViewed(), j)  ;ImageGadget()
    CopyImg   = SelectElement(ScrollViewed(), j)  ;The displayed thumbnail image
    DirFile   = SelectElement(ScrollViewed(), j)  ;The location of the image on disk
    FileName  = SelectElement(ScrollViewed(), j)  ;The name of file
    BtnOpen   = SelectElement(ScrollViewed(), j)  ;The button to open in Windows image viewer
    BtnRemove = SelectElement(ScrollViewed(), j)  ;The button to remove of the list
    Select Event
      Case #PB_Event_Gadget 
        Select EventGadget() 
            
          Case ScrollViewed()\ViewImage ;{
            Select EventType()
              Case #PB_EventType_LeftDoubleClick
                PhotoGalerie$ = ScrollViewed()\DirFile + ScrollViewed()\FileName
                OpenImageGalerie(PhotoGalerie$)
                NomPhoto$ = PhotoGalerie$               
              Case #PB_EventType_RightClick
                PhotoGalerie$ = ScrollViewed()\DirFile + ScrollViewed()\FileName
                ;DisplayPopupMenu(#PopUp_Galerie,WindowID(#WinViewer))               
            EndSelect
            ;}
          Case ScrollViewed()\BtnOpen ;{  
            PhotoGalerie$ = ScrollViewed()\DirFile + ScrollViewed()\FileName
            If PhotoGalerie$
               ShellExecute_(0,"open",PhotoGalerie$,0,0,1)  
             EndIf   ;}             
          Case ScrollViewed()\BtnRemove ;{
             ; Release of all associated gadgets, the Panel last
             ; Libération de tous les gadgets associés, le Panel en dernier
             FreeGadget(ScrollViewed()\BtnOpen)
             FreeGadget(ScrollViewed()\BtnRemove)
             FreeGadget(ScrollViewed()\ViewImage)
             FreeGadget(ScrollViewed()\Panel)
             ; Deleting the item from the list / Suppression de l'élément dans la liste
             DeleteElement(ScrollViewed(),1) 
             ; After deleting the element, the display is adjusted so that there is no gap.
             ; The easiest way to do this is to resize all the PanelGadget()s in the list
             ; Après la suppression de l'élément on ajuste l'affichage pour qu'il n'y ait pas de trou.
             ; Pour cela le plus simple est de redimensionner tous les PanelGadget() de la liste
             PosyImg = 2
             If ListIndex(ScrollViewed())<>-1
               For Pan = 0 To ListSize(ScrollViewed.ImageViewed())-1     
                 SelectElement(ScrollViewed(),Pan)         
                 ResizeGadget(ScrollViewed()\Panel,0,PosyImg, 200, 100) 
                 PosyImg = PosyImg + 102
               Next
             EndIf             
             ;}
             
        EndSelect         
    EndSelect ;}
  Next 
  
  Select Event
      ;-Event Gadget             
    Case #PB_Event_Gadget 
      Select EventGadget()                 
          
        Case #PhotoView ;{          
          Select EventType() 
            Case #PB_EventType_LeftClick  
              ;Action to be taken if necessary
            Case #PB_EventType_RightClick
              ;Action to be taken if necessary
          EndSelect 
          ;}        
          
      EndSelect 
    ;-Event Menu  
     Case #PB_Event_Menu 
       Select EventMenu()
           
           Case #Tbar_btn_OpenFolder ;{
             If ThreadGalerie = 0
               If ChInitial$ = ""
                 ChInitial$ = GetUserDirectory(#PB_Directory_Pictures)
               Else 
                 ChInitial$ = ChInitial$
               EndIf
               ImagesDir$ = PathRequester("Sélectionnez un dossier d'images, elles seront ajoutées à la galerie", ChInitial$,WindowID(#WinViewer)) 
               If ImagesDir$<>""
                 ChInitial$ = ImagesDir$                 
                 If ListSize(ScrollShowImage()) <> 0
                   FreeGalerie()
                   ClearList(ScrollShowImage())
                 EndIf
                 CreateGallery(ImagesDir$)
                 ;ThreadGalerie = CreateThread(@CreateGallery(),0) 
               EndIf
             EndIf 
             ;}               
           Case #Tbar_btn_CloseImage ;{
             ImgInit = IsImage(#PhotoLoad) 
             If ImgInit <> 0 
               SetGadgetState(#PhotoView, 0)   
               ResizeGadget(#PhotoView, 0,0,0,0)
               StatusBarText(#StatusViewer, 4, "Taille : ")
               StatusBarText(#StatusViewer, 3, "Dimensions : ")
               StatusBarText(#StatusViewer, 2, "Vue :")
               FreeImage(#PhotoLoad)
             EndIf 
             ;}   
           Case #Tbar_btn_Redim : DisplayPopupMenu(#MenuSizes,WindowID(#WinViewer))
           Case #Tbar_btn_ActualSize;{
             If IsImage(#PhotoLoad) <> 0
               Hauteur = ImageHeight(#PhotoLoad)  
               Largeur = ImageWidth(#PhotoLoad) 
               SetMenuItemText(#PopUp_ActualSize,#DisplaySizeImage,"Dimensions image affichée : "+Str(Largeur)+" x "+Str(Hauteur))
               DisplayPopupMenu(#PopUp_ActualSize,WindowID(#WinViewer))
             Else 
               MessageRequester("Image","Pas d'image affichée.",#PB_MessageRequester_Warning,WindowID(#WinViewer))
             EndIf 
             ;}
           Case #Tbar_btn_ZoomIn : ZoomAuto(1.1)           
           Case #Tbar_btn_ZoomOut ;{ 
             If IsImage(#PhotoLoad)           ;si une image est affichée
               Wimg = ImageWidth(#PhotoLoad)  ;on récupère sa largeur
               Himg = ImageHeight(#PhotoLoad) ;on récupère sa hauteur           
               If Wimg <= 30 Or Himg <= 30
                 MessageRequester("Réduction d'image", "La dimension minimale est atteinte.",#PB_MessageRequester_Ok|#PB_MessageRequester_Info,WindowID(#WinViewer))
               ElseIf Wimg > 30 And Himg > 30
                 ZoomAuto(0.9)
               EndIf 
             EndIf 
             ;}
           Case #Tbar_btn_ZoomPercent : DisplayPopupMenu(#MenuPercentZoom,WindowID(#WinViewer))
             
           Case #Menu_SizeDiv2 : RedimImageSize_Div(2)      
           Case #Menu_SizeDiv4 : RedimImageSize_Div(4)        
           Case #Menu_SizeDiv6 : RedimImageSize_Div(6)        
           Case #Menu_SizeDiv8 : RedimImageSize_Div(8)
             
           Case #Menu_SizeMult2 : RedimImageSize_Mult(2)       
           Case #Menu_SizeMult4 : RedimImageSize_Mult(4)        
           Case #Menu_SizeMult6 : RedimImageSize_Mult(6)        
           Case #Menu_SizeMult8 : RedimImageSize_Mult(8)
             
           Case #Menu_Galerie_OpenFile ;{  
             If PhotoGalerie$
               ShellExecute_(0,"open",PhotoGalerie$,0,0,1)  
             EndIf   ;}  
           Case #Menu_Galerie_FileProperty ;{  
             If PhotoGalerie$
               FileProperty(PhotoGalerie$) 
             EndIf   ;} 
 
           Case #DisplaySizeImage ;{ 
             If IsImage(#PhotoLoad)
               Hauteur = ImageHeight(#PhotoLoad) : ValeurH$ = Str(Hauteur)  
               Largeur = ImageWidth(#PhotoLoad)  : ValeurL$ = Str(Largeur) 
               If ImageName$<>"" 
                 MessageRequester(ImageName$,"Dimensions de l'image affichée :"+Chr(13)+"Largeur : "+ValeurL$+"  pixels"+Chr(13)+"Hauteur : "+ValeurH$+"  pixels"+Chr(13)+"Emplacement : "+NomPhoto$ ,#PB_MessageRequester_Info,WindowID(#WinViewer))  
               EndIf
             EndIf
             ;}    
           Case #DisplayActualSize ;{
             If IsImage(#PhotoLoad)
               If NomPhoto$
                 If LoadImage(#PhotoLoad,NomPhoto$) 
                   Timgx = ImageWidth(#PhotoLoad)  : ValX$ = Str(Timgx) 
                   Timgy = ImageHeight(#PhotoLoad) : ValY$ = Str(Timgy) 
                   SetGadgetState(#PhotoView, ResizeImage(#PhotoLoad,Val(ValX$) ,Val(ValY$))) ; on remet l'image à sa taille réelle et initiale 
                   SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerWidth, ImageWidth(#PhotoLoad)) 
                   SetGadgetAttribute(#scroll_image, #PB_ScrollArea_InnerHeight, ImageHeight(#PhotoLoad)) 
                 EndIf
               EndIf 
             EndIf 
             ;} 
             
             ;-#MenuZoomIn           
           Case #ZoomIn_10  : zoom$ = "+10 %"  : ZoomInImage(zoom$) ;{
           Case #ZoomIn_20  : zoom$ = "+20 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_30  : zoom$ = "+30 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_40  : zoom$ = "+40 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_50  : zoom$ = "+50 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_60  : zoom$ = "+60 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_70  : zoom$ = "+70 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_80  : zoom$ = "+80 %"  : ZoomInImage(zoom$)
           Case #ZoomIn_90  : zoom$ = "+90 %"  : ZoomInImage(zoom$) 
           Case #ZoomIn_100 : zoom$ = "+100 %" : ZoomInImage(zoom$)
           Case #ZoomIn_120 : zoom$ = "+120 %" : ZoomInImage(zoom$)
           Case #ZoomIn_140 : zoom$ = "+140 %" : ZoomInImage(zoom$)
           Case #ZoomIn_150 : zoom$ = "+150 %" : ZoomInImage(zoom$)
           Case #ZoomIn_160 : zoom$ = "+160 %" : ZoomInImage(zoom$)
           Case #ZoomIn_180 : zoom$ = "+180 %" : ZoomInImage(zoom$)
           Case #ZoomIn_200 : zoom$ = "+200 %" : ZoomInImage(zoom$)
           Case #ZoomIn_220 : zoom$ = "+220 %" : ZoomInImage(zoom$)
           Case #ZoomIn_240 : zoom$ = "+240 %" : ZoomInImage(zoom$)
           Case #ZoomIn_260 : zoom$ = "+260 %" : ZoomInImage(zoom$)
           Case #ZoomIn_280 : zoom$ = "+280 %" : ZoomInImage(zoom$)
           Case #ZoomIn_300 : zoom$ = "+300 %" : ZoomInImage(zoom$)
           Case #ZoomIn_320 : zoom$ = "+320 %" : ZoomInImage(zoom$)
           Case #ZoomIn_340 : zoom$ = "+340 %" : ZoomInImage(zoom$)
           Case #ZoomIn_360 : zoom$ = "+360 %" : ZoomInImage(zoom$)
           Case #ZoomIn_380 : zoom$ = "+380 %" : ZoomInImage(zoom$)
           Case #ZoomIn_400 : zoom$ = "+400 %" : ZoomInImage(zoom$)
           ;}  
             ;-#MenuZoomOut 
           Case #ZoomOut_10 : zoom$ = "-10 %" : ZoomOutImage(zoom$) ;{
           Case #ZoomOut_20 : zoom$ = "-20 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_30 : zoom$ = "-30 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_40 : zoom$ = "-40 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_50 : zoom$ = "-50 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_60 : zoom$ = "-60 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_70 : zoom$ = "-70 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_80 : zoom$ = "-80 %" : ZoomOutImage(zoom$)
           Case #ZoomOut_90 : zoom$ = "-90 %" : ZoomOutImage(zoom$)
           ;}  
         EndSelect
       
     Case #PB_Event_CloseWindow : Quitter = 1 
  
EndSelect 
;-END 
Until Quitter 
End 

Re: Image gallery - with PanelGadget() and ImageGadget()

Posted: Sat Nov 16, 2024 10:12 am
by breeze4me
On Windows, a maximum of around 9000 windows (including child controls) can be created per process.
The panel gadget consists of one tab control and one container control per tab item. If a panel gadget has two tab items, the total number of controls is three.
Therefore, if a large number of images are loaded, no more panel gadgets or image gadgets may be created, as that limit may be exceeded.

And the maximum size of a control is probably 8192 pixels or something like that, IIRC.
So the inner size of the scrollarea gadget can't be larger than this limit either.

However, if all image gadgets and panel gadgets disappear, it may simply be an update issue, so try using APIs like RedrawWindow_() and UpdateWindow_().

And since gadget creation shouldn't be done in a thread, it should be done in the main event loop using the PostEvent() function.
This means that only loading images should be done within a thread, and any gadget-related manipulations should be done in the main event loop.

Code: Select all

;in a thread.
PostEvent(#Custom_Event_CreateGadgets)


; main event loop
...
If Event = #Custom_Event_CreateGadgets
  ...
  SetGadgetAttribute(..., #PB_ScrollArea_InnerHeight, ...)
  ...
  PanelGadget(#PB_Any, ...)
    ...
    ImageGadget(#PB_Any, ...)
    
  ...
EndIf
Edit:
My mistake. The limit of the size inside the scrollarea gadget is 32767 pixels. :oops:

Re: Image gallery - with PanelGadget() and ImageGadget()

Posted: Sat Nov 16, 2024 11:14 am
by Jacobus
breeze4me wrote: Sat Nov 16, 2024 10:12 am And since gadget creation shouldn't be done in a thread, it should be done in the main event loop using the PostEvent() function.
This means that only loading images should be done within a thread, and any gadget-related manipulations should be done in the main event loop.
Hi breeze4me, I had missed this information. Thanks for this detailed feedback.

Re: Image gallery - with PanelGadget() and ImageGadget()

Posted: Thu Apr 24, 2025 6:00 pm
by Jacobus
Hello,
I've updated the code in the first post, fixing some imperfections and adding features. This could be the basis for an image viewer.
A short video of how this image viewer works ici Video of Image Viewer