microsoft/onnxruntime-extensions

Public

mirrored fromhttps://github.com/microsoft/onnxruntime-extensionsAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
skottmckay/BuildInfra_AndTestImageLibs

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

operators/vision/decode_image.cc

169lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3
4#include "decode_image.hpp"
5
6#include "jpeglib.h"
7#include "png.h"
8
9#include "impl/png_encoder_decoder.hpp"
10
11namespace ort_extensions {
12
13namespace {
14struct my_error_mgr {
15 struct jpeg_error_mgr pub; /* "public" fields */
16
17 jmp_buf setjmp_buffer; /* for return to caller */
18};
19
20typedef struct my_error_mgr* my_error_ptr;
21
22void my_error_exit(j_common_ptr cinfo) {
23 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
24 my_error_ptr myerr = (my_error_ptr)cinfo->err;
25
26 /* Always display the message. */
27 /* We could postpone this until after returning, if we chose. */
28 (*cinfo->err->output_message)(cinfo);
29
30 /* Return control to the setjmp point */
31 longjmp(myerr->setjmp_buffer, 1);
32}
33
34void jpeg_decode(const uint8_t* bytes, uint64_t num_bytes) {
35 struct jpeg_decompress_struct cinfo;
36 my_error_mgr jerr;
37 JSAMPARRAY buffer; /* Output row buffer */
38 int row_stride; /* physical row width in output buffer */
39
40 /* Step 1: allocate and initialize JPEG decompression object */
41
42 /* We set up the normal JPEG error routines, then override error_exit. */
43 cinfo.err = jpeg_std_error(&jerr.pub);
44 jerr.pub.error_exit = my_error_exit;
45
46 /* Establish the setjmp return context for my_error_exit to use. */
47 if (setjmp(jerr.setjmp_buffer)) {
48 /* If we get here, the JPEG code has signaled an error.
49 * We need to clean up the JPEG object, close the input file, and return.
50 */
51 jpeg_destroy_decompress(&cinfo);
52 }
53
54 /* Now we can initialize the JPEG decompression object. */
55 jpeg_create_decompress(&cinfo);
56
57 /* Step 2: specify data source (eg, a file) */
58
59 jpeg_mem_src(&cinfo, bytes, num_bytes);
60
61 /* Step 3: read file parameters with jpeg_read_header() */
62
63 (void)jpeg_read_header(&cinfo, TRUE);
64 /* We can ignore the return value from jpeg_read_header since
65 * (a) suspension is not possible with the stdio data source, and
66 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
67 * See libjpeg.txt for more info.
68 */
69
70 /* Step 4: set parameters for decompression */
71
72 /* In this example, we don't need to change any of the defaults set by
73 * jpeg_read_header(), so we do nothing here.
74 */
75
76 /* Step 5: Start decompressor */
77
78 (void)jpeg_start_decompress(&cinfo);
79 /* We can ignore the return value since suspension is not possible
80 * with the stdio data source.
81 */
82
83 /* We may need to do some setup of our own at this point before reading
84 * the data. After jpeg_start_decompress() we have the correct scaled
85 * output image dimensions available, as well as the output colormap
86 * if we asked for color quantization.
87 * In this example, we need to make an output work buffer of the right size.
88 */
89 /* JSAMPLEs per row in output buffer */
90 row_stride = cinfo.output_width * cinfo.output_components;
91
92 /* Make a one-row-high sample array that will go away when done with image */
93 buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
94
95 /* Step 6: while (scan lines remain to be read) */
96 /* jpeg_read_scanlines(...); */
97
98 /* Here we use the library's state variable cinfo.output_scanline as the
99 * loop counter, so that we don't have to keep track ourselves.
100 */
101 while (cinfo.output_scanline < cinfo.output_height) {
102 /* jpeg_read_scanlines expects an array of pointers to scanlines.
103 * Here the array is only one element long, but you could ask for
104 * more than one scanline at a time if that's more convenient.
105 */
106 (void)jpeg_read_scanlines(&cinfo, buffer, 1);
107 /* Assume put_scanline_someplace wants a pointer and sample count. */
108 // TODO: This needs to write the output.
109 }
110
111 /* Step 7: Finish decompression */
112
113 (void)jpeg_finish_decompress(&cinfo);
114 /* We can ignore the return value since suspension is not possible
115 * with the stdio data source.
116 */
117
118 /* Step 8: Release JPEG decompression object */
119
120 /* This is an important step since it will release a good deal of memory. */
121 jpeg_destroy_decompress(&cinfo);
122}
123} // namespace
124
125void KernelDecodeImage::Compute(OrtKernelContext* context) {
126 // Setup inputs
127 const OrtValue* const inputs = ort_.KernelContext_GetInput(context, 0ULL);
128 OrtTensorDimensions dimensions(ort_, inputs);
129 if (dimensions.size() != 1ULL) {
130 ORT_CXX_API_THROW("[DecodeImage]: Raw image bytes with 1D shape expected.", ORT_INVALID_ARGUMENT);
131 }
132
133 OrtTensorTypeAndShapeInfo* input_info = ort_.GetTensorTypeAndShape(inputs);
134 const int64_t encoded_image_data_len = ort_.GetTensorShapeElementCount(input_info);
135 ort_.ReleaseTensorTypeAndShapeInfo(input_info);
136
137 const uint8_t* encoded_image_data = ort_.GetTensorData<uint8_t>(inputs); // uint8 data
138
139 if (PngDecoder::IsPng(encoded_image_data, encoded_image_data_len)) {
140 auto decoder = PngDecoder(encoded_image_data, encoded_image_data_len);
141 const auto& shape = decoder.Shape();
142 OrtValue* output_value = ort_.KernelContext_GetOutput(context, 0, shape.data(), shape.size());
143 uint8_t* decoded_image_data = ort_.GetTensorMutableData<uint8_t>(output_value);
144
145 decoder.Decode(decoded_image_data, decoder.NumDecodedBytes());
146 } else {
147 jpeg_decode(ort_.GetTensorData<uint8_t>(inputs), encoded_image_data_len);
148 }
149
150 // Decode the image
151 // const std::vector<int32_t> encoded_image_sizes{1, static_cast<int32_t>(encoded_image_data_len)};
152 // const void* encoded_image_data = ort_.GetTensorData<uint8_t>(inputs); // uint8 data
153 // const cv::Mat encoded_image(encoded_image_sizes, CV_8UC1, const_cast<void*>(encoded_image_data));
154 // const cv::Mat decoded_image = cv::imdecode(encoded_image, cv::IMREAD_COLOR);
155
156 // if (decoded_image.data == nullptr) {
157 // ORT_CXX_API_THROW("[DecodeImage] Invalid input. Failed to decode image.", ORT_INVALID_ARGUMENT);
158 // };
159
160 //// Setup output & copy to destination
161 // const cv::Size decoded_image_size = decoded_image.size();
162 // const int64_t colors = decoded_image.elemSize(); // == 3 as it's BGR
163
164 // const std::vector<int64_t> output_dims{decoded_image_size.height, decoded_image_size.width, colors};
165 // OrtValue* output_value = ort_.KernelContext_GetOutput(context, 0, output_dims.data(), output_dims.size());
166 // uint8_t* decoded_image_data = ort_.GetTensorMutableData<uint8_t>(output_value);
167 // memcpy(decoded_image_data, decoded_image.data, decoded_image_size.height * decoded_image_size.width * colors);
168}
169} // namespace ort_extensions
170