Skip to content

Commit ffdfe4c

Browse files
committed
Add option to crop after scaling
1 parent 623fa81 commit ffdfe4c

4 files changed

Lines changed: 86 additions & 10 deletions

File tree

src/bin/epeg_main.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@
99
static int verbose_flag = 0;
1010
static int thumb_width = 0; // < 0 means % of input
1111
static int thumb_height = 0; // < 0 means % of input
12+
static int crop_top = 0; // Pixels to crop from the top
13+
static int crop_bottom = 0; // Pixels to crop from the bottom
14+
static int crop_left = 0; // Pixels to crop from the left
15+
static int crop_right = 0; // Pixels to crop from the right
1216
static int max_dimension = 0; // > 0 means we reduce max(w,h) to max_dimension, with aspect preserved
1317
static int outbound_flag = 0; // Ensure specified dimensions will be covered
18+
static int crop_flag = 0; // Crop thumbnail after scaling
1419
static int thumb_quality = 85; // Quality value from 1 to 100
1520
static char *thumb_comment = NULL;
1621
static struct option long_options[] =
@@ -20,6 +25,7 @@ static struct option long_options[] =
2025
{"height", required_argument, 0, 'h'},
2126
{"max", required_argument, 0, 'm'},
2227
{"outbound", no_argument, 0, 'o'},
28+
{"crop", no_argument, 0, 'r'},
2329
{"quality", required_argument, 0, 'q'},
2430
{"comment", required_argument, 0, 'c'},
2531
{0, 0, 0, 0}
@@ -34,6 +40,7 @@ usage(const char *myname)
3440
" -h, --height=<heigth>[%%] set thumbnail heigth [%% of input]\n"
3541
" -m, --max=<maximum> reduce max(w,h) to maximum, with aspect preserved\n"
3642
" -o, --outbound cover at least the specified size (no upscaling or cropping)\n"
43+
" -r, --crop crop the resulting thumbnail (to be used with --outbound)\n"
3744
" -c, --comment=<comment> put a comment in thumbnail\n"
3845
" -q, --quality=<quality> set thumbnail quality (1-100)\n", myname);
3946
exit(0);
@@ -48,7 +55,7 @@ main(int argc, char **argv)
4855
char *input_file = NULL, *output_file = NULL;
4956
char *p;
5057

51-
while ((c = getopt_long(argc, argv, "w:h:voc:m:q:", long_options, &option_index)) != -1) {
58+
while ((c = getopt_long(argc, argv, "w:h:vorc:m:q:", long_options, &option_index)) != -1) {
5259
switch (c) {
5360
case 0:
5461
usage(argv[0]);
@@ -93,6 +100,9 @@ main(int argc, char **argv)
93100
case 'o':
94101
outbound_flag = 1;
95102
break;
103+
case 'r':
104+
crop_flag = 1;
105+
break;
96106
case 'c':
97107
thumb_comment = strdup(optarg);
98108
if (verbose_flag) printf("thumb_comment = %s\n", thumb_comment);
@@ -130,6 +140,7 @@ main(int argc, char **argv)
130140
const char *com;
131141
Epeg_Thumbnail_Info info;
132142
int w, h;
143+
int scaled_w, scaled_h;
133144

134145
com = epeg_comment_get(im);
135146
if (verbose_flag) if (com) printf("Comment: %s\n", com);
@@ -161,17 +172,39 @@ main(int argc, char **argv)
161172
thumb_height = max_dimension;
162173
thumb_width = max_dimension * w / h;
163174
}
175+
if (outbound_flag && crop_flag) {
176+
crop_top = (thumb_height - max_dimension) / 2;
177+
crop_bottom = (thumb_height - max_dimension - crop_top);
178+
crop_left = (thumb_width - max_dimension) / 2;
179+
crop_right = (thumb_width - max_dimension - crop_left);
180+
}
164181
} else if (outbound_flag) {
165-
thumb_width = MAX(thumb_width, thumb_height * w / h);
166-
thumb_height = MAX(thumb_height, thumb_width * h / w);
182+
scaled_w = thumb_height * w / h;
183+
scaled_h = thumb_width * h / w;
184+
if(scaled_w > thumb_width) {
185+
if(crop_flag) {
186+
crop_left = (scaled_w - thumb_width) / 2;
187+
crop_right = scaled_w - thumb_width - crop_left;
188+
}
189+
thumb_width = scaled_w;
190+
}
191+
if(scaled_h > thumb_height) {
192+
if(crop_flag) {
193+
crop_top = (scaled_h - thumb_height) / 2;
194+
crop_bottom = scaled_h - thumb_height - crop_top;
195+
}
196+
thumb_height = scaled_h;
197+
}
167198
}
168199
}
169200

170201
if (verbose_flag) printf("Thumb size: %dx%d\n", thumb_width, thumb_height);
202+
if (verbose_flag) printf("Crop (TxBxLxR): %dx%dx%dx%d\n", crop_top, crop_bottom, crop_left, crop_right);
171203
epeg_decode_size_set(im, thumb_width, thumb_height);
172204
epeg_quality_set (im, thumb_quality);
173205
epeg_thumbnail_comments_enable (im, 1);
174206
epeg_comment_set (im, thumb_comment);
207+
epeg_crop_set (im, crop_top, crop_bottom, crop_left, crop_right);
175208
epeg_file_output_set (im, output_file);
176209
epeg_encode (im);
177210
epeg_close (im);

src/lib/Epeg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ extern "C" {
6262
EAPI void epeg_thumbnail_comments_get (Epeg_Image *im, Epeg_Thumbnail_Info *info);
6363
EAPI void epeg_comment_set (Epeg_Image *im, const char *comment);
6464
EAPI void epeg_quality_set (Epeg_Image *im, int quality);
65+
EAPI void epeg_crop_set (Epeg_Image *im, int top, int bottom, int left, int right);
6566
EAPI void epeg_thumbnail_comments_enable (Epeg_Image *im, int onoff);
6667
EAPI void epeg_file_output_set (Epeg_Image *im, const char *file);
6768
EAPI void epeg_memory_output_set (Epeg_Image *im, unsigned char **data, int *size);

src/lib/epeg_main.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,23 @@ epeg_quality_set(Epeg_Image *im, int quality)
647647
im->out.quality = quality;
648648
}
649649

650+
/**
651+
* Crop a thumbnail after scaling
652+
* @param im A handle to an opened Epeg image.
653+
* @param top Pixels to remove from the top
654+
* @param bottom Pixels to remove from the bottom
655+
* @param left Pixels to remove from the left
656+
* @param right Pixels to remove from the right
657+
*/
658+
EAPI void
659+
epeg_crop_set(Epeg_Image *im, int top, int bottom, int left, int right)
660+
{
661+
im->out.crop_t = (top > 0 ? top : 0);
662+
im->out.crop_b = (bottom > 0 ? bottom : 0);
663+
im->out.crop_l = (left > 0 ? left : 0);
664+
im->out.crop_r = (right > 0 ? right : 0);
665+
}
666+
650667
/**
651668
* Enable thumbnail comments in saved image.
652669
* @param im A handle to an opened Epeg image.
@@ -708,8 +725,8 @@ epeg_memory_output_set(Epeg_Image *im, unsigned char **data, int *size)
708725
*
709726
* This saves the image @p im to its destination specified by
710727
* epeg_file_output_set() or epeg_memory_output_set(). The image will be
711-
* encoded at the deoded pixel size, using the quality, comment and thumbnail
712-
* comment settings set on the image.
728+
* encoded at the deoded pixel size, using the quality, crop, comment and
729+
* thumbnail comment settings set on the image.
713730
*
714731
* retval 1 - error scale
715732
* 2 - error encode
@@ -762,6 +779,7 @@ epeg_close(Epeg_Image *im)
762779
if (!im) return;
763780
if (im->pixels) free(im->pixels);
764781
if (im->lines) free(im->lines);
782+
if (im->cropped_lines) free(im->cropped_lines);
765783
if (im->in.file) free(im->in.file);
766784
if (!im->in.file) free(im->in.jinfo.src);
767785
if (im->in.f || im->in.mem.data) jpeg_destroy_decompress(&(im->in.jinfo));
@@ -983,10 +1001,22 @@ _epeg_decode(Epeg_Image *im)
9831001
return 1;
9841002
}
9851003

1004+
im->cropped_lines = malloc(im->in.jinfo.output_height * sizeof(char *));
1005+
if (!im->cropped_lines)
1006+
{
1007+
free(im->pixels);
1008+
im->pixels = NULL;
1009+
free(im->lines);
1010+
im->lines = NULL;
1011+
return 1;
1012+
}
1013+
9861014
jpeg_start_decompress(&(im->in.jinfo));
9871015

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

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

1028-
for (x = 0; x < im->out.w; x++)
1058+
for (x = 0; x < w; x++)
10291059
{
10301060
src = row + (((x * im->in.jinfo.output_width) / w) * im->in.jinfo.output_components);
10311061
for (i = 0; i < im->in.jinfo.output_components; i++)
@@ -1163,7 +1193,8 @@ _epeg_encode(Epeg_Image *im)
11631193
struct epeg_destination_mgr *dst_mgr = NULL;
11641194
int ok = 0;
11651195

1166-
if ((im->out.w < 1) || (im->out.h < 1)) return 1;
1196+
if ((im->out.w - im->out.crop_l - im->out.crop_r) < 1) return 1;
1197+
if ((im->out.h - im->out.crop_t - im->out.crop_b) < 1) return 1;
11671198
if (im->out.f) return 1;
11681199

11691200
if (im->out.file)
@@ -1218,6 +1249,10 @@ _epeg_encode(Epeg_Image *im)
12181249
}
12191250
im->out.jinfo.image_width = im->out.w;
12201251
im->out.jinfo.image_height = im->out.h;
1252+
if(im->cropped_lines) {
1253+
im->out.jinfo.image_width -= (im->out.crop_l + im->out.crop_r);
1254+
im->out.jinfo.image_height -= (im->out.crop_t + im->out.crop_b);
1255+
}
12211256
im->out.jinfo.input_components = im->in.jinfo.output_components;
12221257
im->out.jinfo.in_color_space = im->in.jinfo.out_color_space;
12231258
im->out.jinfo.dct_method = im->in.jinfo.dct_method;
@@ -1277,8 +1312,13 @@ _epeg_encode(Epeg_Image *im)
12771312
jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf));
12781313
}
12791314

1280-
while (im->out.jinfo.next_scanline < im->out.h)
1281-
jpeg_write_scanlines(&(im->out.jinfo), &(im->lines[im->out.jinfo.next_scanline]), 1);
1315+
if(im->cropped_lines) {
1316+
while (im->out.jinfo.next_scanline < im->out.jinfo.image_height)
1317+
jpeg_write_scanlines(&(im->out.jinfo), &(im->cropped_lines[im->out.crop_t + im->out.jinfo.next_scanline]), 1);
1318+
} else {
1319+
while (im->out.jinfo.next_scanline < im->out.jinfo.image_height)
1320+
jpeg_write_scanlines(&(im->out.jinfo), &(im->lines[im->out.jinfo.next_scanline]), 1);
1321+
}
12821322
jpeg_finish_compress(&(im->out.jinfo));
12831323

12841324
done:

src/lib/epeg_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct _Epeg_Image
3030
struct stat stat_info;
3131
unsigned char *pixels;
3232
unsigned char **lines;
33+
unsigned char **cropped_lines;
3334

3435
char scaled : 1;
3536

@@ -64,6 +65,7 @@ struct _Epeg_Image
6465
} mem;
6566
int x, y;
6667
int w, h;
68+
int crop_t, crop_b, crop_l, crop_r;
6769
char *comment;
6870
FILE *f;
6971
struct jpeg_compress_struct jinfo;

0 commit comments

Comments
 (0)