Посмотрите, как реализовано в
LiipImagineBundle для Symfony.
Оригинал хранится на сервере и есть настраиваемые в конфиге пресеты с заранее заданными размерами, качеством, вотермарками и т.д. На странице в шаблонизаторе указываете, какой пресет использовать. При первом вызове создается изображение под пресет, кэшируется и используется потом из кэша. Если в кэше нет — на лету генерится из оригинала.