How Do You Store Your Images And Thumbnails?

Hi,

This is not about storing images in a database, I store them in the file system. But to handle them, I store information about the image and thumbnails in the database. But right now I’m a little stuck in my approach. Because a lot of people are working with images, I thought why not ask others how they handle their images and thumbnails.

Right now I got an ContentImage CActiveRecord class. My image has a:

id

user_id (owner)

parent_id (only if it’s a thumbnail)

type (content, blog, article)

hash (md5 name of the image)

extension

height

width

But using it for my images and thumbnails did not work out and my class became a mess.

So, how do you store and keep track of your images and thumbnails in Yii? Should I separate the image and thumbnails in two classes and tables?

Since a thumbnails is a special version of the original image, if I have only one thumbnail format I just add ‘thumb_width’ and ‘thumb_height’ columns and add some prefix/postfix to the hash when storing them on disk.

Thanks, yes that’s how I like to use it before. This time I have different types of content. And each type of content has different thumbnail sizes. Some just 1 others about 10 different thumbnail sizes. And new sizes can be added in the future or deleted. So that’s why I though it would be good to also store the thumbnail info in the database table.

So you just need a second table with a relation to the main one.

I was hoping for something special how others do this, but maybe it’s just as simple as this. I’m doing it at the moment like this (simplefied):

table + model:

image

id

hash

blog_image

id

image_id

blog_category_id

user_id

article_image

id

image_id

article_category_id

user_id

product_image

id

image_id

product_id

user_id

image_thumbnails

id

image_id

height

width

But is it bad practice to make a method in Image that calls ImageThumbnail or should I only call ImageThumbnail inside the Controller?

When doing it from the controller, there is a lot of duplicate code because I use it in a lot of controllers. Just call $image->generateThumbnails() in the controller and let generateThumbnails() handle all the sizes and storage paths would be better I guess.

We use a unique id for all of our images. We started at 1000000000000001 (big int, unsigned). We also store our images in the files system. When doing so we part out the ID number (dividing by 1000 a few times) into directories, the complete path for 1000000000000001 would be /1/000/000/000/000/1000000000000001. This will create no more than 1000 files or directories in a given directory, which removes most filesystem limitations. The naming also allows us to link to an image without querying the database since we can determine the full path based on the image id.

We are storing 12 copies of each file. We basically copied the technique sites like Flickr and Smugmug use. (Original, 2048, 1600, 1024, 800, 500, 320, 150x150, 75x75, 240, 150, 100).

When images are being added to our database we use Imagemagick’s identify -verbose and store the output in the table. This is about 4k worth of data for each image, it includes the EXIF info, etc. If we ever need this data it will prevent us from having to open and read every image. That program also gives us a 512 bit signature for each image, which we store in a separate column. The signature makes it easy to track down duplicate images.

Our entire image database has dropped any concept of galleries, folders, etc. We only use tags. To speed up searches we use Redis. We store each tag as a key and the value of each key is a unordered set. Each photo with that tag becomes a member of the tag’s set. Redis has a very nice function called sInter that returns any members that intersect between a list of supplied sets. e.g. we can all sInter(‘skiing’,‘downhill’,‘italy’) and instantly get a list of all of the photo ids that contain the above tags.

I do it this way.

My db table for images has these fields:

id, name, description, file (or just file type - jpg, png etc), width, height, crop coordinates.

Image files are stored in some folder (/upload/images) inside extra set of subfolders.

For example:

Uploaded original image (in case I need to rebuild something): /upload/images/aa/bb/cc/123.jpg

Small size: /upload/images/aa/bb/cc/s_123.jpg

Thumbnail: /upload/images/aa/bb/cc/t_123.jpg

aa/bb/cc here is a set of subfolders based on result of some function of an image field, for example: md5(filename).

This is required for cases when total number of images is very large.

Next, in my model I have

public function getDir() - for getting image folder (including subfolders set)

public function getFullsize(), getPreview(), getThumbnail() - these return path to corresponding image.

And of course in afterDelete I do unlinking of image files.

Thanks Ryan and Orey for your information. I think I can things of that, thanks!

Very cleaver! B)

In my case, I use Rackspace’s Cloud File service. We don’t work with that many images. At the moment we do something simple. We make a folder for each letter, ex: users-a, users-b, users-c, etc. We upload images to each folder depending on the user that uploads the image. Since each folder shouldn’t go past 1,000,000 files according to Rackspace’s documentation, we are thinking of reading the folder’s metadata before an upload, and if it’s at some 100,000, create a new folder (ex: users-a2, users-a3) depending on our needs.

The file itself has its name hashed and saved into the folder. The name is then saved to the database with some other data depening on what it is used for.

It may not be the best approach since we are just starting out, but we also don’t have that many images.

Nowadays my approach is to have it done automatically:

  • Store images on the file system.
  • When image is being loaded, its validated. If valid, its saved, perhaps after resizing, and also its thumbnail is saved.
  • The filenames for the images are determined automatically from the class name and the pk. Perhaps for thumbnails add _thumb or the like. This assumes of course that the relevant models for which images can be uploaded have a nice PK, preferably auto-increment integer.
  • When you render the model, in whatever views, a model method for ‘fetching’ the image filename and the thumbnail filename are used to ‘get’ the needed source for the images.
  • If you’re following, then this can be generified for all AR models, so why not make some extension here, employed on all relevant models? In fact, maybe there is one like this already?.. . Indeed. Have a look on this extension. I have my own version of this extension, IIRC, its more simplified, but basically designed similarly.

Good luck!