Home and Links
 Your PC and Security
 Server NAS
 DVD making
 Raspberry Pi
 PIC projects
 Other projects
 Next >>

QBASIC scripts for PhotoStory 3

QBasic for PhotoStory
In creating my QBasic scripts I made extensive use of the Wikibooks Qbasic command list. However (like Wikipedia) the site now uses an aggressive filter to 'detect' non-constructive changes. Since I can't be bothered to 'report' all the 'false positives' it throws up against my corrections, I have created my own Qbasic commands list (on my 'Next>>' page)

If you have any version of Microsoft Visual Basic (VB) on your computer, the '.bas' extension will be 'associated' with VB. Double clicking your script.bas will then open the VB project GUI. To change this, right click your script.bas and select 'Open with', 'Choose program' and Browse to c:\QBASIC\QBASIC.exe (and set the 'Always use the selected program to open this kind of file/ tick box)

Quick list of my scripts, right click and 'save link as' (for more details, see below)

Note 1 - in every case the PhotoStory project.xml must be 'pre-processed' to convert the 'new line' characters into 'CR + LF' characters before running any QBasic script (if not, the script will abort with 'Out of String Space' error)

Note 2 - the scripts are designed to be run from your C:\QBASIC folder. The 'source' Project.xml must be unpacked (and cr/lf processed) into C:\QBASIC\PSTORY3.

Note 3 - if you double click a .BAS file link (below), Windows will try to 'launch' whatever is associated with the .BAS extension on your PC (or you will get a 'File not found' error) To download, right click the link and 'Save As'.

All rights reserved, all scripts provided 'as is' with no warranty etc. (all the scripts (over)write files in the C:\QBASIC\PSTORY3\ folder without warning)

trim2dvd.BAS Trims each photo to the minimium needed eg DVD, if trimw%=768 (height 3/4 is 576)

chop133a.BAS Chop out the used area and expand height to 133% for 16x9 conversion (this version maintains crop box centre position)


TRANSTN.BAS Splits off each Transition as a new entry in project.xml

TRAN-FRZ.BAS Transition freezer (splits off all transitions as new entries)


SPEED-UP.BAS Speed up = halve all timings (or 1/2.5, if "SLOW_X25" flag is found)



SLOW-X25.BAS Slow down, 2.5x all timings

SLOW-DWN.BAS Slow down = double all timings

REL-RECT.BAS Checks and adjusts the Relative Rect values (+ centers photo in bounding box)


PS3-2PFS.BAS Generates CSV for migration to PhotoFilmStrip (PFS)


HD 16X9

HD169MIN.BAS Height distort by 133% and resolution adjust to the minimum for HD (1920 x 1440)

HD-16X9.BAS 133% height and 2x HD resolution set (3840 x 2880 pixels)

DVD 16X9

7K 16X9

7K-16X9.BAS Adjusts height to 133% and size to 7200 pixels

43to169.BAS Adjusts photo height to 133% (for 16x9) and maximises size (to 7k pixels)

16X9 JPG

What is QBASIC ?

QBASIC is an ancient 'DOS' implementation of the 'BASIC' language. It is still in use today because of it's small 'footprint' (fits on one floppy disc :-) ), lack of 'baggage' (for example, it doesn't use DLL's), excellent string handling capabilities and the huge number of 'legacy' scripts in existence.

Needless to say, it's no longer available from Microsoft. The last version (1.1) was shipped with MS-DOS 6.x, Windows 95, 98 and Me. It can be downloaded from the Internet Archive as part of the Windows 95 'CD ROM Extras', "Old MS-DOS Utilities" set

A modern, rather more bloated (80Mb, before unzipping) rebuild, for both 32bit and 64bit Windows XP, Vista, Win 7 (and Linux, MacOS X) is available from QB64.net

It also extremely quick and easy to 'throw something together' when you want to do something 'today' (rather than next month or next year)
NB. To avoid confusion, your QBasic file name should conform to the DOS file name conventions, known as '8.3', specifically, a name of 8 upper-case** characters max. (with no embedded spaces) and the file extension '.BAS').
**Whilst lower case names are supported, it's a good idea to 'get into the habit' of using upper-case to distinguish a QBasic file (rather than something for Visual Basic).

It's main drawback is it's very poor file handling capabilities. Often a QBasic script will be written to perform string operations on files 'fed' to it by a CMD (or BAT) file script

How do you use QBasic scripts with PhotoStory 3 ?

The first step is to unpack the .wp3 using 7-zip. The unpacked project.xml is then 'processed' in Notepad++ to add end of line 'cr/lf' characters (if you don't do this, the QBasic script will fall over with an 'Out of string space' error).

The simplest way to add cr/lf is to do a Replace on '>' to '>\r\n'

All the unpacked files are then moved into a folder where the QBasic script 'expects' to find them (for example c:\QBASIC\PSTORY) and the script is 'run'. If all goes well, the processed PhotoStory files can then be re-packed into a new .wp3 file

Note, my scripts are intended for use only when you are happy with the way your Story has been 'built' and immediately before 'final' output. You should avoid making changes to the Story after running a script - instead delete the 'script processed' .wp3 and go back to the 'original'

The only exception is 'tweaking' the crop box positions after (one of) the 16x9 scripts has been run

Note that the 'Transition freezer' script (TRAN_FRZ.BAS, see below)  will generate timing values 'not allowed' by the PhotoStory 3 'customise' GUI. Whilst these values will be 'accepted' for Preview and Output, 'opening' a photo in 'customise' window will result in the timing values being 'reset'

Using a QBasic script to optimise photos

What follows is a explanation of 'how a typical script works'. For the actual scripts, see below

All my scripts require that the .wp3 project file be 'unpacked' and copied into the C:\QBASIC\PSTORY folder before running the script. After running the script, the entire contents of C:\QBASIC\PSTORY should be re-packed into the new .wp3 project file.

Before copying Project.xml into \PSTORY, don't forget to add Windows line breaks ('cr/lf' codes), eg by replacing '>' with '>\r\n' (using Notepad++), otherwise you will get an 'Out of string space' Error when the QBASIC script tries to 'read' the first line of the project.xml :-)

Description of a photo processing script

The DVD_16x9.BAS script is used to optimise and resolution distort the photos in your Story prior to output using the 'DVD' (720x576.prx) Profile for a final 'target' playback on a widescreen 16:9 display

To avoid any possibility of PhotoStory 'interpolating up', photos will be resized so that the (smaller) crop box cuts out an area twice that required to build a DVD. In order that the area be used for 16:9 display, it has to be 'height adjusted' by 4/3rds (i.e. zoomed by 133%).

All the Project.xml 'crop' position and size settings have to 'match' the new photo sizes, so this is quite a complex script !

NB. The real script creates a log file (so you can track down any 'odd effects') as it goes along

For each photo VisualUnit (VU) :-
First extract the position of the start and end 'crop box'. The positions are adjusted so they lie completely within the photo. The 'bounding box' offsets can then be removed Next calculate the sizes of the start and end 'crop box'. Using the crop box size and positions, the photo 'Used Area' is calculated. The initial zoom factor is calculated, based on the smaller of the two crop boxes, for 2x DVD output (target DVD for square pixel 4:3 crop is 768x576, so twice is 1562x1152) The photo output size is calculated (= Used Area width * zoom factor by Used Area height * zoom * 4/3). If either dimension would exceed 7200 pixels, the zoom factor is reduced The aspect ratio of the output User Area (output width : output height) is now checked If it's not 4:3, the PhotoStory will add a bounding box with 'black bands' to the width or height - so the 'used area' width or height is expanded (by adding back 'unused' pixels) so the output will be as close to 4:3 as possible. The 7200 limit is then reapplied to get the final zoom factor Based on the final zoom, the start and end crop box new sizes and new positions are calculated The start and end crop box Y (height) positions are then adjusted by adding 1/6 of their new height (this re-centres each crop box within it's 4/3rds height distorted crop area) The new 'bounding box' is calculated and the offsets added to the crop box positions The Motion2 'RelativeRect' values are now calculated (if this is not done, the old values will 'overwrite' the crop box positions when the Story is next opened) The photo is cropped and zoomed (with 4/3rds height distort) using ImageMagick 'convert' command line utility and all the new VU parameters written to the new project temp file. Once all the photo VUs have been processed, the files are closed, the original project.xml is deleted and the temp file renamed as the new project.xml

Limitations of the QBasic 'DVD_169.bas' script

1) To avoid 'edge effects', the script starts by repositioning both crops boxes to within the actual photo area - so a crop box that was deliberately placed 'off the side edge' (or off the top or bottom) of the photo (i.e. partially in the black band 'bounding box' area), will be 'reset' so it is now completely within the photo

If you cropped a portrait off both sides (or a landscape off both top and bottom), the actual crop box size will also be reduced (so it fits completely within the photo)The size will also be changed if the crop box starts 'off one edge' and moving it 'at the same size' means it would 'go off the other edge'. To avoid this, you would have to edit the photo before Importing it (i.e. add your own 'black bands' as actual pixels to the sides)

2) The script will 'add back' some 'unused' parts of the image to make it closer to 4:3 (i.e. fill in what would otherwise be black band 'bounding box'). The script will try to 'add back' evenly from the top/bottom or each side, however this often means you end up with unwanted sky (whilst chopping off half the legs)

There is no easy solution to this (what's good for one photo may be bad for another), other than by 'guiding' the script in some way (see 'using narration tips', below)

3) The 'zoom factor' is calculated so it is just sufficient to generate 2x output width pixels for the smaller of the start / end crop boxes. This limits the zoom, even when a higher factor would have been possible (i.e. when a higher zoom would still fit within the 7200 limit)

This is only really an issue if you want to make changes to crop box zoom after running the 'just before output' script

4) The 4/3rds (133%) height adjust means that, after the adjust, the 'cropped width' will be 'unchanged' (i.e. the crop box will still contain 'all' the original width pixels) whilst the image height area within the 'crop box' will be 'expanded out' of the crop box (equally at top and bottom i.e. by 15%).

Whilst the calculations ensure this 'expanding out' is equal top & bottom this may not be what is wanted. However, the image area that was 'expanded out' of the crop box still forms part of the (cropped) output photo. This allows the crop box to be manually repositioned after the script is run

Script control using 'Narration Tips'

To control script operation on a 'per photo' basis, the 'narrationTips=""' field (at the end of the 'Image path="" XML entry for a VisualUnit) could be used.

Since the PhotoStory GUI allows you to enter whatever text you like into this field (and have it preserved across project 'saves'), it could be used for 'script control flags' (or, indeed, anything else you wanted to store on a 'per photo' basis)Indeed, a complete 'language' of control flags could be invented = for example 'NoCropMove', 'NoImgeChop', 'NoTop/Bottom/Left/Right AddBack', 'MaximiseZoom' etc.

QBasic scripts for 16:9 output

PhotoStory 3 has a fixed 4:3 'crop box' tool. So, in order to output 16:9, you have to distort the photos (so the 4:3 crop gets a 16:9 area)

There are two ways this can be done, 'compress the width' (the method used by the old analogue TV system to transmit wide-screen movies) or 'expand the height', which should result in better image quality since compression will always 'throw away' information.Further, when deciding what to output from PhotoStory 3 you should always try to minimise the number of 'down steam' interpolations needed to reach your 'target'.
Whilst PhotoStory 3 can output 'non-square' pixels, it is very poor at 'interpolating up' - so when 'optimising' the photos it is vital not to end up with 'too few' pixels for the output resolution you are going to use
The higher the pixel counts (within the 7200 pixel limit) the higher the (expected) quality, however it's also the case that the higher the pixel counts the more likely it is that output will fail with a 'insufficient memory' errorFinally, the higher the WVP2 resolution, the more 'jumps' and 'jitter' you will run into

To minimise jumps and jitter, use the 'slow down' scripts (below). It this fails, then you must use lower resolutions

Jumps and jitter is most often seen at HD resolutions.If 'HD direct' 1920x1080 results in unacceptable jumps and jitter, first try 'pre-HD' 1440x1080, then 'half HD' 960x540 and finally 'pre half HD' 720x540.

NB. All PhotoStory 3 profiles are 30 fps (not NTSC 29.97) for playback on a 60 Hertz monitor (to minimise flicker, i.e. make any jitter easier to see) - so when outputting HD from Media Encoder make sure to set 23.976 fps (Movie Maker PAL DV/AVI will always be 25fps)


DVD_16x9.BAS both distorts the photo height by 4/3rds (for 4:3 crop of 16:9 area) and adjusts the resolution so the minimum crop box area is twice 768x576 (= the 'square pixel' count needed for DVD output), so 1152 x 1536

To minimise the number of interpolation steps, my DVD Profile generates DVD distorted 720x576 'directly'
Note that the WVP2 playback fps is set to 30, so playback on a monitor set to 60 Hertz will be 'flicker free' and any 'jitter' seen must be due to WVP2 'morphing' problems = see SLOW_DWN.BAS below)


Optimises the photos for the 'highest possible quality' output by performing 4/3rds height distort and interpolating the photos up to the maximum allowed 7200 pixels

This has no effect on the size of the WVP2 output file - all it does is make more pixels available to PhotoStory so it can 'more accurately' generate (interpolate down to) the static sub-frames (each of the sub-frames is always equal in size to the output resolution)Of course the more pixels each photo contains, the more RAM PhotoStory will need to during output - so if all attempts to output after applying this script fails (with 'insufficient memory' error**), go back and choose one of the lower resolution scripts below** If you have a 64bit Windows 7 computer with at least 6Gb RAM, you can set the /LARGEADDRESSAWARE flag in pstory.exe header and run it on the Windows 7 computer. It will then have access to double the usual RAM during output (i.e. up to 4Gb instead of the usual 2Gb limit = see my Advanced PhotoStory use page)


Photos are optimised with 4/3rds height distort to double 'HD direct' (1920x1080) resolution i.e. 3840x2160

Aimed for use with my 'HD direct' profile (or lower)


Photos are optimised with 4/3rds height distort to double 'preHD' (1440z1080) resolution i.e. 2880x2160

Aimed for use with the 'preHD' Profile 1440x1080 (or lower)


Photos are optimised with 4/3rds height distort to the minimum sized crop area needed to support HD 1920x1080 without 'interpolation up'. Lowest HD optimise possible (when faced with 'insufficient memory' error), before you have to apply 'slow down' (see below), switch to a Windows 7 computer or give up on HD (and drop back to SD).

To avoid any 'interpolation up' when generating 1920x1080, the minimum 4:3 crop area is set to 1920x1440This can then be 'interpolated down' to 1920x1080 during direct HD 16:9 output by 'squeezing' the height from 1440 to 1080


Crops the used area to (twice) the DVD size. Should ONLY be used on a Story .wp3 that has already been optimised for HD but keeps failing during output with 'Insufficient Memory' errors. By reducing the photos to SD size, it's more likely to 'build'

If you can't output due to insufficient RAM, instead of using this script to reduce the photo sizes, I recommend you set the /LARGEADDRESSAWARE flag in pstory3.exe and run it on a Windows 7 64bit computer with at least 6 Gb RAM (see my Advanced PhotoStory use page)


'Transition freezer'. Each photo is checked to see if it's pan / zoom will be combined with a transition effect. If so, a 'static' copy of the photo is inserted for the 'transition time' only (and the original display time adjusted).

Whilst this avoids transitions overlapping into pan and zoom, the pan / zoom has to be sped up to maintain overall timing. This may not matter for photos with slow pan and zoom, however a speed up of a fast pan and zoom results in more 'jumps' during playback. One 'solution' to this would be to run the 'SLOW_DWN' (or SLOW_X25.BAS) script which doubles the length of the Story (but, because the pan and zooms are slower, it needs less RAM during output)

How the Transition Freezer works

Each photo can be involved in both a 'start transition' and an 'end transition'.This photos start Transition actually starts at half the Transition time into the previous photo - and finishes (at half the T time) into this. If both previous and this photos have pan / zoom running, then to 'freeze' the Transition between them it is necessary to insert 'half t-time' static copies of both photos (and adjust the display time of both)The start Transition is defined in 'this photo', the end transition is defined by the next photo - so each photos 'end' timing can't be set until the next photo's settings have been checked (the first photo is a 'special case'). We thus arrive at the following :-

(process the first VU, special case)
Get the first VU
If it has a transition (with black frame) and is non-static, create a 'start' static copy
Set the 'start' transition to the current transition type and (full) time,
set it's display time to half the transition time
Write out the 'start' copy
Set the current to no transition, reduce it's display time by half the transition time
(The current non-static VU can't be 'saved' until the next is checked)
Get the next VU and check for a transition
If the next has a transition, and the current is non-static, create an 'end' static copy of the current
Set the 'end' copy to 'no transition' and a display time equal to half the next transition time
Adjust the current VU's display time (by subtracting half the transition time)
Write out the current VU
If an 'end' copy was created, write that out(The 'next' now becomes the 'current')
If the current is non-static, create a 'start' static copy
Set the 'start' transition to the current transition type and (full) time,
set it's display time to half the transition time
Write out the 'start' copy
Set the current to no transition, reduce it's display time by half the transition time
Loop back to 'Next'

You may note the output project .wp3 is (almost) the same size as the input. This is correct - existing photos are 'referenced' in the 'start' and 'end' VU's in the project.xml but the actual image files are not duplicated

Due to the way in which PhotoStory 'references' photos, when you open the .wp3 in PhotoStory, it is quite happy to use the same photo 2 or 3 times. The same happens during Preview and output.It is only when you 'save' the story that the photo file will be saved multiple times (all the photos are renumbered during the 'Save' process)

Note that the transition timings in the 'start' static copies are 'double' the display times, which exceeds that permitted by the GUI. If you 'open' a start static copy with 'Customize Motion', the timings will be 'automatically reset'

QBasic scripts to reduce 'jitter'

Jitter is caused by errors in the WVP2 playback process. WVP2 playback is a 'morphing' process (similar to animated GIF) that generates video frames from one static sub-frame to the next. It appears that errors can accumulate during the morphing process, especially for fast pan and zoom sequences, which are 'corrected' with a sudden 'jump' when the next static sub-frame is reached.

The only way to reduce these jitters is to increase the number of sub-frames - however the fps setting has no effect on the number of sub-frames generated.The only way to increase the number of sub-frames is to reduce the speed of the pan and zooms i.e. increase all the photo display times (which includes the transition times)

The scripts below all process the project.xml to increase display times


Modifies project.xml by doubling all the photo display timings to reduce 'jitters' in the .wmv / DVD AVI output playback.

SLOW_DWN should be run 'last' i.e. just before using PhotoStory to generate the output .wmv.So, to optimise the photos for 16:9 output, you should run the one of the 16x9.BAS script FIRST (so you can check the crops are what you expected)

You only need to use SLOW_DWN if the WVP2 contains 'jitter'. This can be hard to detect, since a monitor set to 60 Hertz will display 25 fps (PAL) video with a noticeable 'flicker' which will 'mask' any 'real' jitter (errors) in the actual video data stream.

It is for this reason that my PhotoStory DVD output profiles are all set to 30fps (and not because I want NTSC - which would be 29.97 and not 30fps anyway)

Of course DV-AVI is 'defined' as PAL (25fps) or NTSC (29.970 fps) only - so WVP2 '30fps' input will be converted to 25fps avi output without any problem (if you are using Windows Media Encoder - eg to generate for VC-1 for HD - you will need to set the output fps accordingly (i.e. 25fps for PAL SD DVD or 23.976 fps for AVCHD)

So, after 'building' your story 'as normal' and outputting WVP2 you can check** if that plays back OK. If so, convert to DV/AVI using Movie Maker and check** playback again
Of course now you have avi at 25fps and a 60 Hertz monitor may well show flicker. Fortunately, AVI Frame Rate Changer (avifrate) can be used to 'set' any playback rate you like.
So use avifrate to (temporally) set the .avi to 30fps before playing** back on a 60Hertz monitor to check for jitter.If any jitter is found, you can go back to the Story and use SLOW_DWN to double all the photo display and transition timings in your Project. This will double the number of 'sub-frames' created in PhotoStory WPV2 .wmv output and (at least in theory) should halve the 'jitter'

After using SLOW_DWN, the 'half speed' .avi from Movie Maker can be re-checked** for jitter (on a 60Hz monitor by temporally setting the .avi to 60fps). If all is OK, it then has to be set to 50fps (to 'correct' the half speed setting) before being used in your DVD author application

To 'change the speed', what avifrate actually does is modify the 'duration' (MediaInfo will show that the fps always stays the same (i.e. 25fps) whilst the duration changes**), which is exactly what you are trying to achieve :-)** Needless to say, whist VLC (and most other Open Source software) correctly interprets the change, MS Windows Media Player 10 is too dumb to work it out (and thus continues to play the .avi at 25fps no matter what the duration is set to)NB WMP 10 also ignores the 16:9 flag (and always 'plays' .avi in 4:3 / square pixel mode) which can also be confusing

SLOW_DWN is not limited to DVD resolutions = all the photo display and transition times in project.xml are simply doubled (the photos themselves are not changed)

Note that all transitions etc. must be set to specific values in PhotoStory ('manual' setting in the project.xls) - any set to 'auto' might be 'changed back' by PhotoStory itself when you next 'open' the Story
Finally, there is nothing to stop you applying SLOW_DWN a second (or 3rd etc) time to get WVP2 with 4x, 8x (or even more) sub-frames

Of course changing your Story speed will 'trash' the audio track. So you will always need to replace the audio when you reach the DVD author step


"x 2" was chosen for SLOW_DWN to 'make it easy' for the DVD author application to process the 'double speed' .avi down to the correct speed.

However, if you are 'aiming' at anything else (such as HD) chances are you will be converting from WVP2 into 'real' movie format using Windows Media Encoder 9 - and WME supports a maximum speed up ('Time compression') of x2.5

Remember - the PhotoStory 'fps' setting is essentially irrelevant - the number of 'sub-frames' generated for the WVP2 'morphing' method (and thus the 'accuracy' of playback) is set by the story duration (and nothing else).Increasing the Story length by 2.5 times will mean 2.5 times as many sub-frames (and thus, at least in theory, 2.5 times less 'jitter')So, to maximise the quality of wmv generated by Media Encoder, slow down the Story by 2.5 times and set Media Encoder 'Time Compression' to the max.Of course you will still have to 'add back' the correct audio track later (WME is incapable of combining one Video 'source' with a different Audio 'source', although it will 'concatenate' (join) multiple 'sources' together)


Used to restore original project.xml display timings. Allows you to 'go back' to the previous (usually 16:9 modified) version and make pan/zoom timing changes and 'preview' the changes with the audio track 'in sync'

The 'narrationTips=""' field, at the end of the 'Image path="" XML entry for the FIRST VisualUnit is checked for a "SLOW_DWN" or "SLOW_X25" flag. If any are found, the timings will be adjusted accordingly (and that flag removed)If no 'flag(s)' are found, the timings will be halved.The photos etc. are not changed
No checks are made to ensure timings are set to 'manual'

In an ideal world you will never need to use this script - instead you would delete the SLOW modified .wp3 and go back to the original 4:3 'master' - however this script does save time when you want to make multiple 'tweaks' to find one that 'works' :-)

The pages in this topic are :-

  + QBasic command list - (reference) == Latest changes (modified 18th Jun 2020 18:18.)

Next page :- QBasic command list - (reference)