'From Squeak3.3alpha of 28 January 2002 [latest update: #4661] on 11 February 2002 at 1:56:49 pm'! "Change Set: jMovieFrameSorting-jm Date: 11 February 2002 Author: John Maloney Two tweaks to JPEG movies: 1. When creating a movie from a folder of frames, skip file names without embedded digits. This helps keep non-image files, such as the 'Icon' file added by some file servers, from being treated as frames. 2. If a movie player was open in a Squeak snapshot, re-open the file on demand if the movie is played after the snapshot has been resumed. (The movie will resume from the beginning.)" ! !JPEGMovieFile methodsFor: 'file ops' stamp: 'jm 2/11/2002 13:09'! openFile: fileName "For compatability with MPEGFile." self openFileNamed: fileName. ! ! !JPEGMovieFile methodsFor: 'file ops' stamp: 'jm 2/11/2002 13:30'! openFileNamed: fileName "Open the JPEG movie file with the given name." file ifNotNil: [file finalize]. file _ nil. (FileDirectory default fileExists: fileName) ifFalse: [^ self]. file _ (FileStream readOnlyFileNamed: fileName) binary. self readHeader. currentFrameIndex _ 1. ! ! !JPEGMovieFile class methodsFor: 'movie conversion' stamp: 'jm 1/25/2002 20:46'! convertFromFolderOfFramesNamed: folderName toJPEGMovieNamed: jpegFileName frameRate: frameRate quality: quality "Convert a folder of frames into a JPEG movie. The named folder is assumed to contain only image files, all of the same size, and whose alphabetical order (case-insensitive) is the sequence in which they will appear in in the movie. A useful convention is to make the image files end in zero-padded frame numbers, for example 'frame0001.bmp', 'frame0002.bmp', etc. The image files can be any format readable by Form>fromFileNamed:. The movie frame extent is taken from the first frame file." | jpegFile dir fileNames frameCount frameForm frameOffsets | (FileDirectory default directoryExists: folderName) ifFalse: [^ self inform: 'Folder not found: ', folderName]. jpegFile _ (FileStream newFileNamed: jpegFileName) binary. dir _ FileDirectory default on: folderName. fileNames _ self sortedByFrameNumber: dir fileNames. frameCount _ fileNames size. frameForm _ Form fromFileNamed: (dir fullNameFor: fileNames first). "write header" self writeHeaderExtent: frameForm extent frameRate: frameRate frameCount: frameCount soundtrackCount: 0 on: jpegFile. "convert and write frames" frameOffsets _ Array new: frameCount + 1. 1 to: frameCount do: [:i | frameOffsets at: i put: jpegFile position. frameForm _ Form fromFileNamed: (dir fullNameFor: (fileNames at: i)). self writeFrame: frameForm on: jpegFile quality: quality displayFlag: true]. frameOffsets at: (frameCount + 1) put: jpegFile position. self updateFrameOffsets: frameOffsets on: jpegFile. jpegFile close. Display restore. ! ! !JPEGMovieFile class methodsFor: 'movie creation-private' stamp: 'jm 1/25/2002 21:08'! extractFrameNumberFrom: aString "Answer the integer frame number from the given file name string. The frame number is assumed to be the last contiguous sequence of digits in the given string. For example, 'take2 005.jpg' is frame 5 of the sequence 'take2'." "Assume: The given string contains at least one digit." | end start | end _ aString size. [(aString at: end) isDigit not] whileTrue: [end _ end - 1]. start _ end. [(start > 1) and: [(aString at: start - 1) isDigit]] whileTrue: [start _ start - 1]. ^ (aString copyFrom: start to: end) asNumber ! ! !JPEGMovieFile class methodsFor: 'movie creation-private' stamp: 'jm 2/3/2002 10:14'! sortedByFrameNumber: fileNames "Sort the given collection of fileNames by frame number. The frame number is the integer value of the last contiguous sequence of digits in the file name. Omit filenames that do not contain at least one digit; this helps filter out extraneous non-frame files such as the invisible 'Icon' file that may be inserted by some file servers." | filtered pairs | "select the file names contain at least one digit" filtered _ fileNames select: [:fn | fn anySatisfy: [:c | c isDigit]]. "make array of number, name pairs" pairs _ filtered asArray collect: [:fn | Array with: (self extractFrameNumberFrom: fn) with: fn]. "sort the pairs, then answer a collection containing the second element of every pair" pairs sort: [:p1 :p2 | p1 first < p2 first]. ^ pairs collect: [:p | p last]. ! ! !StandardFileStream methodsFor: 'open/close' stamp: 'jm 2/6/2002 08:33'! closed "Answer true if this file is closed." ^ fileID isNil or: [(self primSizeNoError: fileID) isNil] ! !