Does the world need yet another Photo Viewer application?
I doubt it. But I needed something which would help with my photographic work-flow, so I wrote my own.
With three keen SLR camera users in our house, I noticed that at least two of us were following a similar process. Once we had transferred our photos to our Linux powered laptops, we would:-
- Review each photo in turn
- Delete the "no-hope" pictures
- Rename any we wanted to keep that did not require edits
- Launch GIMP for those that did require edits
- Show our best efforts to long suffering friends & relatives
- Review camera settings when asked "How did you do that?"
So I set about making a new Photo Viewer application using my language of choice: Gambas
PhotoViewer running on Lubuntu
Gambas is a kind of Basic language dialect and has a nice, visual, integrated development environment (IDE). Once you've written and debugged your application, you can create a Linux installation package in a number of formats including ".deb" which is suitable for Debian, Lubuntu and other Ubuntu distributions.
Its an obvious choice for someone like me, who used to work quite a bit with VB.classic, and swore he'd never look at another line of C++ code after leaving industry and drifting into semi-retirement.
This application code is written in Gambas2, but would probably be OK in Gambas3, and I suspect it could be re-written in Visual Basic without too much trouble.
This application relies upon the Linux package "exif" to provide data from the image about camera settings. The "Edit with GIMP" menu item requires the installation of GIMP 2.6, but this could easily be changed or extended to include your favourite graphics editor.
There are just 3 screen components plus a timer on the one and only form (FMain):-
The menu bar includes the following menus & items:-
...and this is the FMain.class code. Sorry the full indentation has been lost, but at least I have hand-coloured the comments green:-
' Gambas class file
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' PhotoViewer
'------------
'Yet another Photo Viewer application, but this pulls together the options
'that I need when working on photos.
'Need to install the following Linux packages for this app:-
' "exif" {essential}
' "gimp-2.6" {optional}
'
'Steve Davis
'July 2012
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PUBLIC strPhotoPath AS String
PUBLIC blnBigPic AS Boolean 'use most of screen for photo
PUBLIC SUB _new()
DIM strTest AS String
DIM strInitialPath AS String 'initial dir for File Picker
'Only run one instance of this app
EXEC ["pgrep", "-f", "-l", Application.Name & ".gambas"] WAIT TO strTest
IF Split(Trim$(strTest), gb.newLine).Count > 1 THEN
'Already running, so quit
QUIT
ENDIF
'We need exif to extract photo data
strTest = ""
EXEC ["whereis", "exif"] TO strTest
IF InStr(strTest, "bin/exif") = 0 THEN
Message.Info("Please install: exif", "close")
QUIT
ENDIF
'check for GIMP as this is our editor
strTest = ""
EXEC ["whereis", "gimp"] TO strTest
IF InStr(strTest, "bin/gimp") = 0 THEN
mnuGimp.Enabled = FALSE
ENDIF
'load user settings
strInitialPath = Settings["Settings/InitDir", User.Home & "/Pictures"]
IF NOT Exist(strInitialPath) THEN
strInitialPath = User.Home
ENDIF
FilePicker.Dir = strInitialPath
FilePicker.ShowHidden = FALSE
IF Settings["Settings/DataFilter", "true"] = "true" THEN
mnuFilter.Checked = TRUE
ENDIF
END
PUBLIC SUB Form_Open()
END
PUBLIC SUB tmrStart_Timer()
'now form has loaded, draw controls
tmrStart.Stop
DrawControls
END
PUBLIC SUB DrawControls()
WITH FilePicker
.Width = ME.Width * 0.55
.Height = ME.Height * 0.4
.Left = ME.Width * 0.01
.Top = ME.Height * 0.01
.Filter = ["*.png;*.jpg;*.jpeg;*.bmp", "Picture files"]
.Visible = TRUE
END WITH
WITH pBox
.Width = ME.Width * 0.55
.Height = ME.Height * 0.54
.Left = ME.Width * 0.01
.Top = ME.Height * 0.01 + FilePicker.Top + FilePicker.Height
.Visible = TRUE
END WITH
WITH gViewExif
.Width = ME.Width * 0.42
.Height = ME.Height * 0.95
.Left = ME.Width * 0.57
.Top = ME.Height * 0.01
.Columns.Count = 2
.Columns[0].Width = gViewExif.Width * 0.4
.Columns[1].Width = gViewExif.Width * 0.6
.Visible = TRUE
END WITH
END
PUBLIC SUB DrawPhotoBox(blnLarge AS Boolean)
IF blnLarge THEN
WITH pBox
.Width = ME.Width * 0.95
.Height = ME.Height * 0.9
.Left = ME.Width * 0.01
.Top = ME.Height * 0.01
.Raise
END WITH
FilePicker.Hide
gViewExif.Hide
ELSE
WITH pBox
.Width = ME.Width * 0.55
.Height = ME.Height * 0.54
.Left = ME.Width * 0.01
.Top = ME.Height * 0.01 + FilePicker.Top + FilePicker.Height
END WITH
FilePicker.Show
gViewExif.Show
ENDIF
END
PUBLIC SUB FilePicker_Change()
'user has selected a photo...so load it
strPhotoPath = FilePicker.SelectedPath
LoadPhoto
END
PUBLIC SUB LoadPhoto()
DIM strPhotoName AS String
DIM picPhoto AS NEW Picture
DIM fFactor AS Float
IF strPhotoPath <> "" THEN
strPhotoName = Mid(strPhotoPath, RInStr(strPhotoPath, "/") + 1)
strPhotoName = Mid(strPhotoName, 1, InStr(strPhotoName, ".") - 1)
IF InStr(UCase(strPhotoPath), ".") > 0 THEN
pBox.Hide
DrawPhotoBox(mnuBigPic.Value)
picPhoto = Picture.Load(strPhotoPath)
IF (picPhoto.Width * 4 / 5.63) > picPhoto.Height THEN
fFactor = pBox.Width / picPhoto.Width
ELSE
fFactor = pBox.Height / picPhoto.Height
ENDIF
pBox.Resize(picPhoto.Width * fFactor, picPhoto.Height * fFactor)
pBox.Picture = picPhoto
pBox.Stretch = TRUE
pBox.Show
GetExif()
ENDIF
ENDIF
CATCH
'file does not exist in this dir!
IF Error.code <> -1 THEN
Message.Info("Error: " & Error.Code & " - " & Error.Text, "close")
ENDIF
END
PUBLIC FUNCTION GetExif() AS String
DIM strEXIF AS String
DIM index AS Integer
DIM strParam AS String
gViewExif.Clear
gViewExif.Rows.Count = 1
EXEC ["exif", strPhotoPath] TO strEXIF
IF InStr(strEXIF, "Model") > 0 THEN
strEXIF = Mid(strEXIF, InStr(strEXIF, "Model"))
index = 0
DO UNTIL InStr(strEXIF, "|") = 0
IF mnuFilter.Checked = TRUE THEN 'select limited data
strParam = Mid(strEXIF, 1, InStr(strEXIF, "|") - 1)
IF FilterExif(strParam) = TRUE THEN
gViewExif.Rows.Count = index + 1
gViewExif.Row = index
gViewExif[index, 0].Text = Mid(strEXIF, 1, InStr(strEXIF, "|") - 1)
strEXIF = Mid(strEXIF, InStr(strEXIF, "|") + 1)
gViewExif[index, 1].Text = Mid(strEXIF, 1, InStr(strEXIF, Chr(10)) - 1)
INC index
ENDIF
ELSE 'show all data
gViewExif.Rows.Count = index + 1
gViewExif.Row = index
gViewExif[index, 0].Text = Mid(strEXIF, 1, InStr(strEXIF, "|") - 1)
strEXIF = Mid(strEXIF, InStr(strEXIF, "|") + 1)
gViewExif[index, 1].Text = Mid(strEXIF, 1, InStr(strEXIF, Chr(10)) - 1)
INC index
ENDIF
strEXIF = Mid(strEXIF, InStr(strEXIF, Chr(10)) + 1)
LOOP
gViewExif.Row = 0
ELSE
gViewExif[0, 0].Text = "No EXIF Data"
ENDIF
CATCH
Message.Error("Error: " & Error.Text, "close")
END
PUBLIC SUB mnuExit_Click()
QUIT
END
PUBLIC SUB mnuGimp_Click()
IF strPhotoPath <> "" THEN
EXEC ["gimp-2.6", strPhotoPath]
ELSE
Message.Warning("Nothing selected to edit", "close")
ENDIF
END
PUBLIC SUB mnuRename_Click()
DIM lngReply AS Long
DIM strPath AS String
DIM strExtension AS String
DIM strNewName AS String
DIM strNewPathName AS String
IF strPhotoPath = "" THEN
Message.Warning("Hey, no photo selected to rename!", "close")
ELSE
strNewName = InputBox("Enter new file name (without extension) or cancel", "Change File Name?", "")
IF strNewName <> "" THEN
strPath = Mid(strPhotoPath, 1, RInStr(strPhotoPath, "/"))
strExtension = Mid(strPhotoPath, InStr(strPhotoPath, "."))
strNewPathName = strPath & strNewName & strExtension
IF Exist(strNewPathName) THEN
Message.Warning("No chance! This file name already exists.", "Close")
ELSE
TRY MOVE strPhotoPath TO strNewPathName
IF ERROR THEN
Message.Info("Sorry mate! That didn't work!", "Close")
ELSE
strPhotoPath = strNewPathName
'need to do this to update FileChooser
FilePicker.SelectedPath = strNewName
FilePicker.Dir = strPath
ENDIF
ENDIF
ENDIF
ENDIF
END
PUBLIC SUB mnuDelete_Click()
DIM lngReply AS Long
IF strPhotoPath = "" THEN
Message.Warning("You didn't select a photo for deletion!", "close")
ELSE
lngReply = Message.Question("Are you sure you want to delete: " & strPhotoPath & "?", "Yes", "No")
FilePicker.Id
IF lngReply = 1 THEN
TRY KILL strPhotoPath
IF NOT ERROR THEN
pBox.Hide
gViewExif.Clear
gViewExif.Rows.Count = 1
ENDIF
ENDIF
ENDIF
END
PUBLIC SUB mnuAbout_Click()
DIM strVersion AS String
strVersion = Application.Version
Message.Info("PhotoViewer version: " & strVersion & " by Steve Davis", "close")
END
PUBLIC SUB mnuBigPic_Click()
LoadPhoto
END
PUBLIC SUB mnuDefaultDir_Click()
Settings["Settings/InitDir"] = User.Home & "/Pictures"
mnuDefaultDir.Checked = TRUE
mnuCurrDir.Checked = FALSE
END
PUBLIC SUB mnuCurrDir_Click()
Settings["Settings/InitDir"] = FilePicker.Dir
mnuCurrDir.Checked = TRUE
mnuDefaultDir.Checked = FALSE
END
PUBLIC FUNCTION FilterExif(strParam AS String) AS Boolean
'just display data for parameters containing the following strings:-
IF InStr(LCase(strParam), "model") > 0 THEN
RETURN TRUE
ENDIF
IF InStr(LCase(strParam), "exposure") > 0 THEN
RETURN TRUE
ENDIF
IF InStr(LCase(strParam), "f-n") > 0 THEN
RETURN TRUE
ENDIF
IF InStr(LCase(strParam), "iso") > 0 THEN
RETURN TRUE
ENDIF
IF InStr(LCase(strParam), "length") > 0 THEN
RETURN TRUE
ENDIF
IF InStr(LCase(strParam), "white") > 0 THEN
RETURN TRUE
ENDIF
END
PUBLIC SUB mnuFilter_Click()
IF mnuFilter.Checked = TRUE THEN
Settings["Settings/DataFilter"] = "true"
ELSE
Settings["Settings/DataFilter"] = "false"
ENDIF
END
One feature I'd still like to add is a histogram display. I took a quick look at the "ImageJ" stuff, but haven't worked out what to do with it. But if anyone has any ideas.....
Gambas: http://gambasdoc.org/help?v2
No comments:
Post a Comment