Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Recipe: Processing each file in a directory with a specific extension
Last updated at 1:29 pm UTC on 12 October 2006
Problem
I wanted to import some images of kanji characters, but ones I got off the web had white background (with exception of color words, which had the corresponding color bg). So I wanted to mass convert them to be transparent.

Solution
I ran the following code:

"read all gif images, make all colors, except black, transparent, open as a SketchMorph - like from FileList menu"
| slash dir image transparent black dirName |
slash _ FileDirectory slash.
black _ Color r:0 g:0 b: 0.
dirName _ (*2184* default pathName), slash, 'kanji', slash, 'matrix_kanji', slash.
dir _ FileDirectory on: dirName.

dir fileNames withIndexDo: [:fname :fid | (fname asLowercase endsWith: '.gif')
  ifTrue: [image _ GIFReadWriter formFromFileNamed: dirName, fname.
    transparent _ (image colors select: [:c | c isTransparent]) first.
    image colors withIndexDo: [:c :i |
      (c isTransparent not and: [(c = black) not])
         ifTrue: [image colors at: i put: transparent]].

   World addMorph: (image _ SketchMorph new form: image).
   image position: (fid*10)@(fid*10)]].

Source: Squeak mailing list - Bolot Kerimbaev -
Subject: [GOODIE] selecting multiple morphs, kanji fun
Date: Wed, 17 Nov 1999

Another example that recursively visits sub-dirs


Note the use of #readOnlyFileNamed:, #baseNameFor, and #directoryNamed: to build up fully qualified filenames, rather than platform-specific string concatenation. nb #readOnlyFileNamed: is useful in that it won't silently create files when your logic isn't correct!


scaleImagesOnPath: aPath toSize: anExtent
    | dir form filename |
    dir := FileDirectory on: aPath.
    Transcript cr; show: dir pathName.

	(dir fileNames
		select: [:each |
			(each asLowercase endsWith: '.jpg')
			and: [(each includesSubString: 'thumb') not]])
	do: [:key |
		form := Form fromBinaryStream: (dir readOnlyFileNamed:  key).
		filename := dir fullPathFor: (FileDirectory baseNameFor: key) , '-thumb.jpg'.
		dir deleteFileNamed: filename.
		JPEGReadWriter2
			putForm: (form scaledToSize: anExtent)
			onFileNamed: filename].
	"recurse"
	dir directoryNames
		do: [:each |
			self scaleImagesOnPath:
				(dir directoryNamed: each) pathName toSize: anExtent]

Based on an example from Ramon Leon's excellent blog.



Use a pattern


Separate the directory traversal from the processing, thus:

traverse: aFileDirectory doing: aBlockWithFileArgument
	aFileDirectory fileNames 
		do: [ :p | aBlockWithFileArgument value: (aFileDirectory fullPathFor: p)].

	aFileDirectory directoryNames 
		select: [ :d | (d startsWith: '.') not]
		thenDo: [ :d | self traverse: (aFileDirectory directoryNamed: d) doing: aBlockWithFileArgument  ].



Call this code, eg:

	self 
		traverse: (FileDirectory on: 'c:\') 
		doing: [ :fp | Transcript show: fp; cr.].