And in response to several comments:
1) Sending cache headers will cause a pain in the ring if say for example he/she wants to change methods, i.e. not cache the images. And as an added note: I have had to deal with cache images recently and the majority of browsers ignore this and do what the hell they want.
2) Overlaying the image as noted will not retain the watermark and if a user saves the images they will only get the overlayed image.
3) Generating when required is the best solution.
if(file_exists("whatever.png")) {
// Use image
} else {
// Generate
}
If you need to regenerate the image for whatever reason, simply delete it and the script will regenerate.