Skip to content

Commit cb32aa3

Browse files
Copilotletmaik
andcommitted
Move shot_select from postprocess to imread/open_file/open_buffer
Co-authored-by: letmaik <530988+letmaik@users.noreply.github.com>
1 parent d1ed981 commit cb32aa3

File tree

3 files changed

+45
-42
lines changed

3 files changed

+45
-42
lines changed

rawpy/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
import rawpy._rawpy
66
globals().update({k:v for k,v in rawpy._rawpy.__dict__.items() if not k.startswith('_')})
77

8-
def imread(pathOrFile):
8+
def imread(pathOrFile, shot_select=0):
99
"""
1010
Convenience function that creates a :class:`rawpy.RawPy` instance, opens the given file,
1111
and returns the :class:`rawpy.RawPy` instance for further processing.
1212
1313
:param str|file pathOrFile: path or file object of RAW image that will be read
14+
:param int shot_select: select which image to extract from RAW files that contain multiple images
15+
(e.g., Dual Pixel RAW). Default is 0 for the first/main image.
1416
:rtype: :class:`rawpy.RawPy`
1517
"""
1618
d = RawPy()
1719
if hasattr(pathOrFile, 'read'):
18-
d.open_buffer(pathOrFile)
20+
d.open_buffer(pathOrFile, shot_select=shot_select)
1921
else:
20-
d.open_file(pathOrFile)
22+
d.open_file(pathOrFile, shot_select=shot_select)
2123
return d

rawpy/_rawpy.pyx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,15 @@ cdef class RawPy:
411411
with nogil:
412412
self.p.recycle()
413413

414-
def open_file(self, path):
414+
def open_file(self, path, shot_select=0):
415415
"""
416416
Opens the given RAW image file. Should be followed by a call to :meth:`~rawpy.RawPy.unpack`.
417417
418418
.. NOTE:: This is a low-level method, consider using :func:`rawpy.imread` instead.
419419
420420
:param str path: The path to the RAW image.
421+
:param int shot_select: select which image to extract from RAW files that contain multiple images
422+
(e.g., Dual Pixel RAW). Default is 0 for the first/main image.
421423
"""
422424
cdef wchar_t *wchars
423425
cdef Py_ssize_t wchars_len
@@ -433,14 +435,19 @@ cdef class RawPy:
433435
ELSE:
434436
res = self.p.open_file(path.encode('UTF-8'))
435437
self.handle_error(res)
438+
# Set shot_select after opening file
439+
cdef libraw_raw_unpack_params_t* rp = &self.p.imgdata.rawparams
440+
rp.shot_select = shot_select
436441

437-
def open_buffer(self, fileobj):
442+
def open_buffer(self, fileobj, shot_select=0):
438443
"""
439444
Opens the given RAW image file-like object. Should be followed by a call to :meth:`~rawpy.RawPy.unpack`.
440445
441446
.. NOTE:: This is a low-level method, consider using :func:`rawpy.imread` instead.
442447
443448
:param file fileobj: The file-like object.
449+
:param int shot_select: select which image to extract from RAW files that contain multiple images
450+
(e.g., Dual Pixel RAW). Default is 0 for the first/main image.
444451
"""
445452
self.unpack_called = False
446453
self.unpack_thumb_called = False
@@ -451,6 +458,9 @@ cdef class RawPy:
451458
with nogil:
452459
e = self.p.open_buffer(buf, buf_len)
453460
self.handle_error(e)
461+
# Set shot_select after opening buffer
462+
cdef libraw_raw_unpack_params_t* rp = &self.p.imgdata.rawparams
463+
rp.shot_select = shot_select
454464

455465
def unpack(self):
456466
"""
@@ -971,10 +981,6 @@ cdef class RawPy:
971981
p.gamm[1] = params.gamm[1]
972982
p.aber[0] = params.aber[0]
973983
p.aber[2] = params.aber[1]
974-
975-
# shot_select is in rawparams, not params
976-
cdef libraw_raw_unpack_params_t* rp = &self.p.imgdata.rawparams
977-
rp.shot_select = params.shot_select
978984

979985
cdef handle_error(self, int code):
980986
if code > 0:
@@ -1122,7 +1128,7 @@ class Params(object):
11221128
bright=1.0, highlight_mode=HighlightMode.Clip,
11231129
exp_shift=None, exp_preserve_highlights=0.0, no_auto_scale=False,
11241130
gamma=None, chromatic_aberration=None,
1125-
bad_pixels_path=None, shot_select=0):
1131+
bad_pixels_path=None):
11261132
"""
11271133
11281134
If use_camera_wb and use_auto_wb are False and user_wb is None, then
@@ -1165,8 +1171,6 @@ class Params(object):
11651171
:param str bad_pixels_path: path to dcraw bad pixels file. Each bad pixel will be corrected using
11661172
the mean of the neighbor pixels. See the :mod:`rawpy.enhance` module
11671173
for alternative repair algorithms, e.g. using the median.
1168-
:param int shot_select: select which image to extract from RAW files that contain multiple images
1169-
(e.g., Dual Pixel RAW). Default is 0 for the first/main image.
11701174
"""
11711175

11721176
if demosaic_algorithm:
@@ -1227,7 +1231,6 @@ class Params(object):
12271231
else:
12281232
self.aber = (1, 1)
12291233
self.bad_pixels = bad_pixels_path
1230-
self.shot_select = shot_select
12311234

12321235
cdef class processed_image_wrapper:
12331236
cdef RawPy raw

test/test_shot_select.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,37 @@
99
rawTestPath = os.path.join(thisDir, 'iss030e122639.NEF')
1010

1111

12-
def test_shot_select_parameter_exists():
13-
"""Test that shot_select parameter can be passed to postprocess"""
14-
with rawpy.imread(rawTestPath) as raw:
15-
# Test default shot_select=0
16-
rgb = raw.postprocess(shot_select=0, no_auto_bright=True)
12+
def test_shot_select_parameter_via_imread():
13+
"""Test that shot_select parameter can be passed to imread"""
14+
# Test default shot_select=0
15+
with rawpy.imread(rawTestPath, shot_select=0) as raw:
16+
rgb = raw.postprocess(no_auto_bright=True)
1717
assert rgb is not None
1818
assert rgb.shape[2] == 3 # RGB image
1919

20-
def test_shot_select_different_values():
21-
"""Test that different shot_select values can be set"""
22-
with rawpy.imread(rawTestPath) as raw:
23-
# Test shot_select=0
24-
rgb0 = raw.postprocess(shot_select=0, no_auto_bright=True)
25-
assert rgb0 is not None
26-
27-
# Test shot_select=1 (may not have effect on single-shot files)
28-
rgb1 = raw.postprocess(shot_select=1, no_auto_bright=True)
29-
assert rgb1 is not None
30-
31-
# Both should produce valid images (same for single-shot files)
32-
assert rgb0.shape == rgb1.shape
33-
34-
35-
def test_shot_select_via_params():
36-
"""Test that shot_select can be passed via Params object"""
37-
with rawpy.imread(rawTestPath) as raw:
38-
params = rawpy.Params(shot_select=0)
39-
rgb = raw.postprocess(params=params)
40-
assert rgb is not None
41-
assert rgb.shape[2] == 3
20+
21+
def test_shot_select_nonexistent_image():
22+
"""Test that shot_select=1 raises error for single-image files"""
23+
# Test shot_select=1 on a file with only one image should raise an error
24+
with pytest.raises(rawpy.LibRawRequestForNonexistentImageError):
25+
with rawpy.imread(rawTestPath, shot_select=1) as raw:
26+
rgb = raw.postprocess(no_auto_bright=True)
27+
28+
29+
def test_shot_select_via_open_file():
30+
"""Test that shot_select can be passed via open_file"""
31+
raw = rawpy.RawPy()
32+
raw.open_file(rawTestPath, shot_select=0)
33+
raw.unpack()
34+
rgb = raw.postprocess()
35+
assert rgb is not None
36+
assert rgb.shape[2] == 3
37+
raw.close()
4238

4339

4440
def test_shot_select_default_value():
4541
"""Test that default shot_select value is 0"""
46-
params = rawpy.Params()
47-
assert params.shot_select == 0
42+
with rawpy.imread(rawTestPath) as raw:
43+
rgb = raw.postprocess()
44+
assert rgb is not None
45+
assert rgb.shape[2] == 3

0 commit comments

Comments
 (0)