Mikedowney.co.uk
What's New
Site Map

Diary
Astronomy
Bits N Bobs
Computing
Food And Drink
Links
Photography
Welcome


Recipe Collections
Recipe A Week 2013
Recipe A Week 2010
A-Z of Regional Cakes
Alphabet of Nations


Selected Entries
Pinhole Photography
Keeping Quail
Coventry
Recipes
A different recipe each week
Friends websites
Oven Temperatures and Measuring Cups


Most popular stories
A Hamster's Home is his C...
Hamster Peanuts
Simple HDR photography wi...
A Tangfastic Mess
Halloween Animal Beds
Decaffeinated Coffee
Garden Fountain
Pizza, Hamsters and Ballo...
Hamster Baby Update
More Squirrel Photos
Not Quite HDR photography


RSS Feeds:
RSS Feed Entire Site.
RSS Feed Diary only.



Powered by Blosxom


Pinhole Photography Ring
pinhole webring logo
powered by RingSurf
Next | Previous
Random Site | List Sites

Connecting an LCD screen to the NodeMCU

Story location: Home / computing / nodemcu /
14/Apr/2017

When I bought the electronics starter kit for the Raspberry Pi, it came with a small 16 character by 2 line LCD. I found instructions on the Adafruit website for wiring it up and controlling it. I thought it might also be a useful thing to use with the NodeMCU board so I had a look for any instructions for that.

Unfortunately everything I found was for the I2C version of the display and I've got the plain parallel bus version, so I decided to have a go at wiring it up and programming it myself.

The NodeMCU board with the LCD1602 display

See more ....

Wiring up the board

The wiring is quite straightforward, although a lot of wires are required. Six GPIO pins are needed at the NodeMCU end, along with power and ground.

Starting with the power pins, connect one of the ground pins from the NodeMCU to the ground rail of the breadboard. The 'Vin' pin supplies 5 volts (if used with a usb connection) so connect a wire from that to the '+' rail of the breadboard.

Four data lines are required: D4-D7 on the LCD. To make things easier I connected these to pins 4-7 on the NodeMCU board. The final two connections from the NodeMCU are 'Clock' (called 'E' on the display board) which went to pin 2, and 'RS' which went to pin 1. Data line D0-D3 from the display board are left unconnected.

The NodeMCU board with the LCD1602 display

The rest of the pins on the board go to either 0V, 5V or a potentiometer set as a voltage divider (ignore the 3 LEDs in the pictures, they aren't needed here).

Connect the following pins to ground (0V):

  • 'RW' (set permanently to Write mode since we aren't reading from the board)
  • 'VSS' (the board's ground connection)
  • 'K' (the ground connection for the backlight)
  • One side of the two potentiometers.

Wiring up the LCD1602 display

Connect the 'VDD' pin to 5V and also the other side of the two 10K potentiometers. Finally, the 'V0' and 'A' pins can be connected to the centre of the two potentiometers to provied adjustable contrast and backlight.

Wiring up the LCD1602 display

Programming the board

I based my Lua code on the Python code downloaded from the Adafruit website. Since I was converting the code from one language to another, I read through it carefully to make sure I only converted the bare minimum to get it working.

My first version of the code was little more than a few subroutines to send bytes to the board. While I was reading the NodeMCU Lua FAQ, I noticed that they recommend that code is written to be event driven instead of the more traditional program flow used in scripting. They also state that routines called from an event can only take a maximum of 10 milliseconds to run before they affect background services. After reading that I changed my code to buffer the text and use a timer to check the buffer and send the bytes to the display.

The current version is probably too cautious and sends a byte at a time. It might be more efficient to send a line at a time but that should be easy to change.

The code can be found over on Github. I have decided to put it there since it is easier for me to keep it up to date and easier for anyone else to download.



Using the Raspberry Pi serial port from Java

Story location: Home / computing / raspberry_pi /
25/Feb/2017

A couple of days ago I wrote about connecting the Raspberry Pi to the NodeMCU microprocessor board. I originally used Python since I find that the easiest for testing ideas or simple prototyping. Since I use Java for most of my application programming, I thought I should work out how to do the same thing in Java too.

Luckily there is a Java serial comms library called RxTx which is available precompiled for Debian Linux and can be installed on the Raspberry Pi simply by typing

sudo apt-get install librxtx-java

The jar file is placed in /usr/share/java/RXTXcomm.jar (and doesn't seem to be added automatically to the classpath) so to compile any code, you'll need to use something like

javac -cp /usr/share/java/RXTXcomm.jar:. SerialTest.java

and to run the code you need to reference both the jar and the JNI library, using

java -cp /usr/share/java/RXTXcomm.jar:. -Djava.library.path=/usr/lib/jni SerialTest

The Code

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.*
import java.util.Scanner;

public class SerialTest{

    public static void main(String[] args) throws Exception{
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier("/dev/ttyS0");
        CommPort commPort = portIdentifier.open("Java Serial Test",1000);
        System.out.println("Opened Port");

        SerialPort serialPort = (SerialPort) commPort;
                serialPort.setSerialPortParams(115200,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);

        String[] leds = new String[]{"r","g","b","off"};

                try(BufferedInputStream in = new BufferedInputStream(serialPort.getInputStream());
                BufferedOutputStream out = new BufferedOutputStream(serialPort.getOutputStream());
        Scanner s = new Scanner(in)){

            for(String c : leds){
                out.write(c.getBytes());
                out.flush();
                System.out.println(s.next());
                Thread.sleep(1000);
            }
        }
    }
}

I saved the code as SerialTest.java and compiled it and ran it using the commands above. It expects the serial.lua file to already be running on the NodeMCU board, either by running the python script from last time or by executing

python nodemcu-uploader.py --port /dev/serial0 file do serial.lua

As you can see, the code is much more verbose than the Python version but it gets the job done.



The long awaited Raspberry Pi post: Interfacing with a NodeMCU

Story location: Home / computing / raspberry_pi /
22/Feb/2017

I first used a Raspberry Pi when I was working in Leicester and I bought one for home not long after that. I set it up as a file/media server and it has been sitting in the front room quietly doing its job since then.

Last year I bought a Pi 3 and an electronics starter kit (which consisted of a breadboard, LEDs, switches and various other components) so I could learn how to connect things to the Pi.

A few weeks ago I was given a NodeMCU development board (my friend Tim has already written about some of his experiments with his).

I followed the instructions on flashing the firmware and getting a script running. For some reason the ESPlorer software doesn't seem to behave well on my computer. It usually takes several rounds of restarting/resetting/reconnecting before it will agree to communicate with it. The command line tools have no problems, neither does CoolTerm. After a day when it felt like I was spending half of my time struggling to get ESPlorer to connect properly, I decided to ditch it and use the nodemcu-uploader command line instead.

The first thing I wrote was the Hello World of the microcontroller world: the flashing LEDs. The next stage was to use the serial ports to connect the Raspberry Pi and the NodeMCU together.

See more ....

Setting up the Raspberry Pi Serial Port

By default, the serial port on the Pi is configured to be used for a serial console , mainly for diagnostics. To use it for other things, you need to disable the console. There are lots of different instructions to do this but for the Pi 3 it boils down to editing the /boot/config.txt file and adding the line

enable_uart=1

followed by editing /boot/cmdline.txt and removing the

console=serial0,115200

entry. After rebooting the Pi, the GPIO pins 14 & 15 should be available for the serial port.

Writing the script for the NodeMCU

I took my flashing LED script and modified it to listen to the serial port. Sending 'r','g' or 'b' will light up the respective LEDs, any other character will turn them off. If the following script is saved as serial.lua, it can be uploaded to the NodeMCU using

python nodemcu-uploader.py -port /dev/serial0 upload serial.lua

as long as the NodeMCU Uploader has been installed first.

-- Listen on the serial port for a colour.
-- Toggle the colour of the LED.

green=2
blue=1
red=3
gpio.mode(red,gpio.OUTPUT)
gpio.mode(green,gpio.OUTPUT)
gpio.mode(blue,gpio.OUTPUT)

-- Start with the LEDs off
gpio.write(red,gpio.LOW)
gpio.write(green,gpio.LOW)
gpio.write(blue,gpio.LOW)

uart.setup(0,115200,8, uart.PARITY_NONE, uart.STOPBITS_1, 1)

uart.on("data",1,
    function(char)
        if char=="r" then
            print("red")
            gpio.write(red,gpio.HIGH)
            gpio.write(green,gpio.LOW)
            gpio.write(blue,gpio.LOW)
        elseif char=="g" then 
            print("green")
            gpio.write(red,gpio.LOW)
            gpio.write(green,gpio.HIGH)
            gpio.write(blue,gpio.LOW)
            lighton=2
        elseif char=="b" then
            print("blue")
            gpio.write(red,gpio.LOW)
            gpio.write(green,gpio.LOW)
            gpio.write(blue,gpio.HIGH)
        else
            print("Off")
            gpio.write(red,gpio.LOW)
            gpio.write(green,gpio.LOW)
            gpio.write(blue,gpio.LOW)
        end
    end,0)

The script can be run using

python nodemcu-uploader.py -port /dev/serial0 file do serial.lua

Getting the Pi to talk to the NodeMCU

I connected the RX GPIO pin on the Pi to the TX pin on the NodeMCU, and vice versa. The easiest way of powering the NodeMCU was to use the power out pins from the Pi. I found that connecting the 5V out to Vin on the NodeMCU worked reliably. If I had the Pi plugged into a good quality USB power adaptor then I could sometimes get it to work by connecting one of the 3.3V pins of the Pi to one of the 3.3V pins of the NodeMCU board, but this isn't guaranteed to work.

The script uses the serial port library, which can be installed using

sudo apt-get install python-serial

The Python script is fairly simple and just cycles through the LEDs a few times. The third line runs the lua script, in case it wasn't already running. There isn't a pause between cycling between the LEDs but the serial timeout is set to 1 second and the port.read(100) command attempts to read 100 bytes. Since there should only be the colour names being returned, this automatically adds a 1 second delay. This might not be very good programming practice but it was the easiest way of incorporating reading a variable length response and adding a pause all at once.

import serial

port = serial.Serial("/dev/serial0", baudrate=115200, parity=serial.PARITY_NONE, timeout=1.0)

port.write("dofile('serial.lua')\r\n")

for i in range(1,10):
    for c in ['r','g','b']:
    port.write(c)
        r = port.read(100)
        print(r)

Flashing LEDs

This first demonstration is pretty trivial, although it took a few days of trial and error to get everything working. In due course I'll experiment with connecting different sensors to the Pi and NodeMCU.

Flashing LEDs on the NodeMCU, controlled by the Raspberry Pi

I think my next step is to use Java on the Pi to do the same thing. I have had a quick look at Java serial port stuff and it isn't as straightforward as Python but since I do most of my programming in Java these days, it will be useful to know how to do that.



Mandelbrot Set on the Atari ST

Story location: Home / computing /
29/Nov/2015

In the early 90s I wrote a Mandelbrot Set generator in 68000 assembly language on the Atari ST. The 68000 processor didn't have any floating point arithmetic so I wrote a set of fixed point arithmetic routines with precision ranging from 16bit, 24bit and 32bit. These all had 8 bits for the integer with the remaining holding the fraction part.

I managed to find a copy of the program and got it to load in an emulator. The Atari takes around 10 seconds to draw, and only uses a 200x200 window. A couple of years ago, I wrote a Java version which works as an ImageJ plugin. This version is much faster (0.07s for a 800x600 image), which works out as 1700x faster than the Atari, despite only being clocked 300x faster. Processor design improvements and hardware floating point probably account for much of this increase.

The atari version can be downloaded here. The ImageJ version is available here (ImageJ and Java8 required - an older version which works with Java6 is also available)



Mandelbrot Set animation

Story location: Home / computing /
27/Nov/2015

A couple of years ago I wrote an ImageJ plugin to draw the Mandelbrot Set. I recently updated it to make animations (download available here).

See more ....

To make an animation like the video, use the ImageJ 'polyline' tool to draw a line, with the spline option to smooth the line. Clicking on the Julia Set button will create a set of images which can be aligned using the following script:

var out = "zigzag1/";

run("TIFF Virtual Stack...", "open=[JuliaSet.tif]");
rename("julia");

var frames = nSlices;
var w = getWidth();
var h = getHeight();

run("TIFF Virtual Stack...", "open=[mandelbrot.tif]");
rename("brot");

setBatchMode(true);

for(i=1; i<=frames; i++){
    merge(i);
}

run("Close All");
setBatchMode(true);
print("Finished");
exit;

function merge(i){
imgname = "frame"+i;
newImage(imgname, "RGB black", w*2, h, 1);

selectWindow("julia");
setSlice(i);
run("Select All");
run("Copy");

selectWindow(imgname);
makeRectangle(w, 0, w, h);
run("Paste");

selectWindow("brot");
setSlice(i);
run("Select All");
run("Copy");

selectWindow(imgname);
makeRectangle(0, 0, w, h);
run("Paste");

fn =  out + imgname+".zip";
print(fn);
saveAs("ZIP", fn);
close();
}

The images will be saved in the folder given in the 'out' variable. Although this can be accomplished using the 'Combine' option in the ImageJ stack menu, the script works with virtual stacks so can handle much longer animations.



Plugin for a 'Like' button

Story location: Home / computing / blosxom /
08/Oct/2014

I wrote this plugin over 4 years ago, to add a 'Like' button similar to Facebook. It is a standard Blosxom plugin which uses a bit of JavaScript to modify the page when the button is clicked.

I hadn't realised that I never uploaded it here. I have updated it to use JQuery, which replaces some if statements and browser specific code with a single line (JQuery takes care of all the browser specific stuff).

To use the plugin, copy it into the plugins folder as usual. It needs

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

adding to the head section of the webpage, like all the other JQuery based plugins here. Add the line:

$like::likeform

where you want the button to appear.

A list of most-liked stories can be generated and is available in

$like::mostliked

The plugin is available to download here.



Updated Seemore Plugin

Story location: Home / computing / blosxom /
13/Sep/2014

This website uses the seemore plugin which makes it possible to only show the start of an entry, and expand to show the full item when a link is clicked. The original version reloaded the entire page but I have modified the plugin to use JQuery so it now expands the item in-situ without having to reload.

It works in a similar fashion to the updated gallery plugin and also needs

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

to be added to the head section of the webpage.

The updated plugin can be downloaded here.



Updated Gallery Software

Story location: Home / computing / blosxom /
10/Sep/2014

One problem with still using the fairly ancient Blosxom blogging software for my website is that it receives practically no updates any more and most of the plugins aren't being updated either.

Although everything still works, it would sometimes be good to have a more modern, better supported system, I have been staying with Blosxom because it would be a pain to transfer everything to a new format. One of the main problems would be the photo galleries which use ImageGallery, where the images and captions are all stored in different files, in different folders. I would need to find a way of converting the data to a new format. If I stick with Blosxom (and ImageGallery) then I would have to put up with the whole page being reloaded when a new image is selected.

Since there doesn't seem to be anything better at the moment I decided to update the plugin to use JQuery which lets you easily change document elements and load files from the server.

My new version, ImageGalleryJQ is a drop in replacement for ImageGallery but loads the images and descriptions without reloading the entire page. To use, simply rename the file to imagegallery and copy to the plugins folder. The JQuery library needs to be loaded by including something like

Add

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

to the head section of the webpage.

All of the gallery pages in a website will automatically use the new plugin.



Game of Life

Story location: Home / computing /
15/Jun/2013

Here is the ImageJ version of the classic Game of Life which I wrote in an evening, several years ago. I have made a small change since then so the 'Reset' button clears the window and the 'Random' button fills the window with random dots.

See more ....
Game of Life running in ImageJ

The ImageJ drawing tools can be used to fill in pixels. Clicking on 'Start' will begin the animation. Pixels which have remained unchanged slowly fade to grey while pixels which 'came alive' are in white.

To Install

Download the source code and load into ImageJ or Fiji. Select 'Compile and Run' to start.

The program was cobbled together fairly quickly and ideally would need a bit more work to make it more user-friendly. Any configuration is done by editing the source code and recompiling. The speed of the animation can be changed by altering the value of 'pause' (value in milliseconds). The size of the world is given by the 'width' and 'height' variables. If these are changed then the image window may need to be resized by changing the default magnification in the setMagnification() command.



Mandelbrot Set

Story location: Home / computing /
13/Jun/2013

A few weeks ago I was reading the book The Emperors New Mind by Rodger Penrose and I reached the part where he discusses the Mandelbrot Set. Years ago I used to enjoy exploring this on my computer. I decided to download a mandelbrot program for my mac but couldn't really find one which I liked. This prompted me to have a go at writing one myself. I decided to cheat a little and write it as an ImageJ plugin so I didn't have to handle the display and mouse myself.

See more ....

I reused some bits of code from a version of Life which I wrote a few years ago and also some code which I developed during my PhD and managed to get a useable plugin up and running that evening. Over the next few days I added a few extra features and made it a bit more useable.

To Install

Click on the download link and save the 'jar' file into the ImageJ or Fiji plugins directory.

Download

To Run

Select 'Mandelbrot' from the 'Plugins' menu. Configuration options are in the 'About Plugins' submenu of the 'Help' menu. After changing any options, the mandelbrot set window will need to be closed and the plugin re-run before any changes will come into effect.

How to Use

Mandelbrot Set in ImageJ

To zoom in or out, use the 'Point' tool of ImageJ to select the new centre and click on either the 'Zoom To' or 'Zoom Out' buttons at the bottom of the window. To pan the view without changing the zoom, select the new centre then click on the 'Re-Centre' button. The 'Reset' button returns the view back to the original zoom.

The number selection box to the right of 'Reset' controls how many calculations are performed before the algorithm decides whether a point belongs to the set or not. Increasing this number will show more detail at the fringes of the set at higher zoom levels.

The Normal/Sqrt/Log selection controls how the colour values are calculated. Initially all values are displayed in greyscale. To display in colour, select one of the ImageJ lookup tables for the required colour scheme.

Julia Set in ImageJ

Finally the Julia Set for a particular point can be displayed by selecting a point then clicking on the 'Julia Set' button.

More Details

Further details on the Mandelbrot Set and Julia set can be found in Wikipedia.



Simple HDR photography with ImageJ

Story location: Home / photography /
02/Jan/2010

This follows from my first attempt at 'HDR-style' photography with ImageJ. I have abandoned my old approach, which used ImageJ macros, and have developed a couple of plugins which are easier to use.

See more ....

Description of Plugins

The first plugin is a version of Unsharp Masking, which subtracts a blurred version of an image from the original. This can improve local contrast and bring out detail in flat areas.

The second plugin is a modification of the CLAHE (Contrast Limited Adaptive Histogram Equalization) plugin. This performs local histogram equalization on sections of the image. This usually gives better results than the simple Unsharp Mask, but is a lot slower.

Installation

  1. Download and install ImageJ following the instructions at http://rsbweb.nih.gov/ij/download.html.
  2. Download the file hdr_.jar. Copy this file into the ImageJ/plugins/ directory.
  3. Start ImageJ, or select 'Help->Update Menus' if ImageJ is already running.

Usage

The plugins can be found in the 'Plugins' menu, in a 'HDR' submenu.

Both plugins expect a 3-channel TIFF file and can accept 16bit or floating point files. If your camera can save 16 bit RAW files then it may be possible to convert these into TIFF files - check the camera's documentation or any software supplied with it.

After loading the image, select the appropriate plugin from the menu. If 'preview' is selected, a small preview window opens which gives a approximate version of the result. At the moment, this window cannot be moved, so if it appears under the dialogue box, that window will need moving out of the way.

After clicking on 'OK', the plugins process the image and return a processed colour image, and a 3-channel floating point image which holds the full dynamic range and could be used for any additional processing steps.

Unsharp Mask

This plugin has the following options:

  1. Strength (1-100). Higher values give a stronger effect.
  2. Blur Radius (1-100). This is the amount of blurring applied to the image which is subtracted from the original.
  3. Saturated (1-100). After applying the Unsharp Mask, the contrast is adjusted so that a small number of pixels are saturated (set to either 0 or 255). The percentage of pixels is the selected value/10.

Local Contrast

Two options are available:

  1. Block Size (in pixels). This is the size of the area used to calculate the histogram. The best value depends on the properties of the image.
  2. Maximum Slope. The CLAHE method increases contrast but will use this parameter to set a maximum contrast. The actual slope is value/10. Higher values give a stronger effect but can also increase noise in areas of flat colour.

Examples of Use

original
Original image - photograph of Ironbridge in Shropshire, taken on a overcast day with very poor light. The camera was set to its lowest contrast setting to capture the full dynamic range, otherwise the sky would have been burnt out.

Unsharp Mask
After applying an Unsharp Mask. The whole image has been lightened, with the darker areas being lightened more.

CLAHE
After applying the CLAHE method. The effect is much stronger than the Unsharp Mask, with more detail visible in the sky and better colour in the ground.



Not Quite HDR photography

Story location: Home / photography /
23/Nov/2008

I've been intending to experiment with HDR (High Dynamic Range) photography, where images maintain details in both the shadows and highlights. Normal photography has a fairly low dynamic range, so if you want to have good shadow detail, highlights are usually over-exposed.

Normally, HDR software requires 3 bracketed exposures but this usually requires a tripod to ensure all 3 photos can be easily aligned and merged to give the HDR image. I thought I would try to come up with a shortcut to allow me to get results close to HDR but without the need to take multiple images or carry a tripod.

My method requires a digital camera which can produce a 16 bit colour file. I use the 'RAW' image format on my Nikon D40, and then convert it to a 16 bit uncompressed TIF using the ViewNX software which came with the camera. Other cameras should be suitable as long as a 16 bit image format is available.

Required Software

  • Download and install Imagej and the Calculator Plus plug-in.

  • Download the HDR Maker macro and copy it into the ImageJ plugins directory.

  • Install any software necessary to load or convert RAW images from the camera. ImageJ has plugins to handle a lot of different image formats.

Procedure

This is obviously biased towards Nikon cameras, the D40 in particular. Instructions for other cameras will vary.

  • Set the camera to take RAW images. One way of doing this on the D40 is to go into the Shooting Menu and select Image Quality and choose NEF (RAW) or NEF(RAW) + Jpeg.

  • We will need to get a wide range of intensities recorded, so we'll use low contrast to reduce the amount of detail lost in shadows and highlights. On the D40, there are two main ways of doing this. In the Shooting Menu, choose Optimise Image. From there you can either select Softer or go to Custom and set Tone Compression to one of the low contrast options.

  • After transferring the images to the computer, use the ViewNX software (which comes with the camera) to convert the raw NEF file to a 16 bit uncompressed TIFF file.

  • Load ImageJ and open the 16 bit TIFF.

  • Go to the Plugins menu and select 'HDR Maker'.

  • The dialogue box gives options for shadow/highlight values. The defaults are 25% and 75% which means the darkest 25% of pixels will be lightened slightly and the lightest 25% (100-75) will be darkened.

  • The next options are dodging (lightening shadow areas) and burning (darkening highlights). Higher values have a greater effect.

  • The blur value is related to the sharpness of the area where the lightness adjustment takes place. Good values range from 0.9 to 50, and vary depending on the image.

  • The saturation value refers to the percentage of pixels which will be set to the extreme light and dark settings after processing.

  • The default values are only suggestions and will not work for all images. Feel free to experiment and try different values to obtain a good effect.

HDR test image

The image above shows the output of the macro. The original photo is on the left, and has detail in the sky but the shadows are very dark. The middle image is the output from the HDR Maker macro. The image on the right is the original photo with the brightness and contrast increased to show detail in the shadows. This has resulted in losing all detail in the sky. Click on the image for a full size version.

The images used above are only to illustrate the procedure, rather than examples of good photography. The HDR macro is an early version and needs more development. The main problem is the lack of contrast in the shadow areas. I tried different values for shadow/highlight/dodge/burn but couldn't get an image which gave 'punchy' detail such as in the right hand image. With any luck I'll be able to sort this out in a future version.



Trying to prevent image theft 2: Watermarking images

Story location: Home / computing /
14/Apr/2008

Yesterday I mentioned using the .htaccess file with Apache to prevent people hot-linking images. That would only be a temporary solution, which would stop current hot-links from working. Any future image theft would involve people downloading images and re-uploading them somewhere else.

See more ....
One way of stopping that is to add a watermark to each image. There are a lot of websites explaining how to do that manually in Photoshop or Gimp, but I needed a simple way of adding a watermark to several hundred images.

I had heard about Image Magick and thought it might have a way of doing it. There are instructions here explaining how to do it.

The images on my website are spread across a lot of directories, so I wrote a small perl script to watermark all the images in a directory (including subdirectories):

#!/usr/bin/perl
# use ImageMagick to add copyright watermark to images

use File::Find;
use strict;

my  = "jpg|png";    # file extensions to apply watermarks to
my /computing = "/images";      # directory holding the images
my  = "/copyright3.png";    # full path to watermark image

sub processFile{
    return if ($_ !~ /.*\.[]/);
    my  = ::name;

    `composite -dissolve 10% -tile  "" ""`;
}

find(\&processFile,/computing);

The /computing and `` variables should hold the full path for the directory and watermark file. You'll need to produce an image with a transparent background for the watermark.

Changing the 10% value gives a ligher or darker watermark, depending on how obvious you want it to be.



Storylog and Storyfilter plugins updated

Story location: Home / computing / blosxom /
17/Sep/2006

I have updated the Storylog (v0.29) and Storyfilter (v0.39) plugins for Blosxom. Both now include file locking so there should be no problems with simultaneous access to a site causing file corruption any more.

Storylog now includes an ignore list for URLs and user agents so search engine hits can be ignored so they won't affect the 'most popular clicks' list.

Storyfilter now has the option to generate a list of all keywords, which is useful for site maps. This requires the line
meta-showkeywords: yes
to be included at the start of the story and fills the $storyfilter::allkeywords variable with the list.

Both plugins can be downloaded here.



Storylog v0.20

Story location: Home / computing / blosxom /
24/Oct/2005

Storylog is another Blosxom plugin. It logs the category views (and if storyfilter is installed, optionally logs keyword links).
Download the current version (version 0.20).
Instructions are in the zip file (no perldoc yet). For a demonstration of storylog in action, see the 'Most popular clicks' in the menu bar on the left. This uses the 'combined' log of both categories and keywords.