@@ -57,6 +57,15 @@ static ErrorOr<void> invert_cmyk(LoadedImage& image)
57
57
return {};
58
58
}
59
59
60
+ static ErrorOr<void > crop_image (LoadedImage& image, Gfx::IntRect const & rect)
61
+ {
62
+ if (!image.bitmap .has <RefPtr<Gfx::Bitmap>>())
63
+ return Error::from_string_view (" Can't --crop CMYK bitmaps yet" sv);
64
+ auto & frame = image.bitmap .get <RefPtr<Gfx::Bitmap>>();
65
+ frame = TRY (frame->cropped (rect));
66
+ return {};
67
+ }
68
+
60
69
static ErrorOr<void > move_alpha_to_rgb (LoadedImage& image)
61
70
{
62
71
if (!image.bitmap .has <RefPtr<Gfx::Bitmap>>())
@@ -189,6 +198,7 @@ struct Options {
189
198
bool no_output = false ;
190
199
int frame_index = 0 ;
191
200
bool invert_cmyk = false ;
201
+ Optional<Gfx::IntRect> crop_rect;
192
202
bool move_alpha_to_rgb = false ;
193
203
bool strip_alpha = false ;
194
204
StringView assign_color_profile_path;
@@ -198,6 +208,28 @@ struct Options {
198
208
u8 quality = 75 ;
199
209
};
200
210
211
+ template <class T >
212
+ static ErrorOr<Vector<T>> parse_comma_separated_numbers (StringView rect_string)
213
+ {
214
+ auto parts = rect_string.split_view (' ,' );
215
+ Vector<T> part_numbers;
216
+ for (size_t i = 0 ; i < parts.size (); ++i) {
217
+ auto part = parts[i].to_number <T>();
218
+ if (!part.has_value ())
219
+ return Error::from_string_view (" comma-separated parts must be numbers" sv);
220
+ TRY (part_numbers.try_append (part.value ()));
221
+ }
222
+ return part_numbers;
223
+ }
224
+
225
+ static ErrorOr<Gfx::IntRect> parse_rect_string (StringView rect_string)
226
+ {
227
+ auto numbers = TRY (parse_comma_separated_numbers<i32 >(rect_string));
228
+ if (numbers.size () != 4 )
229
+ return Error::from_string_view (" rect must have 4 comma-separated parts" sv);
230
+ return Gfx::IntRect { numbers[0 ], numbers[1 ], numbers[2 ], numbers[3 ] };
231
+ }
232
+
201
233
static ErrorOr<Options> parse_options (Main::Arguments arguments)
202
234
{
203
235
Options options;
@@ -207,6 +239,8 @@ static ErrorOr<Options> parse_options(Main::Arguments arguments)
207
239
args_parser.add_option (options.no_output , " Do not write output (only useful for benchmarking image decoding)" , " no-output" , {});
208
240
args_parser.add_option (options.frame_index , " Which frame of a multi-frame input image (0-based)" , " frame-index" , {}, " INDEX" );
209
241
args_parser.add_option (options.invert_cmyk , " Invert CMYK channels" , " invert-cmyk" , {});
242
+ StringView crop_rect_string;
243
+ args_parser.add_option (crop_rect_string, " Crop to a rectangle" , " crop" , {}, " x,y,w,h" );
210
244
args_parser.add_option (options.move_alpha_to_rgb , " Copy alpha channel to rgb, clear alpha" , " move-alpha-to-rgb" , {});
211
245
args_parser.add_option (options.strip_alpha , " Remove alpha channel" , " strip-alpha" , {});
212
246
args_parser.add_option (options.assign_color_profile_path , " Load color profile from file and assign it to output image" , " assign-color-profile" , {}, " FILE" );
@@ -219,6 +253,9 @@ static ErrorOr<Options> parse_options(Main::Arguments arguments)
219
253
if (options.out_path .is_empty () ^ options.no_output )
220
254
return Error::from_string_view (" exactly one of -o or --no-output is required" sv);
221
255
256
+ if (!crop_rect_string.is_empty ())
257
+ options.crop_rect = TRY (parse_rect_string (crop_rect_string));
258
+
222
259
return options;
223
260
}
224
261
@@ -236,6 +273,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
236
273
if (options.invert_cmyk )
237
274
TRY (invert_cmyk (image));
238
275
276
+ if (options.crop_rect .has_value ())
277
+ TRY (crop_image (image, options.crop_rect .value ()));
278
+
239
279
if (options.move_alpha_to_rgb )
240
280
TRY (move_alpha_to_rgb (image));
241
281
0 commit comments