PC Plus HelpDesk - issue 262
This month, Paul Grosse gives you more insight into some of the topics dealt with in HelpDesk. From the pages of HelpDesk, we look at:
- End-Of-Line codes;
- Animated favicons;
- Never work with children and animals;
- Correcting photographs for density; and,
- Is my manager/partner a psychopath?
HelpDesk
End-Of-Line codes
If you are transferring flat text files between Windows and UNIX-based systems, you might well encounter a problem with files that are interpreted.
If you want to run a file in the current directory called, say, 'silk5.pl' and this has been written on Windows, say by Notepad, when you enter into the shell './silk5.pl' the shell might well say:
bash: ./silk5.pl: /usr/bin/perl^M: bad interpreter: No such file or directorySo, what is the problem?
All of the UNIX-like OSes use a single character for a new line (0x0a on UNIX and 0x0d on Mac OS X). However, Windows uses 0x0d0a so when Notepad saves a file, it uses two characters instead.
The first, 0x0d, is not looked upon as a new line (except in Mac OS X) but as a character - the following 0x0a being the new line. So, when Bash looks at the first line, it is looking for a program called '/usr/bin/perl^M' ('^M' or [Ctrl][M] being 0x0d) which, of course, doesn't (or, at least, shouldn't) exist.
There are two easy ways to get around this:
- One is to insist that your friend uses the '-w' warnings switch on the hash bang line - this will have the effect of placing the ^M after a switch so the program name will be correct; and,
- The other is that you open his file in a text editor such as KWrite and and under 'Tools', 'End of Line', select 'UNIX'.
It should all run nicely now.
Animated favicons
By now, most of us have come across the favicon.ico that appears in the address bar of the browser when we see a web page. However, these are not limited to static images or even .ICO files.
You can include an animated .GIF file by using the following line of HTML code in the <HEAD> section of your page - substituting 'animated_favicon1.gif' with the path and file name of your image...
<link rel="icon" href="animated_favicon1.gif" type="image/gif">So, that's how easy it is to include an animated gif but how do we go about getting one?
There are a number of different image processors that will produce animated .GIF images but out of Photoshop CS3 Extended, PaintShop Pro XI and The GIMP, only The GIMP (as far back as version 1.2.3 and probably before) will read them in - the others let you know that they will discard all but the first layer of the image.
So, in the interests of being able to read in and edit the file you have created (and also with the bonus of being cross-platform), we'll use The GIMP (The GIMP has been able to do this for years so we'll do this on version 1.2.3).
First of all, you need to create the text or other image(s) that you are going to use. Here, we'll display some text and have that scroll by us. This is an image that is 16 pixels high. At the end of it, we have the first part, up to and including the 15th pixel. If this was not included, the image would jump from some empty space at the end to the first frame - here, we feed into the first frame so that it looks nice and continuous.
Next, copy the image (usually by pressing [Ctrl][D]) and then use the crop tool to make it a 16x16 square at the far left (you'll find it useful to zoom in by a factor of 10 or so). This will now be the first frame of the animated .GIF file. Next, click on the long image again and then, in the Layers dialogue box, drag its image and drop that on the square image. This has now become the top layer.
Use the move tool to make it displaced one pixel to the left of the image underneath it. You can check that this is the case either by clicking on the Eye logo in the Layers dialogue or by changing its opacity (remembering to change them back afterwards, of course).
Once you have a full strip in your image, you can just drag that from the Layers dialogue and drop it in the image - each one adds a new top layer that you can then move.
Once you have got to the last frame (or even before, if you want to see how it is getting on), you can test out the layered image by right-clicking on the image and then selecting 'Filters', 'Animation', 'Animation Playback...' and pressing 'Play' in the dialogue.
If it all looks the way you want it, you can trim it down to size because at the moment, almost all of the layers are too long.
The last image in the sequence looks like this. You can see from the dotted line that the rest of the image goes off to the left. Ideally, you want to get rid of this. You can either: go through each image on the Layers dialogue box, clicking on 'Layer to imagesize'; or,
you can select the crop tool from the toolbox. Select the whole of the 16x16 image and click on 'Crop'.
This will cut every layer down to size, all in one go. Next, convert it to a palette-based image by right-clicking on the image and selecting 'Image', 'Mode', 'Indexed' and...
Next, we can produce an optimised animated gif by right-clicking on the image and selecting 'Filters', 'Animation', 'Animation Optimize' which produces a new image. You can see from the layers dialogue screenshot on the right that each layer only includes the changes that it needs to make from the previous layer - this keeping down the image size and processing that is needed in order for the image to work.
Finally, we have our image. Right-click on the image and select 'File', 'Save As...' then type in a name that ends with '.gif' such as 'anifavi.gif' and then click on 'OK'.
Now, you need to let the program know that you do want to save it as an animation so click on 'Save as Animation' and then on 'Export'.
The next dialogue box allows you to specify how you want any non-specified layers to be dealt with. If you have followed these instructions, you shouldn't have any of these so just click on 'OK'.
And this is how it should look. If your browser supports favicon.ico images then this should work. You should, of course, remember that you can specify a normal icon and an icon file for shortcuts as well so your head section should look like this...
<link rel="shortcut icon" href="favicon.ico" > <link rel="icon" href="animated_favicon1.gif" type="image/gif" >
Never work with children and animals
Photography using photographic film that was then developed required a certain amount of skill - especially when using medium format - because darkroom skill had to be earned. If you wanted to adjust the density of a certain part of the image, you would be better off changing the lighting when you took the original image.
On the whole, you would take care to make sure that you had the correct focussing, lighting and aperture before you took the shot. This is fine if you have a stationary subject - you are taking a picture of a USB drive or something - or a co-operative one - an adult or group - but if the subject matter is moving unpredictably, you might just have to take a shot and hope for the best.
This is where image processing software comes in.
Unfortunately, there is a tendency for people to take dozens of poor shots and then hope that they can use Photoshop, PaintShop Pro or The GIMP to get something reasonable out of it. If they can't, they then add one of the special effects (make it look as though it is printed on canvas or an old photograph) so that the effect messes it up more than the original photograph was messed up, thus disguising the fact that it was not a very good image to start with.
So, assuming that you had a small furry kitten that was not going to sit still and you had to take a photograph of them, what can you do?
...
Correcting photographs for density
We're going to have a look at two pictures of a kitten and make them look all right.
These are things that you can do in the darkroom if you want but as the images are already digital, we're going to do it with an image processor (or three).
They are quite simple things to do to images that haven't got a lot wrong with them in the first place - making the picture better to look at by correcting issues that are a result of lack of opportunity (rather than just adding meretricious effects to a picture that is not particularly good to start with, in the hope that the effects will distract the viewer from the poor photography).
Here is the first image. It is of the kitten lying down on a window ledge - she had just woken up and there wasn't a chance to get a light reflector on the left (you can't see one in the kittens right eye). If the opportunity presented itself a reflector would have been best - if handled with respect, these don't frighten kittens in the same way that a fill-in flash would.
This is what needs doing to it. We could just open up the curves dialogue and push the darker areas up a bit but that would reduce local contrast and produce an inferior image. We need to boost the luminosity of the darker area overall without losing that local contrast.
So, this is the first step. Take a copy of your image (as you should always do - never work on the original) and copy the layer.
- GIMP - drag the image from the Layers dialogue and drop it on the image itself - this duplicates it, making it a two layer image with the current layer as the top layer.
- PaintShop Pro - drag the image from the Layers dialogue and drop it on itself - this duplicates it and makes it a two layer image with the current layer as the top layer.
- Photoshop CS3 Extended - create a duplicate image by selecting 'Image', 'Duplicate'. Then, select the original image so that it becomes the current image and in the Layers dialogue, drag the original image and drop it into the new image - this becoming the top and current layer of the new image.
Next, we need to produce a mask from it that we can then blur - we need to keep local contrast whilst reducing the overall contrast between the shadow area and the rest of the image.
- GIMP - select the threshold tool and click on the image. Take the lower threshold down to zero and then adjust the upper threshold until the shadow area is highlighted - around 40.
- PaintShop Pro - Click on 'Adjust', 'Brightness and Contrast', 'Threshold'. Take the threshold down to around 40 (in this case, you can't do it the other way around. To get around this, we need to invert the densities on that layer. Select 'Image', 'Negative Image'.
- Photoshop CS3 Extended - Click on 'Image', 'Adjustments', 'Threshold...', move the cursor along until it says around 40 and click on 'OK'. This control has even less control over it than PaintShop Pro and again, we need to invert it. So, select 'Image', 'Adjustments', 'Invert'.
Next, we need to blur it so that we preserve the local contrast in the image.
- GIMP - select 'Filters', 'Blur', 'Gaussian Blur...' and then choose a blur radius of 40 (in this case - both for horizontal and vertical) and click 'OK'.
- PaintShop Pro - select 'Adjust', 'Blur', 'Gaussian Blur...' and choose a blur radius of 10 for the same effect then click on 'OK'.
- Photoshop CS3 Extended - select 'Filter', 'Blur', 'Gaussian Blur...' and choose a blur radius of around 10 for the same effect then click on 'OK'.
Now, we need to use this to process our image - the black and white image is too strong so we will use the 'Opacity'/'Transparency' control to reduce its effect. We could just take it away from our image but that would have the effect of reducing the saturation of the affected part of the image as well as reducing the overall tonal range of the image.
- GIMP - instead, we need to select 'Dodge'. Now, move the Opacity control until you have the correct effect. Remember that we don't want to see that it has been corrected so we only need a small amount - around 5 - 10%.
- PaintShop Pro - Change the blend mode to 'Dodge' and lower the percentage for that layer to around 20%.
- Photoshop CS3 Extended - Change the layer mode to 'Color [sic] Dodge' and the opacity to around 5%.
Next, we need to make it one layer.
- GIMP - flatten the image and that is all there is to it.
- PaintShop Pro - select 'Layers', 'Merge', 'Merge All (Flatten)'.
- Photoshop CS3 Extended - select 'Layers', 'Flatten Image'.
This is the image (left) compared to the original (right).
You can see that the detail in the shadow is a lot more visible and will print better.
Here's the second image. This was taken a few weeks before the one above and you can see that her eye's aren't as mature - they still have the wappy psycho-kitten look about them and they are pointing in slightly different directions.
The kitten eventually settled down between a bookshelf and a blue, plastic storage box.
This is the image after straightening and cropping.
The fur on the kitten's front is white so we would like to increase the luminosity of that. In addition, we want it to look like a picture of a kitten and not a kitten sandwich so, as the kitten is light and its immediate surroundings are dark, we'll tone down the fronts of the bookshelf and the storage box thus making the kitten the focal point of the photograph.
Also we need to remove the red-eye so, first of all, let's do just that...
We need to mask off the pupil.
- GIMP - One way of doing this is to click on the ruby mask button at the bottom-left of the image window, zoom in on the image and then use the paint brush with a fuzzy brush to paint white where the bits you want to edit are. When you click back from the ruby mask, you will see your area selected as in the image on the right.
- PaintShop Pro - Select 'Adjust', 'Red Eye Removal...'. Next, select the method 'Point-to-Point Outline' and then, click points on the image on the left, double-clicking when you have done.
- Photoshop CS3 Extended - find on the tool ribbon the healing brush tool (a plaster icon) and click on it but hold it down. A tools menu will open up and the 'Red Eye Tool' - select that and the icon will change.
Next, get rid of the red. We don't want any red but we do want the white highlight.
- GIMP - Right-click on the image and select 'Layer', 'Colours', 'Desaturate' and the selected area will become monochrome. The pupil now looks grey and white but we want it with almost black instead of grey. Click on the Curves tool (or right-click on the image, select 'Layer', 'Colour', 'Curves...') and change it so that the highlights have the same density but the lowlights are darkened.
- PaintShop Pro - Next, you can change the feather, glint size and so on. Note that PaintShop Pro produces a false glint. When you have finished, repeat the process for the other eye.
- Photoshop CS3 Extended - click on the red eye and it will darken, preserving the original highlight.
Now, we want to tone down the edge of the book case (left) and the blue plastic container (right) so that our kitten is what we focus on. The reflective surface of the floor is horizontal so we need to treat reflections in the same way as the objects themselves.
- GIMP - Select the rectangular selection tool, feather the edges to around 40 pixels and shrink down the image. Expand the window and then drag the cursor so that the top and bottom are well away from the image - this means that the feathering only affects the vertical lines. Invert the selection ('Select', 'Invert' or [Ctrl][I]) and then click on the Adjust Colour Curves tool. Drag the curve downwards to tone down the book case and the plastic container and click on 'OK'. Next, deselect the selection ('Select', 'None') and then use the Adjust Colour Curves tool to make the kitten's fur the right density.
- PaintShop Pro - Select the parts of the image with the rectangular tool in the same way as the GIMP above. Select 'Selections', '' to invert the selection of the image and then select 'Adjust', 'Brightness and Contrast', 'Curves...' and adjust the density of the bookcase and the plastic container by dragging the right hand marker down on the RGB display then clicking on 'OK'. Next, right-click on the image to remove the mask and repeat the curves tool, only adjusting a point in the middle this time to bring the fur out to its correct density
- Photoshop CS3 Extended - click on the 'Rectangular Marquee Tool', set the feather to 20px and then drag the cursor across the image following the same top-left to bottom-right path that you can see in the GIMP image on the right. This, unfortunately, feathers the top of the image whereas, in The GIMP and PaintShop Pro, they select properly. Next, invert the mask by clicking on 'Select', Inverse. Next, click on 'Image', 'Adjustments', 'Curves...' and pull the right hand half of the graph down to make the book case and the plastic container darker and click on 'OK'. Click on 'Select', 'Deselect' to remove the mask and then click on 'Image', 'Adjustments', 'Curves...' and pull the right half and the middle of the graph upwards to lighten the fur.
One alternative is that you can darken the book case and the plastic box and then, instead of deleting the selection, just invert it and make the fur lighter - the choice is yours.
And this is it (left) compared with the original (right).
Is my manager/partner a psychopath?
Note that this runs on Windows, UNIX, Linux, *BSDs, Mac OS X and so on.
There is a 20 point questionnaire called the Hare List that was developed over the years by a number of psychiatrists/psychologists so that there could be (along with a number of interviews carried out by a psychiatrist) a reasonably objective way of assessing people to see if they fell into a group of personality types that are known as psychopaths - there are other parts to this assessment that the trained professional would know about but here, we are, in the true tradition of those psychometric tests that you see in women's magazines at the doctor's/dentist's, we're going to throw to one side all attempts to be objective and instead, have a 'fun-to-do' test that will show off some of the aspects of the Perl Tk GUI. This is, of course, light-hearted and you shouldn't take the results seriously. And, just in case you were wondering if psychopaths had any positive contribution to make to society, they do make good managers (although, you might question if that is a positive contribution and also, you might ask why are psychopaths more suited to the requirements of modern management than others?).
So, where do we start and what do we need?
The Hare psychopathy check-list is freely available on the Internet (you can find it in the Wikipedia for instance) but we have a copy here.
The scoring on it for each check-list statement is:
- 0 for doesn't fit;
- 1 for fits a bit; and,
- 2 for fits completely.
There are four categories for the statements:
Interpersonal
- Glibness/superficial charm
- Egocentricity/Grandiose sense of self-worth
- Pathological lying
- Conning/Manipulative
Affective
- Lack of remorse or guilt
- Callous/Lack of empathy
- Shallow affect
- Failure to accept responsibility for own actions
Lifestyle
- Need for stimulation/Proneness to boredom
- Parasitic lifestyle
- Lack of realistic, long-term goals
- Impulsivity
- Irresponsibility
Antisocial
- Early behaviour problems
- Poor behavioural controls
- Juvenile delinquency
- Violation of conditional release
- Criminal versatility
Traits not associated
with any factor
- Promiscuous sexual behaviour
- Many short-term marital relationships
However, we will just look at the overall score. So, all we need now is a program. Perl is cross-platform and it has a GUI - unlike the GUIs on some operating systems, Perl's GUI is about getting the job done, not distracting the user with facile special effects.
We've all used Perl - it is the industry standard web server language - but whilst it runs on literally millions of servers every day, we can also use it for normal programming as well and, it is particularly easy to learn.
The GUI is called Perl Tk and it has the advantage that you can design it using UNIX or Windows and it will run on all of the others.
To use Perl Tk, you need to do a bit of object oriented programming but this is fairly easy.
You can find the program here and have a look at it. Below is a summary of how the program is written, right from the basics.
The following line tells the shell in UNIX where the program that needs to run this script actually exists. In this case it is in a directory called /usr/bin but can be in /usr/local/bin or somewhere else.
#!/usr/bin/perl -wOn a UNIX system, you need to get this correct (you can use the 'whereis' command to find out the answer).
On a Windows system. this doesn't matter because the file associations are system-wide through the file extension (normally .PL in the case of Perl programs).
The '-w' switch tells perl to use warnings - this is useful when you are developing programs as they give out useful information such as which line the interpreter thinks an error occurs on and so on.
To remark a line out (that is, to remove the functionality of a line of code without deleting that line) just start the line with a hash mark '#'. You can deactivate commands or write notes with these.
The next two lines tell perl to use the Tk module and the progress bar module
use Tk; use Tk::ProgressBar;Now, we will call the program as a whole. Subroutines that I have written start with an ampersand when they are called.
The first two lines set things up in terms of variables and the third generates the GUI. The fourth runs the GUI and at that point, the program becomes event driven.
&readfile; #input Definitions and explanations (1..20)... &initvars; #initialise the variables &creategui; #make the GUI MainLoop; #run it... exit (0);Here's the first subroutine. We start off by defining the block of program using 'sub name {}'. Anything within the braces is part of the subroutine.
sub initvars { $progress = 0; $qn = 1; $c = $d[$progress]; $b = $e[$progress] }'$progress' is a type of variable called a 'scalar'. It can have integers, floating points or strings in it. You can also have arrays (such as @myarray) but if you want to address a single scalar within that array, you use the $ sign in front (such as $myarray[17]). Array indices start at zero.
In 'readfile' we open the list of statements and descriptions. We give the file a handle (in this case called 'FH') and we can use that to refer to the file in future.
open (FH, "list");There are 20 but they will use the indices 0..19. To get a list of numbers (say 5 to 9), you do the following (5..9) which returns a list '5 6 7 8 9'. If we wanted to go through these in reverse, we would say 'reverse (5..9)' which would produce '9 8 7 6 5'. The foreach statements produces a list of values and stores them in $c
foreach $c (0..19) { $a[$c] = -1; # set element of array @a to -1 $d[$c] = <FH>; # read statement line from file chomp ($d[$c]); # take return off end of line $e[$c] = <FH>; # read description line from file chomp ($e[$c]); # take return off end of line #chop down the lengths of the string into more handleable portions my @f = split " ", $e[$c]; # split the description line up into words and # store them in an array called @f $e[$c] =""; # empty the description my ($g, $lg) = ("", 0); # set two local variables at the same time $w = 50; # set a global variable - the line length foreach $h (@f) { # create a loop using each word in the description $lh = length ($h); # find the word's length if (($lh + $lg) > $w) { # if that plus the length of the existing line # is greater than the width ($w) then: $e[$c] .= $g . "\n"; # add a new line character to the end and save it in # the description array; $g = $h . " "; # start a new line for the description $lg = length($g) # find its length } else { # alternatively: $g .= $h . " "; # add the word and a space to the end $lg = length($g) # and find its length } } # finish the loop if ($lg) { # if there is anything left over, chomp ($g); $e[$c] .= $g . "\n" # add that as well. } } close FH; # close the file. }Now for some OOP.
sub creategui { # create GUI $mw = MainWindow -> new(-title => "Hare Test...", -bd => 10); ^ ^ ^ ^ ^ ^ ^ Variable | | | | | Value Object type | | set value Variable | Method PointerHere, we are setting a new variable $mw to contain the pointer to an object (called 'MainWindow'). It doesn't exist until we execute this line so we have to use a method called 'new' which creates it. Optionally we set some of its attributes, in this case, we set the '-title' to have a value 'Hare Test...'. That is almost all there is to it.
$bf = $mw -> Frame () -> pack (-side => 'bottom', -fill => 'x');Now, we create a new variable - pointing to the pointer $mw - that has a frame in it. It needs packing into our main window so we call the pack method which has its own variables. The reason we give it a pointer is that we need to refer to it later so that we can put things in it or modify it in some way. Like this...
$bf -> Button (-text => 'Quit', -command => sub{exit(0)}) -> pack (-side => 'right');The above line doesn't generate a variable with a pointer in it because we don't need one. The button, though, does need to do something when it is clicked so we have something called a 'callback', the '-command' line. In this case, it is an anonymous procedure consisting of just the exit command.
$bf -> Button (-text => 'About', -command => sub{&about}) -> pack (-side => 'right');Here, it refers to an external command (so, if you have a complex subroutine that is called more than a couple of times from a number of different places, you can refer to that; or,
$sb -> Button (-text => 'Last', -command => sub{if ($progress >0) { $progress--; $qn = $progress +1; $c = $d[$progress]; $b = $e[$progress]; $n = $a[$progress]; }}) -> pack (-side => 'left');in the above example, it is a multi-line procedure which goes
if ($progress >0) { $progress--; $qn = $progress +1; $c = $d[$progress]; $b = $e[$progress]; $n = $a[$progress]; }and that is about it. Use a few different types of object and you can produce whatever you want.
There is plenty of more about this on the Internet and there are loads of books as well. Mastering Perl/Tk is a good start from O'Reilly (ISBN 1-56592-716-8).
So, how does it look on various platforms?
SuSE 8.2 professional SUSE 10.2 with Compiz OpenBSD 4.1 with KDE Windows Vista Ultimate. Note that with Windows, you need to install ActiveState Perl (free) in order to run it.