forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathJpegDecoder.c
More file actions
210 lines (190 loc) · 9.12 KB
/
JpegDecoder.c
File metadata and controls
210 lines (190 loc) · 9.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// This file is part of the CircuitPython project: https://circuitpython.org
//
// SPDX-FileCopyrightText: Copyright (c) 2023 Jeff Epler for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include "py/obj.h"
#include "py/builtin.h"
#include "py/runtime.h"
#include "shared-bindings/bitmaptools/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-bindings/jpegio/JpegDecoder.h"
#include "shared-module/jpegio/JpegDecoder.h"
#include "shared-module/displayio/Bitmap.h"
//| class JpegDecoder:
//| """A JPEG decoder
//|
//| A JpegDecoder allocates a few thousand bytes of memory. To reduce memory fragmentation,
//| create a single JpegDecoder object and use it anytime a JPEG image needs to be decoded.
//|
//| Example::
//|
//| from jpegio import JpegDecoder
//| from displayio import Bitmap, TileGrid, ColorConverter, Colorspace
//| import supervisor
//|
//| decoder = JpegDecoder()
//| width, height = decoder.open("/sd/example.jpg")
//| bitmap = Bitmap(width, height, 65535)
//| decoder.decode(bitmap)
//| tg = TileGrid(bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED))
//| supervisor.runtime.display.root_group = tg
//| while True:
//| pass
//|
//| """
//|
//| def __init__(self) -> None:
//| """Create a JpegDecoder"""
//| ...
//|
static mp_obj_t jpegio_jpegdecoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
static const mp_arg_t allowed_args[] = {
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
jpegio_jpegdecoder_obj_t *self = mp_obj_malloc(jpegio_jpegdecoder_obj_t, &jpegio_jpegdecoder_type);
common_hal_jpegio_jpegdecoder_construct(self);
return MP_OBJ_FROM_PTR(self);
}
//|
//| @overload
//| def open(self, filename: str) -> Tuple[int, int]: ...
//| @overload
//| def open(self, buffer: ReadableBuffer) -> Tuple[int, int]: ...
//| @overload
//| def open(self, bytesio: io.BytesIO) -> Tuple[int, int]:
//| """Use the specified object as the JPEG data source.
//|
//| The source may be a filename, a binary buffer in memory, or an opened binary stream.
//|
//| The single parameter is positional-only (write ``open(f)``, not
//| ``open(filename=f)`` but due to technical limitations this is
//| not shown in the function signature in the documentation.
//|
//| Returns the image size as the tuple ``(width, height)``."""
//|
static mp_obj_t jpegio_jpegdecoder_open(mp_obj_t self_in, mp_obj_t arg) {
jpegio_jpegdecoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (mp_obj_is_str(arg)) {
arg = mp_call_function_2(
MP_OBJ_FROM_PTR(&mp_builtin_open_obj),
arg,
MP_OBJ_NEW_QSTR(MP_QSTR_rb));
}
mp_buffer_info_t bufinfo;
const mp_stream_p_t *proto = mp_get_stream(arg);
if (proto && proto->read && !proto->is_text) {
return common_hal_jpegio_jpegdecoder_set_source_file(self, arg);
} else if (mp_get_buffer(arg, &bufinfo, MP_BUFFER_READ)) {
return common_hal_jpegio_jpegdecoder_set_source_buffer(self, arg);
}
mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q, %q, or %q, not %q"), MP_QSTR_data_source, MP_QSTR_str, MP_QSTR_BytesIO, MP_QSTR_ReadableBuffer);
}
MP_DEFINE_CONST_FUN_OBJ_2(jpegio_jpegdecoder_open_obj, jpegio_jpegdecoder_open);
//| def decode(
//| self,
//| bitmap: displayio.Bitmap,
//| scale: int = 0,
//| x: int = 0,
//| y: int = 0,
//| *,
//| x1: int,
//| y1: int,
//| x2: int,
//| y2: int,
//| skip_source_index: int,
//| skip_dest_index: int,
//| ) -> None:
//| """Decode JPEG data
//|
//| The bitmap must be large enough to contain the decoded image.
//| The pixel data is stored in the `displayio.Colorspace.RGB565_SWAPPED` colorspace.
//|
//| The image is optionally downscaled by a factor of ``2**scale``.
//| Scaling by a factor of 8 (scale=3) is particularly efficient in terms of decoding time.
//|
//| The remaining parameters are as for `bitmaptools.blit`.
//| Because JPEG is a lossy data format, chroma keying based on the "source
//| index" is not reliable, because the same original RGB value might end
//| up being decompressed as a similar but not equal color value. Using a
//| higher JPEG encoding quality can help, but ultimately it will not be
//| perfect.
//|
//| After a call to ``decode``, you must ``open`` a new JPEG. It is not
//| possible to repeatedly ``decode`` the same jpeg data, even if it is to
//| select different scales or crop regions from it.
//|
//| :param Bitmap bitmap: Optional output buffer
//| :param int scale: Scale factor from 0 to 3, inclusive.
//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int skip_source_index: bitmap palette index in the source that will not be copied,
//| set to None to copy all pixels
//| :param int skip_dest_index: bitmap palette index in the destination bitmap that will not get overwritten
//| by the pixels from the source
//| """
//|
//|
static mp_obj_t jpegio_jpegdecoder_decode(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
jpegio_jpegdecoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
enum { ARG_bitmap, ARG_scale, ARG_x, ARG_y, ARGS_X1_Y1_X2_Y2, ARG_skip_source_index, ARG_skip_dest_index };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_bitmap, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none } },
{ MP_QSTR_scale, MP_ARG_INT, {.u_int = 0 } },
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0 } },
{ MP_QSTR_y, MP_ARG_INT, {.u_int = 0 } },
ALLOWED_ARGS_X1_Y1_X2_Y2(0, 0),
{MP_QSTR_skip_source_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{MP_QSTR_skip_dest_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t bitmap_in = args[ARG_bitmap].u_obj;
mp_arg_validate_type(bitmap_in, &displayio_bitmap_type, MP_QSTR_bitmap);
displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);
int scale = args[ARG_scale].u_int;
mp_arg_validate_int_range(scale, 0, 3, MP_QSTR_scale);
int x = mp_arg_validate_int_range(args[ARG_x].u_int, 0, bitmap->width, MP_QSTR_x);
int y = mp_arg_validate_int_range(args[ARG_y].u_int, 0, bitmap->height, MP_QSTR_y);
bitmaptools_rect_t lim = bitmaptools_validate_coord_range_pair(&args[ARG_x1], bitmap->width, bitmap->height);
uint32_t skip_source_index;
bool skip_source_index_none; // flag whether skip_value was None
if (args[ARG_skip_source_index].u_obj == mp_const_none) {
skip_source_index = 0;
skip_source_index_none = true;
} else {
skip_source_index = mp_obj_get_int(args[ARG_skip_source_index].u_obj);
skip_source_index_none = false;
}
uint32_t skip_dest_index;
bool skip_dest_index_none; // flag whether skip_self_value was None
if (args[ARG_skip_dest_index].u_obj == mp_const_none) {
skip_dest_index = 0;
skip_dest_index_none = true;
} else {
skip_dest_index = mp_obj_get_int(args[ARG_skip_dest_index].u_obj);
skip_dest_index_none = false;
}
common_hal_jpegio_jpegdecoder_decode_into(self, bitmap, scale, x, y, &lim, skip_source_index, skip_source_index_none, skip_dest_index, skip_dest_index_none);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_KW(jpegio_jpegdecoder_decode_obj, 1, jpegio_jpegdecoder_decode);
static const mp_rom_map_elem_t jpegio_jpegdecoder_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&jpegio_jpegdecoder_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&jpegio_jpegdecoder_decode_obj) },
};
static MP_DEFINE_CONST_DICT(jpegio_jpegdecoder_locals_dict, jpegio_jpegdecoder_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
jpegio_jpegdecoder_type,
MP_QSTR_JpegDecoder,
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
make_new, jpegio_jpegdecoder_make_new,
locals_dict, &jpegio_jpegdecoder_locals_dict
);