Compress and timestamp your pictures to gain disk space

I was running out of space again on my notebook. As years go by, digital cameras can take pictures with more megapixels, but that means they take up more space.

Thus my pictures from 10 years ago are much smaller than this year’s.

Since I have multiple copies of my picture collection (28,000!) I didn’t mind modifying the notebook’s copy. Also, since the notebook resolution is 1400 X 1050, and I only ever display the notebook pictures on the notebook screen, the camera picture’s resolution 3072 X 2074 (Canon Powershot SD800) included more info than I needed.

The code resulted in most pictures compressing about 80%! You can vary the quality parameter and try it yourself. Also, my disk contains all the movies taken by the camera too, and these aren’t touched by the code.

So I ran the code below and gained 5 Gigabytes of storage! Not bad.

The code uses the GDIPlus class library to load, compress and store the file. This changes the file timestamp, so the code also preserves the original timestamp.

See also:

Recompress your digital pictures to save space

Resize your pictures for your phone or pocket pc

Timestamp digital pictures

cRoot=ADDBS("d:\pictures\2006\")

recurdir(cRoot)

?"Done",DATETIME()

PROCEDURE recurdir(cBasePath)

          LOCAL n,i

          LOCAL aa[1]

          ?cbasePath

          n=ADIR(aa,cBasePath+"*.*","D")

          FOR i = 1 TO n

                   IF "D"$aa[i,5]

                             IF LEFT(aa[i,1],1)<>"."

                                      recurdir(cBasePath+aa[i,1]+"\")

                             ENDIF

                   ELSE

                             IF LOWER(JUSTEXT(aa[i,1]))="jpg"

                                      recompress(cBasePath+aa[i,1])

                                      retimestamp("d:\t.jpg",CTOT(DTOC(aa[i,3])+" "+aa[i,4]))

                                      COPY FILE d:\t.jpg TO (cBasePath+aa[i,1])

                             ENDIF

                   ENDIF

          ENDFOR

          RETURN

         

PROCEDURE recompress(cPict as String)

          LOCAL aa[1]

          cOutfile="d:\t.jpg"

          LOCAL oImage as gpImage OF (HOME()+"ffc\_gdiplus")

          oImage=NEWOBJECT("gpImage",HOME()+"ffc\_gdiplus","",cpict)

          oImage.SaveToFile(cOutfile,"image/jpeg","Quality=20")

          ADIR(aa,cOutfile)

          nSizeNew=aa[1,2]

          ADIR(aa,cPict)

          nSizeOrig=aa[1,2]

          ?cPict

          ??" Orig Size = ",TRANSFORM(nSizeOrig,"999,999,999")

          ??" New Size = ",TRANSFORM(nSizeNew,"999,999,999")

* ??" # bytes smaller = ", TRANSFORM(nSizeOrig - nSizeNew,"999,999,999")

          ??" # times smaller", TRANSFORM(nSizeOrig / nSizeNew)

          ??" % savings=", TRANSFORM(100*(nSizeOrig - nSizeNew)/nSizeOrig )

          *! &cOutfile

RETURN

*From WINNT.H:

#define FILE_SHARE_READ 0x00000001

#define FILE_SHARE_WRITE 0x00000002

#define FILE_SHARE_DELETE 0x00000004

#define FILE_ATTRIBUTE_READONLY 0x00000001

#define FILE_ATTRIBUTE_HIDDEN 0x00000002

#define FILE_ATTRIBUTE_SYSTEM 0x00000004

#define FILE_ATTRIBUTE_DIRECTORY 0x00000010

#define FILE_ATTRIBUTE_ARCHIVE 0x00000020

#define FILE_ATTRIBUTE_DEVICE 0x00000040

#define FILE_ATTRIBUTE_NORMAL 0x00000080

#define FILE_ATTRIBUTE_TEMPORARY 0x00000100

#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200

#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400

#define FILE_ATTRIBUTE_COMPRESSED 0x00000800

#define FILE_ATTRIBUTE_OFFLINE 0x00001000

#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000

#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000

#define FILE_WRITE_ATTRIBUTES 0x100

#define GENERIC_WRITE (0x40000000)

#define GENERIC_READ (0x80000000)

*From winbase.h:

#define CREATE_NEW 1

#define CREATE_ALWAYS 2

#define OPEN_EXISTING 3

#define OPEN_ALWAYS 4

#define TRUNCATE_EXISTING 5

PROCEDURE ReTimeStamp(cFilename as string, dt as Datetime)

                   DECLARE integer CreateFile in win32api string, integer dwDesiredAccess, integer dwShareMode, integer security, ;

                             integer dwCreationDisposition, integer FlagsAttrs, integer hTemplate

                   DECLARE INTEGER CloseHandle in win32api integer hFile

                   DECLARE integer SystemTimeToFileTime IN WIN32API string , string @

                   DECLARE INTEGER SetFileTime IN kernel32;

                             INTEGER hFile, STRING lpCreationTime,;

                             STRING lpLastAccessTime, STRING lpLastWriteTime

                   DECLARE INTEGER SystemTimeToFileTime IN kernel32;

                             STRING lpSystemTime, STRING @lpFileTime

                   DECLARE INTEGER LocalFileTimeToFileTime IN kernel32;

                             STRING lpLocalFileTime, STRING @lpFileTime

                   DECLARE integer GetLastError in win32api

                   cFileTime = SPACE(8)

                   cSysTime=BINTOC(YEAR(dt),"2rs") + ;

                                      BINTOC(MONTH(dt),"2rs") + ;

                                      BINTOC(DOW(dt,0),"2rs") + ;

                                      BINTOC(DAY(dt),"2rs") + ;

                                      BINTOC(HOUR(dt),"2rs") + ;

                                      BINTOC(MINUTE(dt),"2rs") + ;

                                      REPLICATE(CHR(0),4)

                   SystemTimeToFileTime(cSysTime, @cFileTime)

 

                   LocalFileTimeToFileTime(cFileTime, @cFileTime)

                   hFile = CreateFile(cFilename, GENERIC_WRITE+GENERIC_READ,FILE_SHARE_READ, 0, OPEN_EXISTING, 0,0)

                   SetFileTime(hFile , cFileTime, cFileTime,cFileTime)

                   CloseHandle(hFile)

RETURN