| 36 | }; |
| 37 | |
| 38 | bool JpegPartialDecodeRandomCropImage(const unsigned char* data, size_t length, |
| 39 | RandomCropGenerator* random_crop_gen, |
| 40 | unsigned char* workspace, size_t workspace_size, |
| 41 | cv::Mat* out_mat) { |
| 42 | struct jpeg_decompress_struct compress_info {}; |
| 43 | struct jpeg_error_mgr jpeg_err {}; |
| 44 | compress_info.err = jpeg_std_error(&jpeg_err); |
| 45 | jpeg_create_decompress(&compress_info); |
| 46 | if (compress_info.err->msg_code != 0) { return false; } |
| 47 | |
| 48 | LibjpegCtx ctx_guard(&compress_info); |
| 49 | |
| 50 | jpeg_mem_src(ctx_guard.compress_info(), data, length); |
| 51 | if (ctx_guard.compress_info()->err->msg_code != 0) { return false; } |
| 52 | |
| 53 | int rc = jpeg_read_header(ctx_guard.compress_info(), TRUE); |
| 54 | if (rc != JPEG_HEADER_OK) { return false; } |
| 55 | |
| 56 | jpeg_start_decompress(ctx_guard.compress_info()); |
| 57 | int width = ctx_guard.compress_info()->output_width; |
| 58 | int height = ctx_guard.compress_info()->output_height; |
| 59 | int pixel_size = ctx_guard.compress_info()->output_components; |
| 60 | |
| 61 | unsigned int u_crop_x = 0, u_crop_y = 0, u_crop_w = width, u_crop_h = height; |
| 62 | if (random_crop_gen) { |
| 63 | CropWindow crop; |
| 64 | random_crop_gen->GenerateCropWindow({height, width}, &crop); |
| 65 | u_crop_y = crop.anchor.At(0); |
| 66 | u_crop_x = crop.anchor.At(1); |
| 67 | u_crop_h = crop.shape.At(0); |
| 68 | u_crop_w = crop.shape.At(1); |
| 69 | } |
| 70 | |
| 71 | unsigned int tmp_w = u_crop_w; |
| 72 | jpeg_crop_scanline(ctx_guard.compress_info(), &u_crop_x, &tmp_w); |
| 73 | if (jpeg_skip_scanlines(ctx_guard.compress_info(), u_crop_y) != u_crop_y) { return false; } |
| 74 | |
| 75 | int row_offset = (tmp_w - u_crop_w) * pixel_size; |
| 76 | int out_row_stride = u_crop_w * pixel_size; |
| 77 | std::vector<unsigned char> decode_output_buf; |
| 78 | unsigned char* decode_output_pointer = nullptr; |
| 79 | size_t image_space_size = width * pixel_size; |
| 80 | |
| 81 | if (image_space_size > workspace_size) { |
| 82 | decode_output_buf.resize(image_space_size); |
| 83 | decode_output_pointer = decode_output_buf.data(); |
| 84 | } else { |
| 85 | decode_output_pointer = workspace; |
| 86 | } |
| 87 | out_mat->create(u_crop_h, u_crop_w, CV_8UC3); |
| 88 | |
| 89 | while (ctx_guard.compress_info()->output_scanline < u_crop_y + u_crop_h) { |
| 90 | unsigned char* buffer_array[1]; |
| 91 | buffer_array[0] = decode_output_pointer; |
| 92 | unsigned int read_line_index = ctx_guard.compress_info()->output_scanline; |
| 93 | jpeg_read_scanlines(ctx_guard.compress_info(), buffer_array, 1); |
| 94 | memcpy(out_mat->data + (read_line_index - u_crop_y) * out_row_stride, |
| 95 | decode_output_pointer + row_offset, out_row_stride); |