Skip to content

Commit

Permalink
Add option to crop after scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
z38 committed Mar 16, 2015
1 parent f5dac6f commit 298dd12
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 11 deletions.
39 changes: 35 additions & 4 deletions src/bin/epeg_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@
static int verbose_flag = 0;
static int thumb_width = 0; // < 0 means % of input
static int thumb_height = 0; // < 0 means % of input
static int crop_top = 0; // Pixels to crop from the top
static int crop_bottom = 0; // Pixels to crop from the bottom
static int crop_left = 0; // Pixels to crop from the left
static int crop_right = 0; // Pixels to crop from the right
static int max_dimension = 0; // > 0 means we reduce max(w,h) to max_dimension, with aspect preserved
static int inset_flag = 0; // Ensure specified dimensions will be covered
static int crop_flag = 0; // Crop thumbnail after scaling
static int thumb_quality = 85; // Quality value from 1 to 100
static char *thumb_comment = NULL;
static struct option long_options[] =
Expand All @@ -34,6 +39,7 @@ usage(const char *myname)
" -h, --height=<heigth>[%%] set thumbnail heigth [%% of input]\n"
" -m, --max=<maximum> reduce max(w,h) to maximum, with aspect preserved\n"
" -i, --inset cover at least the specified size (no upscaling or cropping)\n"
" -r, --crop crop the resulting thumbnail (to be used with --inset)\n"
" -c, --comment=<comment> put a comment in thumbnail\n"
" -q, --quality=<quality> set thumbnail quality (1-100)\n", myname);
exit(0);
Expand All @@ -48,7 +54,7 @@ main(int argc, char **argv)
char *input_file = NULL, *output_file = NULL;
char *p;

while ((c = getopt_long(argc, argv, "w:h:vic:m:q:", long_options, &option_index)) != -1) {
while ((c = getopt_long(argc, argv, "w:h:virc:m:q:", long_options, &option_index)) != -1) {
switch (c) {
case 0:
usage(argv[0]);
Expand Down Expand Up @@ -93,6 +99,9 @@ main(int argc, char **argv)
case 'i':
inset_flag = 1;
break;
case 'r':
crop_flag = 1;
break;
case 'c':
thumb_comment = strdup(optarg);
if (verbose_flag) printf("thumb_comment = %s\n", thumb_comment);
Expand Down Expand Up @@ -130,6 +139,7 @@ main(int argc, char **argv)
const char *com;
Epeg_Thumbnail_Info info;
int w, h;
int scaled_w, scaled_h;

com = epeg_comment_get(im);
if (verbose_flag) if (com) printf("Comment: %s\n", com);
Expand Down Expand Up @@ -161,17 +171,38 @@ main(int argc, char **argv)
thumb_height = max_dimension;
thumb_width = max_dimension * w / h;
}
if (crop_flag) {
crop_top = (thumb_height - max_dimension) / 2;
crop_bottom = (thumb_height - crop_top);
crop_left = (thumb_width - max_dimension) / 2;
crop_right = (thumb_width - crop_left);
}
} else if (inset_flag) {
thumb_width = MAX(thumb_width, thumb_height * w / h);
thumb_height = MAX(thumb_height, thumb_width * h / w);
scaled_w = thumb_height * w / h;
scaled_h = thumb_width * h / w;
if(scaled_w > thumb_width) {
if(crop_flag) {
crop_left = (scaled_w - thumb_width) / 2;
crop_right = scaled_w - thumb_width - crop_left;
}
thumb_width = scaled_w;
}
if(scaled_h > thumb_height) {
if(crop_flag) {
crop_top = (scaled_h - thumb_height) / 2;
crop_bottom = scaled_h - thumb_height - crop_top;
}
thumb_height = scaled_h;
}
}
}

if (verbose_flag) printf("Thumb size: %dx%d\n", thumb_width, thumb_height);
if (verbose_flag) printf("Crop (TxBxLxR): %dx%dx%dx%d\n", crop_top, crop_bottom, crop_left, crop_right);
epeg_decode_size_set(im, thumb_width, thumb_height);
epeg_quality_set (im, thumb_quality);
epeg_thumbnail_comments_enable (im, 1);
epeg_comment_set (im, thumb_comment);
epeg_crop_set (im, crop_top, crop_bottom, crop_left, crop_right);
epeg_file_output_set (im, output_file);
epeg_encode (im);
epeg_close (im);
Expand Down
1 change: 1 addition & 0 deletions src/lib/Epeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ extern "C" {
EAPI void epeg_thumbnail_comments_get (Epeg_Image *im, Epeg_Thumbnail_Info *info);
EAPI void epeg_comment_set (Epeg_Image *im, const char *comment);
EAPI void epeg_quality_set (Epeg_Image *im, int quality);
EAPI void epeg_crop_set (Epeg_Image *im, int top, int bottom, int left, int right);
EAPI void epeg_thumbnail_comments_enable (Epeg_Image *im, int onoff);
EAPI void epeg_file_output_set (Epeg_Image *im, const char *file);
EAPI void epeg_memory_output_set (Epeg_Image *im, unsigned char **data, int *size);
Expand Down
54 changes: 47 additions & 7 deletions src/lib/epeg_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,23 @@ epeg_quality_set(Epeg_Image *im, int quality)
im->out.quality = quality;
}

/**
* Crop a thumbnail after scaling
* @param im A handle to an opened Epeg image.
* @param top Pixels to remove from the top
* @param bottom Pixels to remove from the bottom
* @param left Pixels to remove from the left
* @param right Pixels to remove from the right
*/
EAPI void
epeg_crop_set(Epeg_Image *im, int top, int bottom, int left, int right)
{
im->out.crop_t = (top > 0 ? top : 0);
im->out.crop_b = (bottom > 0 ? bottom : 0);
im->out.crop_l = (left > 0 ? left : 0);
im->out.crop_r = (right > 0 ? right : 0);
}

/**
* Enable thumbnail comments in saved image.
* @param im A handle to an opened Epeg image.
Expand Down Expand Up @@ -708,8 +725,8 @@ epeg_memory_output_set(Epeg_Image *im, unsigned char **data, int *size)
*
* This saves the image @p im to its destination specified by
* epeg_file_output_set() or epeg_memory_output_set(). The image will be
* encoded at the deoded pixel size, using the quality, comment and thumbnail
* comment settings set on the image.
* encoded at the deoded pixel size, using the quality, crop, comment and
* thumbnail comment settings set on the image.
*
* retval 1 - error scale
* 2 - error encode
Expand Down Expand Up @@ -762,6 +779,7 @@ epeg_close(Epeg_Image *im)
if (!im) return;
if (im->pixels) free(im->pixels);
if (im->lines) free(im->lines);
if (im->cropped_lines) free(im->cropped_lines);
if (im->in.file) free(im->in.file);
if (!im->in.file) free(im->in.jinfo.src);
if (im->in.f || im->in.mem.data) jpeg_destroy_decompress(&(im->in.jinfo));
Expand Down Expand Up @@ -983,10 +1001,22 @@ _epeg_decode(Epeg_Image *im)
return 1;
}

im->cropped_lines = malloc(im->in.jinfo.output_height * sizeof(char *));
if (!im->cropped_lines)
{
free(im->pixels);
im->pixels = NULL;
free(im->lines);
im->lines = NULL;
return 1;
}

jpeg_start_decompress(&(im->in.jinfo));

for (y = 0; y < im->in.jinfo.output_height; y++)
for (y = 0; y < im->in.jinfo.output_height; y++) {
im->lines[y] = im->pixels + (y * im->in.jinfo.output_components * im->in.jinfo.output_width);
im->cropped_lines[y] = im->lines[y] + (im->out.crop_l * im->in.jinfo.output_components);
}

while (im->in.jinfo.output_scanline < im->in.jinfo.output_height)
{
Expand Down Expand Up @@ -1025,7 +1055,7 @@ _epeg_scale(Epeg_Image *im)
row = im->pixels + (((y * im->in.jinfo.output_height) / h) * im->in.jinfo.output_components * im->in.jinfo.output_width);
dst = im->pixels + (y * im->in.jinfo.output_components * im->in.jinfo.output_width);

for (x = 0; x < im->out.w; x++)
for (x = 0; x < w; x++)
{
src = row + (((x * im->in.jinfo.output_width) / w) * im->in.jinfo.output_components);
for (i = 0; i < im->in.jinfo.output_components; i++)
Expand Down Expand Up @@ -1163,7 +1193,8 @@ _epeg_encode(Epeg_Image *im)
struct epeg_destination_mgr *dst_mgr = NULL;
int ok = 0;

if ((im->out.w < 1) || (im->out.h < 1)) return 1;
if ((im->out.w - im->out.crop_l - im->out.crop_r) < 1) return 1;
if ((im->out.h - im->out.crop_t - im->out.crop_b) < 1) return 1;
if (im->out.f) return 1;

if (im->out.file)
Expand Down Expand Up @@ -1218,6 +1249,10 @@ _epeg_encode(Epeg_Image *im)
}
im->out.jinfo.image_width = im->out.w;
im->out.jinfo.image_height = im->out.h;
if(im->cropped_lines) {
im->out.jinfo.image_width -= (im->out.crop_l + im->out.crop_r);
im->out.jinfo.image_height -= (im->out.crop_t + im->out.crop_b);
}
im->out.jinfo.input_components = im->in.jinfo.output_components;
im->out.jinfo.in_color_space = im->in.jinfo.out_color_space;
im->out.jinfo.dct_method = im->in.jinfo.dct_method;
Expand Down Expand Up @@ -1277,8 +1312,13 @@ _epeg_encode(Epeg_Image *im)
jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf));
}

while (im->out.jinfo.next_scanline < im->out.h)
jpeg_write_scanlines(&(im->out.jinfo), &(im->lines[im->out.jinfo.next_scanline]), 1);
if(im->cropped_lines) {
while (im->out.jinfo.next_scanline < im->out.jinfo.image_height)
jpeg_write_scanlines(&(im->out.jinfo), &(im->cropped_lines[im->out.crop_t + im->out.jinfo.next_scanline]), 1);
} else {
while (im->out.jinfo.next_scanline < im->out.jinfo.image_height)
jpeg_write_scanlines(&(im->out.jinfo), &(im->lines[im->out.jinfo.next_scanline]), 1);
}
jpeg_finish_compress(&(im->out.jinfo));

done:
Expand Down
2 changes: 2 additions & 0 deletions src/lib/epeg_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct _Epeg_Image
struct stat stat_info;
unsigned char *pixels;
unsigned char **lines;
unsigned char **cropped_lines;

char scaled : 1;

Expand Down Expand Up @@ -64,6 +65,7 @@ struct _Epeg_Image
} mem;
int x, y;
int w, h;
int crop_t, crop_b, crop_l, crop_r;
char *comment;
FILE *f;
struct jpeg_compress_struct jinfo;
Expand Down

0 comments on commit 298dd12

Please sign in to comment.