-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathcode_stream.cpp
More file actions
724 lines (641 loc) · 28.7 KB
/
code_stream.cpp
File metadata and controls
724 lines (641 loc) · 28.7 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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "code_stream.h"
#include <iostream>
#include "error_handling.h"
#include "type_utils.h"
#include "region.h"
#include <tiff_utils.h>
#include <ilogger.h>
#include <log.h>
namespace nvimgcodec {
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, const std::filesystem::path& filename,
size_t bitstream_offset, uint32_t limit_images)
: instance_{instance}
, logger_{logger}
, code_stream_{nullptr}
{
py::gil_scoped_release release;
nvimgcodecCodeStreamView_t view{NVIMGCODEC_STRUCTURE_TYPE_CODE_STREAM_VIEW, sizeof(nvimgcodecCodeStreamView_t),
nullptr, 0, {}, bitstream_offset, limit_images};
auto ret = nvimgcodecCodeStreamCreateFromFile(instance, &code_stream_, filename.string().c_str(),
(bitstream_offset != 0 || limit_images != 0) ? &view : nullptr);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to create code stream");
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, const unsigned char * data, size_t len,
size_t bitstream_offset, uint32_t limit_images)
: instance_{instance}
, logger_{logger}
, code_stream_{nullptr}
{
py::gil_scoped_release release;
nvimgcodecCodeStreamView_t view{NVIMGCODEC_STRUCTURE_TYPE_CODE_STREAM_VIEW, sizeof(nvimgcodecCodeStreamView_t),
nullptr, 0, {}, bitstream_offset, limit_images};
auto ret = nvimgcodecCodeStreamCreateFromHostMem(instance, &code_stream_, data, len,
(bitstream_offset != 0 || limit_images != 0) ? &view : nullptr);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to create code stream");
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, py::bytes data,
size_t bitstream_offset, uint32_t limit_images)
: CodeStream(
instance,
logger,
reinterpret_cast<const unsigned char*>(
static_cast<std::string_view>(data).data()),
static_cast<std::string_view>(data).size(),
bitstream_offset,
limit_images)
{
data_ref_bytes_ = data;
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, py::array_t<uint8_t> arr,
size_t bitstream_offset, uint32_t limit_images)
: CodeStream(instance, logger,
arr.unchecked<1>().data(0),
arr.size(),
bitstream_offset,
limit_images)
{
data_ref_arr_ = arr;
}
unsigned char* CodeStream::resize_buffer(size_t bytes)
{
if (pin_memory_) {
pinned_buffer_->resize(bytes, 0); // Use stream 0 for now
return static_cast<unsigned char*>(pinned_buffer_->data);
} else {
host_buffer_->resize(bytes);
return host_buffer_->data();
}
}
unsigned char* CodeStream::static_resize_buffer(void* ctx, size_t bytes)
{
py::gil_scoped_acquire acquire;
auto handle = reinterpret_cast<CodeStream*>(ctx);
return handle->resize_buffer(bytes);
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, size_t pre_allocated_size, bool pin_memory)
: instance_{instance}
, logger_{logger}
, code_stream_{nullptr}
, pin_memory_{pin_memory}
{
py::gil_scoped_release release;
if (pin_memory_) {
pinned_buffer_ = PinnedBuffer();
if (pre_allocated_size > 0) {
pinned_buffer_->resize(pre_allocated_size, 0);
}
} else {
host_buffer_ = std::vector<unsigned char>();
if (pre_allocated_size > 0) {
host_buffer_->resize(pre_allocated_size);
}
}
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, nvimgcodecImageInfo_t& out_image_info, bool pin_memory)
: instance_{instance}
, logger_{logger}
, image_info_{out_image_info}
, image_info_read_{true}
, code_stream_{nullptr}
, pin_memory_{pin_memory}
{
if (pin_memory_) {
pinned_buffer_ = PinnedBuffer();
} else {
host_buffer_ = std::vector<unsigned char>();
}
py::gil_scoped_release release;
auto ret = nvimgcodecCodeStreamCreateToHostMem(instance, &code_stream_, (void*)this, &static_resize_buffer, &out_image_info);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to create code stream");
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, const std::filesystem::path& filename, nvimgcodecImageInfo_t& out_image_info)
: instance_{instance}
, logger_{logger}
, code_stream_{nullptr}
{
py::gil_scoped_release release;
auto ret = nvimgcodecCodeStreamCreateToFile(instance, &code_stream_, filename.string().c_str(), &out_image_info);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to create code stream");
}
CodeStream::CodeStream(nvimgcodecInstance_t instance, ILogger* logger, nvimgcodecCodeStream_t code_stream)
: instance_{instance}
, logger_{logger}
, code_stream_{code_stream}
{
}
CodeStream::~CodeStream()
{
if (code_stream_) {
nvimgcodecCodeStreamDestroy(code_stream_);
}
}
void CodeStream::reuse(nvimgcodecImageInfo_t& out_image_info)
{
py::gil_scoped_release release;
auto ret = nvimgcodecCodeStreamCreateToHostMem(instance_, &code_stream_, (void*)this, &static_resize_buffer, &out_image_info);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to create code stream");
image_info_ = out_image_info;
image_info_read_ = true;
}
nvimgcodecCodeStream_t CodeStream::handle() const {
return code_stream_;
}
const nvimgcodecCodeStreamInfo_t& CodeStream::getCodeStreamInfo() const {
if (!codestream_info_read_) {
py::gil_scoped_release release;
// Reset the TIFF extension and chain it to codestream_info_
codestream_info_tiff_ext_ = {NVIMGCODEC_STRUCTURE_TYPE_TIFF_CODE_STREAM_INFO, sizeof(nvimgcodecCodeStreamInfoTiffExt_t), nullptr, 0};
codestream_info_ = {NVIMGCODEC_STRUCTURE_TYPE_CODE_STREAM_INFO, sizeof(nvimgcodecCodeStreamInfo_t),
static_cast<void*>(&codestream_info_tiff_ext_), nullptr};
auto ret = nvimgcodecCodeStreamGetCodeStreamInfo(code_stream_, &codestream_info_);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to get code stream info");
codestream_info_read_ = true;
}
return codestream_info_;
}
const nvimgcodecImageInfo_t& CodeStream::getImageInfo() const {
if (!image_info_read_) {
py::gil_scoped_release release;
tile_geometry_info_ = {NVIMGCODEC_STRUCTURE_TYPE_TILE_GEOMETRY_INFO, sizeof(nvimgcodecTileGeometryInfo_t), nullptr, 0, 0, 0, 0};
image_info_ = {NVIMGCODEC_STRUCTURE_TYPE_IMAGE_INFO, sizeof(nvimgcodecImageInfo_t), static_cast<void*>(&tile_geometry_info_)};
auto ret = nvimgcodecCodeStreamGetImageInfo(code_stream_, &image_info_);
if (ret != NVIMGCODEC_STATUS_SUCCESS)
throw std::runtime_error("Failed to get image info");
// Ensure our chain is used so tile accessors (and repr) never see a C++ internal pointer
image_info_.struct_next = static_cast<void*>(&tile_geometry_info_);
image_info_read_ = true;
}
return image_info_;
}
int CodeStream::num_images() const
{
auto& info = getCodeStreamInfo();
return info.num_images;
}
int CodeStream::height() const {
auto& info = getImageInfo();
assert(info.num_planes > 0);
return info.plane_info[0].height;
}
int CodeStream::width() const {
auto& info = getImageInfo();
assert(info.num_planes > 0);
return info.plane_info[0].width;
}
std::optional<int> CodeStream::tile_height() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.tile_height > 0 ? tile_geometry_info_.tile_height : std::optional<int>{};
}
std::optional<int> CodeStream::tile_width() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.tile_width > 0 ? tile_geometry_info_.tile_width : std::optional<int>{};
}
std::optional<int> CodeStream::num_tiles_y() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.num_tiles_y > 0 ? tile_geometry_info_.num_tiles_y : std::optional<int>{};
}
std::optional<int> CodeStream::num_tiles_x() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.num_tiles_x > 0 ? tile_geometry_info_.num_tiles_x : std::optional<int>{};
}
std::optional<int> CodeStream::tile_offset_x() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.tile_width > 0 ? tile_geometry_info_.tile_offset_x : std::optional<int>{};
}
std::optional<int> CodeStream::tile_offset_y() const {
auto& info = getImageInfo();
if (info.struct_next != &tile_geometry_info_)
return std::nullopt;
return tile_geometry_info_.tile_height > 0 ? tile_geometry_info_.tile_offset_y : std::optional<int>{};
}
std::optional<CodeStreamView> CodeStream::view() const
{
auto& info = getCodeStreamInfo();
if (!info.code_stream_view) {
return std::nullopt;
}
return CodeStreamView(*info.code_stream_view);
}
int CodeStream::num_channels() const
{
auto& info = getImageInfo();
int total_channels = 0;
for (uint32_t i = 0; i < info.num_planes; ++i) {
total_channels += info.plane_info[i].num_channels;
}
return total_channels;
}
py::dtype CodeStream::dtype() const
{
auto& info = getImageInfo();
std::string format = format_str_from_type(info.plane_info[0].sample_type);
return py::dtype(format);
}
int CodeStream::precision() const
{
auto& info = getImageInfo();
return info.plane_info[0].precision;
}
std::string CodeStream::codec_name() const
{
auto& info = getImageInfo();
return info.codec_name;
}
size_t CodeStream::capacity() const
{
if (data_ref_bytes_.has_value()) {
auto data_view = static_cast<std::string_view>(data_ref_bytes_.value());
return data_view.size();
} else if (data_ref_arr_.has_value()) {
auto data = data_ref_arr_->unchecked<1>();
return data.size();
} else if (pin_memory_ && pinned_buffer_.has_value()) {
return pinned_buffer_->capacity;
} else if (host_buffer_.has_value()) {
return host_buffer_->capacity();
} else {
auto& info = getCodeStreamInfo();
return info.size;
}
}
size_t CodeStream::size() const
{
if (pin_memory_ && pinned_buffer_.has_value()) {
return pinned_buffer_->size;
} else if (host_buffer_.has_value()) {
return host_buffer_->size();
} else {
auto& info = getCodeStreamInfo();
return info.size;
}
}
bool CodeStream::pin_memory() const
{
return pin_memory_;
}
nvimgcodecColorSpec_t CodeStream::getColorSpec() const
{
auto& info = getImageInfo();
return info.color_spec;
}
nvimgcodecSampleFormat_t CodeStream::getSampleFormat() const
{
auto& info = getImageInfo();
return info.sample_format;
}
std::optional<size_t> CodeStream::next_bitstream_offset() const
{
auto& info = getCodeStreamInfo();
const auto* tiff_ext = findInfoTiffExt(&info);
if (tiff_ext && tiff_ext->next_bitstream_offset != 0) {
return tiff_ext->next_bitstream_offset;
}
return std::nullopt;
}
std::vector<size_t> CodeStream::subifd_offsets() const
{
auto& info = getCodeStreamInfo();
const auto* tiff_ext = findInfoTiffExt(&info);
if (tiff_ext && tiff_ext->subifd_count > 0) {
return std::vector<size_t>(tiff_ext->subifd_offsets,
tiff_ext->subifd_offsets + tiff_ext->subifd_count);
}
return {};
}
CodeStream* CodeStream::getSubCodeStream(const CodeStreamView& code_stream_view)
{
nvimgcodecCodeStream_t sub_code_stream{nullptr};
{
size_t nimg = num_images();
if (code_stream_view.impl_.image_idx >= nimg) {
throw std::runtime_error("Image index #" + std::to_string(code_stream_view.impl_.image_idx) + " out of range (0, " + std::to_string(nimg - 1) + ")");
}
auto already_have_region = view() && view()->impl_.region.ndim != 0;
if (already_have_region && code_stream_view.impl_.region.ndim != 0) {
throw std::runtime_error("Cannot create a sub code stream with nested regions. This is not supported.");
}
py::gil_scoped_release release;
CHECK_NVIMGCODEC(nvimgcodecCodeStreamGetSubCodeStream(code_stream_, &sub_code_stream, &code_stream_view.impl_));
}
return new CodeStream(instance_, logger_, sub_code_stream);
}
void CodeStream::exportToPython(py::module& m, nvimgcodecInstance_t instance, ILogger* logger)
{
// clang-format off
py::class_<CodeStream>(m, "CodeStream",
R"pbdoc(
Class representing a coded stream of image data.
This class provides access to image informations such as dimensions, codec,
and tiling details. It supports initialization from bytes, numpy arrays, or file path.
)pbdoc",
py::buffer_protocol())
.def(py::init([instance, logger](py::bytes bytes, size_t bitstream_offset, uint32_t limit_images) {
return new CodeStream(instance, logger, bytes, bitstream_offset, limit_images);
}),
"bytes"_a, "bitstream_offset"_a = 0, "limit_images"_a = 0, py::keep_alive<1, 2>(),
R"pbdoc(
Initialize a CodeStream using bytes as input.
Note: image_idx and region are not supported here. Use get_sub_code_stream() to select
a specific image or region after creation.
Args:
bytes: The byte data representing the encoded stream.
bitstream_offset: For TIFF files, byte offset to start parsing IFDs from.
Defaults to 0 (parse from file header).
limit_images: For TIFF files, maximum number of images to parse.
Defaults to 0 (no limit, parse all).
)pbdoc")
.def(py::init([instance, logger](py::array_t<uint8_t> arr, size_t bitstream_offset, uint32_t limit_images) {
return new CodeStream(instance, logger, arr, bitstream_offset, limit_images);
}),
"array"_a, "bitstream_offset"_a = 0, "limit_images"_a = 0, py::keep_alive<1, 2>(),
R"pbdoc(
Initialize a CodeStream using a numpy array of uint8 as input.
Note: image_idx and region are not supported here. Use get_sub_code_stream() to select
a specific image or region after creation.
Args:
array: The numpy array containing the encoded stream.
bitstream_offset: For TIFF files, byte offset to start parsing IFDs from.
Defaults to 0 (parse from file header).
limit_images: For TIFF files, maximum number of images to parse.
Defaults to 0 (no limit, parse all).
)pbdoc")
.def(py::init([instance, logger](const std::filesystem::path& filename,
size_t bitstream_offset, uint32_t limit_images) {
return new CodeStream(instance, logger, filename, bitstream_offset, limit_images);
}),
"filename"_a, "bitstream_offset"_a = 0, "limit_images"_a = 0,
R"pbdoc(
Initialize a CodeStream using a file path as input.
Note: image_idx and region are not supported here. Use get_sub_code_stream() to select
a specific image or region after creation.
Args:
filename: The file path to the encoded stream data.
bitstream_offset: For TIFF files, byte offset to start parsing IFDs from.
Use this to continue pagination from next_bitstream_offset or to access
SubIFDs directly. Defaults to 0 (parse from file header).
limit_images: For TIFF files, maximum number of images to parse.
When set, parsing stops after this many IFDs and next_bitstream_offset
will contain the offset to continue. Defaults to 0 (no limit, parse all).
)pbdoc")
.def(py::init([instance, logger](size_t pre_allocated_size, bool pin_memory) {
return new CodeStream(instance, logger, pre_allocated_size, pin_memory);
}),
"pre_allocated_size"_a = 0, "pin_memory"_a = true,
R"pbdoc(
Initialize a CodeStream for encoding output.
Args:
pre_allocated_size: The size of the pre-allocated memory. (default: 0)
pin_memory: If True, the output memory will be pinned. (default: True)
)pbdoc")
.def_buffer([](CodeStream& code_stream) -> py::buffer_info {
auto make_buffer_info = [](void* ptr, size_t size) {
std::vector<size_t> shape{size};
std::vector<size_t> stride{1};
return py::buffer_info(
static_cast<unsigned char*>(ptr), /* Pointer to buffer */
1, /* Size of one scalar */
"B", /* Python struct-style format descriptor */
1, /* Number of dimensions */
shape, /* Buffer dimensions */
stride /* Strides (in bytes) for each index */
);
};
if (code_stream.pin_memory_ && code_stream.pinned_buffer_.has_value()) {
return make_buffer_info(code_stream.pinned_buffer_->data, code_stream.pinned_buffer_->size);
} else if (!code_stream.pin_memory_ && code_stream.host_buffer_.has_value()) {
return make_buffer_info(code_stream.host_buffer_->data(), code_stream.host_buffer_->size());
} else if (code_stream.data_ref_bytes_.has_value()) {
auto data_view = static_cast<std::string_view>(code_stream.data_ref_bytes_.value());
return make_buffer_info(const_cast<void*>(static_cast<const void*>(data_view.data())), data_view.size());
} else if (code_stream.data_ref_arr_.has_value()) {
auto data = code_stream.data_ref_arr_->unchecked<1>();
return make_buffer_info(const_cast<void*>(static_cast<const void*>(data.data(0))), data.size());
} else {
throw std::runtime_error("Not initialized buffer");
}
})
.def("get_sub_code_stream", [](CodeStream& self, size_t image_idx, std::optional<Region> region,
size_t bitstream_offset, uint32_t limit_images) -> CodeStream* {
return self.getSubCodeStream(CodeStreamView(image_idx, region, bitstream_offset, limit_images));
},
"image_idx"_a = 0, "region"_a = std::nullopt,
"bitstream_offset"_a = 0, "limit_images"_a = 0,
/* Keep this (1) CodeStream alive as long as newly created and returned (0) codeStream is alive.
* This is required as this CodeStream may keep alive python object with data (like bytes).
*/
py::keep_alive<0, 1>(),
R"pbdoc(
Get a sub code stream for a specific image index, optional region, and TIFF-specific parameters.
Args:
image_idx: Index of the image in the code stream. Defaults to 0.
region: Optional region of interest within the image.
bitstream_offset: Byte offset to start parsing from (for TIFF SubIFD access).
Use this to access SubIFDs by providing the offset from TIFF Tag 330 metadata.
Defaults to 0 (parse from file header).
limit_images: Maximum number of images to parse (for TIFF pagination).
When set, parsing stops after this many IFDs and next_bitstream_offset
will contain the offset to continue. Defaults to 0 (no limit, parse all).
Returns:
A new CodeStream object representing the sub code stream.
)pbdoc")
.def("get_sub_code_stream", [](CodeStream& self, const CodeStreamView& view) -> CodeStream* {
return self.getSubCodeStream(view);
},
"view"_a,
/* Keep this (1) CodeStream alive as long as newly created and returned (0) codeStream is alive.
* This is required as this CodeStream may keep alive python object with data (like bytes).
*/
py::keep_alive<0, 1>(),
R"pbdoc(
Get a sub code stream using a CodeStreamView object.
Args:
view: A CodeStreamView object specifying the image index and optional region.
Returns:
A new CodeStream object representing the sub code stream.
)pbdoc")
.def_property_readonly("num_images", &CodeStream::num_images,
R"pbdoc(
The number of images in the code stream.
)pbdoc")
.def_property_readonly("next_bitstream_offset", &CodeStream::next_bitstream_offset,
R"pbdoc(
For TIFF files with pagination enabled: the byte offset to the next IFD.
When limit_images is specified in get_sub_code_stream(), this property returns
the offset to continue parsing at. Returns None if there are no more images
or if the file format doesn't support pagination.
Use this for efficient traversal of large multi-page TIFF files.
)pbdoc")
.def_property_readonly("subifd_offsets", &CodeStream::subifd_offsets,
R"pbdoc(
For TIFF files: list of SubIFD byte offsets for the current image (Tag 330).
SubIFDs typically contain reduced-resolution versions (thumbnails) or other
related images. Use these offsets with the bitstream_offset parameter to
create a CodeStream for the SubIFD.
Returns an empty list if no SubIFDs exist or if the format is not TIFF.
Example:
cs = nvimgcodec.CodeStream(path)
sub = cs.get_sub_code_stream(image_idx=0)
for offset in sub.subifd_offsets:
subifd_cs = nvimgcodec.CodeStream(path, bitstream_offset=offset)
)pbdoc")
.def_property_readonly("height", &CodeStream::height,
R"pbdoc(
The vertical dimension of the entire image in pixels.
)pbdoc")
.def_property_readonly("width", &CodeStream::width,
R"pbdoc(
The horizontal dimension of the entire image in pixels.
)pbdoc")
.def_property_readonly("num_channels", &CodeStream::num_channels,
R"pbdoc(
The overall number of channels in the image across all planes.
)pbdoc")
.def_property_readonly("dtype", &CodeStream::dtype,
R"pbdoc(
Data type of samples.
)pbdoc")
.def_property_readonly("precision", &CodeStream::precision,
R"pbdoc(
Maximum number of significant bits in data type. Value 0
means that precision is equal to data type bit depth.
)pbdoc")
.def_property_readonly("codec_name", &CodeStream::codec_name,
R"pbdoc(
Image format.
)pbdoc")
.def_property_readonly("capacity", &CodeStream::capacity,
R"pbdoc(
The capacity of the internal buffer in bytes.
)pbdoc")
.def_property_readonly("size", &CodeStream::size,
R"pbdoc(
The size of the compressed bitstream in bytes.
)pbdoc")
.def_property_readonly("pin_memory", &CodeStream::pin_memory,
R"pbdoc(
Whether the internal buffer is pinned.
)pbdoc")
.def_property_readonly("color_spec", &CodeStream::getColorSpec,
R"pbdoc(
Property to get the color specification for the code stream.
This determines the color space or color profile of the image data.
For instance, sRGB is a common color specification.
Please notice that color specification of decoded Image depends of color_spec
parameter used in decode function so can be different from the one of the code stream.
)pbdoc")
.def_property_readonly("sample_format", &CodeStream::getSampleFormat,
R"pbdoc(
The sample format of the code stream indicating how color components are matched to channels and channels to planes.
)pbdoc")
.def_property_readonly("view", &CodeStream::view,
R"pbdoc(
The view of this code stream, if it was created as a sub code stream.
Contains the image index and optional region of interest.
Returns:
CodeStreamView object if this is a sub code stream, None otherwise.
)pbdoc")
.def_property_readonly("num_tiles_y", &CodeStream::num_tiles_y,
R"pbdoc(
The number of tiles arranged along the vertical axis of the image.
)pbdoc")
.def_property_readonly("num_tiles_x", &CodeStream::num_tiles_x,
R"pbdoc(
The number of tiles arranged along the horizontal axis of the image.
)pbdoc")
.def_property_readonly("tile_height", &CodeStream::tile_height,
R"pbdoc(
The vertical dimension of each individual tile within the image.
)pbdoc")
.def_property_readonly("tile_width", &CodeStream::tile_width,
R"pbdoc(
The horizontal dimension of each individual tile within the image.
)pbdoc")
.def_property_readonly("tile_offset_x", &CodeStream::tile_offset_x,
R"pbdoc(
The horizontal offset of the tile grid to the left of the image.
)pbdoc")
.def_property_readonly("tile_offset_y", &CodeStream::tile_offset_y,
R"pbdoc(
The vertical offset of the tile grid to the top of the image.
)pbdoc")
.def("__repr__", [](const CodeStream* cs) {
std::stringstream ss;
ss << *cs;
return ss.str();
},
R"pbdoc(
Returns a string representation of the CodeStream object, displaying core attributes.
)pbdoc");
// clang-format on
py::implicitly_convertible<py::bytes, CodeStream>();
py::implicitly_convertible<py::array_t<uint8_t>, CodeStream>();
py::implicitly_convertible<std::string, CodeStream>();
py::implicitly_convertible<py::tuple, CodeStream>();
py::implicitly_convertible<CodeStream, CodeStream>();
}
std::ostream& operator<<(std::ostream& os, const CodeStream& cs)
{
os << "CodeStream("
<< " codec_name=" << cs.codec_name()
<< " num_images=" << cs.num_images();
auto view_opt = cs.view();
if (view_opt) {
os << " view=" << *view_opt;
}
os << " height=" << cs.height()
<< " width=" << cs.width()
<< " num_channels=" << cs.num_channels()
<< " dtype=" << dtype_to_str(cs.dtype())
<< " precision=" << cs.precision()
<< " color_spec=" << cs.getColorSpec()
<< " sample_format=" << cs.getSampleFormat()
<< " size=" << cs.size()
<< " capacity=" << cs.capacity();
auto num_tiles_y = cs.num_tiles_y();
if (num_tiles_y)
os << " num_tiles_y=" << num_tiles_y.value();
auto num_tiles_x = cs.num_tiles_x();
if (num_tiles_x)
os << " num_tiles_x=" << num_tiles_x.value();
auto tile_height = cs.tile_height();
if (tile_height)
os << " tile_height=" << tile_height.value();
auto tile_width = cs.tile_width();
if (tile_width)
os << " tile_width=" << tile_width.value();
os << ")";
return os;
}
} // namespace nvimgcodec