September 2005
The Enlightenment project has created a great deal of incredibly useful software as a result of working on a window manager. One piece of that software is the Epeg API. The Epeg software is designed solely to thumbnail - fast. In two other articles , single file thumbnailing and using a hardcoded source to destination directory method was used. In this text, the two are combined and some errors in the previous implementations fixed.
Note: For those who want to skip the diatribe, you can download the software.
There is a lot that goes on in etu, ironically it
is mostly input parsing and directory/file operations. The
beginning of the program has the includes and prototypes.
/* * etu.c - Epeg Thumbnailing Utility. Thx to raster, devilhorns and icarus. */ #include <getopt.h> #include <unistd.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <Epeg.h> void update_thumb (char *, char *, int, int, int); void create_thumb (char *, char *, int, int, int); void usage (void); int check_handle (char *); char *fullpath (char *, char *); ...
main()Nothing fancy yet, now the main function along with the initialized variables.
...
int main (int argc, char **argv)
{
int c;
int thumb_height;
int thumb_quality;
int thumb_width;
char *thumb_dir; /* output dir to be processed */
char *jpegs_dir; /* input dir to be processed */
char *jpeg_file; /* input file to be processed */
char *thumb_file; /* output file to be processed */
jpeg_file = NULL;
thumb_file = NULL;
jpegs_dir = NULL;
thumb_dir = NULL;
thumb_height = 96;
thumb_quality = 75;
thumb_width = 128;
...
The c variable is just a counter. The rest is
pretty obviously named. Note that the single file and directory
names are not preset to anything like some of the earlier versions.
It should be noted that the program only works in one of two modes,
a single input regular image and output thumbnail or a single input
directory full of images and an output directory of corresponding
thumbnails.
Next, of course, is the parsing loop. The GNU
getopt() bits are used for parsing input. The options fill
in the NULL values which are either directory handles
or filenames and/or overrides the dimensions variables.
while ((c = getopt(argc, argv, "d:h:i:o:q:s:w:")) != -1) {
switch (c) {
case 'd':
thumb_dir = optarg;
break;
case 'h':
thumb_height = atoi(optarg);
break;
case 'i':
jpeg_file = optarg;
break;
case 'o':
thumb_file = optarg;
break;
case 'q':
thumb_quality = atoi(optarg);
break;
case 's':
jpegs_dir = optarg;
break;
case 'w':
thumb_width = atoi(optarg);
break;
default:
usage();
return 1;
break;
}
}
main()The rest of the main function checks to see if there is an input
file, if there is - just process it by calling
create_thumb() and assume there is an output file, if
there isn't nothing will happen. If there is not an input file it
assumes that a check for a source directory of images is needed,
provided that passes it checks to see if the destination directory
exists - if it doesn't it creates the destination. If the
destination does exist - the program simply updates it.
etu could be used to continually refresh a given
thumbnail directory. Once the directories are taken care of, the
update_thumb() function is called.
if (jpeg_file != NULL) {
create_thumb(jpeg_file, thumb_file,
thumb_height, thumb_quality, thumb_width);
return 0;
}
if (check_handle(jpegs_dir) != 0) {
fprintf(stderr, "%s directory not found\n", jpegs_dir);
return 1;
}
if (check_handle(thumb_dir) != 0)
if (mkdir(thumb_dir, 0755)) {
fprintf(stderr,
"Could not create directory %s\n", thumb_dir);
return 1;
}
update_thumb(jpegs_dir, thumb_dir,
thumb_height, thumb_quality, thumb_width);
return 0;
}
Next there are two etu specific functions that are
used to handle directory operations and thumbnail creation.
update_thumb()Update is somewhat of a misnomer, basically a trick is used in
etu, even if the thumbnail directory is not there
already it checks
and if there is not a corresponding
thumbnail, it creates one. Of course, if there is one, it keeps
going. Basically all that happens is the source jpegs directory is
opened on a handle and the thumbnail (of the same name) is created
in the thumbnail directory. Note that in earlier versions, the
DIR * handle was passed around.
void update_thumb(char *jpegs, char *thumbs,
int height, int quality, int width)
{
int i;
char thumb_path[PATH_MAX];
char jpeg_path[PATH_MAX];
struct dirent *jpegs_dp;
DIR * jpegs_dir_handle;
jpegs_dir_handle = opendir(jpegs);
i = 0;
while (jpegs_dp = (readdir(jpegs_dir_handle))) {
if (i > 1) {
strncpy(thumb_path, fullpath(jpegs_dp->d_name, thumbs),
sizeof(jpegs_dp->d_name) + 1);
if (check_handle(thumb_path) != 0) {
strncpy(jpeg_path,
fullpath(jpegs_dp->d_name, jpegs),
sizeof(jpegs_dp->d_name) + 1);
create_thumb(jpeg_path, thumb_path,
height, quality, width);
}
}
i++;
}
closedir(jpegs_dir_handle);
}
create_thumb()In the thumb creation code, the actual Epeg calls are made using
the full paths and dimension values from
update_thumb().
void create_thumb(char *jpeg, char *thumb,
int height, int quality, int width)
{
Epeg_Image * jpeg_image;
jpeg_image = epeg_file_open(jpeg);
if (!jpeg_image) {
fprintf(stderr, "Cannot open %s\n", jpeg);
exit (1);
}
epeg_decode_size_set(jpeg_image, width, height);
epeg_quality_set(jpeg_image, quality);
epeg_file_output_set(jpeg_image, thumb);
epeg_encode(jpeg_image);
epeg_close(jpeg_image);
}
The Epeg calls do as follows in order:
The program has two helpers, one that checks to see if a directory exists (by looking the same way as if checking a file) and another that builds a path. They are both pretty straightforward.
int check_handle(char *dir)
{
struct stat statbuf;
if (stat(dir, &statbuf) != 0)
return 1;
return 0;
}
char *fullpath(char *file, char *dir)
{
static char path[PATH_MAX];
strcpy(path, dir);
strcat(path, "/");
strcat(path, file);
return (path);
}
There is also a usage() function, however it does
not need to be included here.
A quick example, of course, is always nice. In the following there are two scenarios, first, a single input jpeg and an output thumb, then a directory of large jpegs to be processed.
[mui@vela:$] etu -i big_room.jpg -o big_room_thumb.jpg [mui@vela:$] etu -s my_sic_party/ -d my_sic_party_thumbs
In earlier versions, some includes were there - but not used.
The PATH_MAX variable comes to mind. Additionally, the
simplest approach to handling files was used versus repeated
DIR * handles and iterations.
The etu program has a lot of possibilities such as
using it as is for building and maintaining thumbnails to extending
it for wholesale management of images and their corresponding
thumbnails. In any case, it does what it is supposed to - fast.
Previous: Epeg II