Coverage Report

Created: 2026-10-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openexr/src/lib/OpenEXR/ImfScanLineInputFile.cpp
Line
Count
Source
1
//
2
// SPDX-License-Identifier: BSD-3-Clause
3
// Copyright (c) Contributors to the OpenEXR Project.
4
//
5
6
//-----------------------------------------------------------------------------
7
//
8
//  class ScanLineInputFile
9
//
10
//-----------------------------------------------------------------------------
11
12
#include "ImfScanLineInputFile.h"
13
14
#include "Iex.h"
15
16
#include "IlmThreadPool.h"
17
#if ILMTHREAD_THREADING_ENABLED
18
#    include "IlmThreadProcessGroup.h"
19
#    include <mutex>
20
#endif
21
22
#include "ImfFrameBuffer.h"
23
#include "ImfInputPartData.h"
24
25
#include <vector>
26
27
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
28
29
namespace {
30
31
struct ScanLineProcess
32
{
33
    ~ScanLineProcess ()
34
17.5k
    {
35
17.5k
        if (!first)
36
2.25k
            exr_decoding_destroy (decoder.context, &decoder);
37
17.5k
    }
38
39
    void run_decode (
40
        exr_const_context_t ctxt,
41
        int pn,
42
        const FrameBuffer *outfb,
43
        int fbY,
44
        int fbLastY,
45
        const std::vector<Slice> &filllist);
46
47
    void run_unpack (
48
        exr_const_context_t ctxt,
49
        int pn,
50
        const FrameBuffer *outfb,
51
        int fbY,
52
        int fbLastY,
53
        const std::vector<Slice> &filllist);
54
55
    void update_pointers (
56
        const FrameBuffer *outfb,
57
        int fbY,
58
        int fbLastY);
59
60
    void run_fill (
61
        const FrameBuffer *outfb,
62
        int fbY,
63
        const std::vector<Slice> &filllist);
64
65
    exr_result_t          last_decode_err = EXR_ERR_UNKNOWN;
66
    bool                  first = true;
67
    exr_chunk_info_t      cinfo;
68
    exr_decode_pipeline_t decoder = EXR_DECODE_PIPELINE_INITIALIZER;
69
70
    // requirement to use process group
71
    ScanLineProcess* next;
72
};
73
74
#if ILMTHREAD_THREADING_ENABLED
75
using ScanLineProcessGroup = ILMTHREAD_NAMESPACE::ProcessGroup<ScanLineProcess>;
76
#endif
77
78
} // empty namespace
79
80
struct ScanLineInputFile::Data
81
{
82
    Data (Context *ctxt, int pN, int nT)
83
2.69k
    : _ctxt (ctxt)
84
2.69k
    , partNumber (pN)
85
2.69k
    , numThreads (nT)
86
2.69k
    {}
87
88
    void initialize ()
89
2.69k
    {
90
2.69k
        if (_ctxt->storage (partNumber) != EXR_STORAGE_SCANLINE)
91
0
            throw IEX_NAMESPACE::ArgExc ("File part is not a scanline part");
92
2.69k
    }
93
94
    Context* _ctxt;
95
    int partNumber;
96
    int numThreads;
97
    Header header;
98
    bool header_filled = false;
99
100
    // TODO: remove once we can remove deprecated API
101
    std::vector<char> _pixel_data_scratch;
102
103
    void readPixels (const FrameBuffer &fb, int scanLine1, int scanLine2);
104
105
    // only keep a single stash of a scanline for things which
106
    // are reading one-scanline at a time. if we try to keep a
107
    // multi-threaded stash of scanlines, memory grows too rapidly
108
    std::unique_ptr<ScanLineProcess> singleScan;
109
    std::unique_ptr<ScanLineProcess> checkoutScan ()
110
43.4k
    {
111
43.4k
#if ILMTHREAD_THREADING_ENABLED
112
43.4k
        std::lock_guard<std::mutex> lock (_mx);
113
43.4k
#endif
114
43.4k
        if (singleScan)
115
41.7k
            return std::move (singleScan);
116
1.71k
        return std::make_unique<ScanLineProcess> ();
117
43.4k
    }
118
    void checkinScan (std::unique_ptr<ScanLineProcess> &sp)
119
42.9k
    {
120
42.9k
#if ILMTHREAD_THREADING_ENABLED
121
42.9k
        std::lock_guard<std::mutex> lock (_mx);
122
42.9k
#endif
123
42.9k
        singleScan = std::move (sp);
124
42.9k
    }
125
126
    FrameBuffer frameBuffer;
127
    std::vector<Slice> fill_list;
128
129
#if ILMTHREAD_THREADING_ENABLED
130
    std::mutex _mx;
131
132
    class LineBufferTask final : public ILMTHREAD_NAMESPACE::Task
133
    {
134
    public:
135
        LineBufferTask (
136
            ILMTHREAD_NAMESPACE::TaskGroup* group,
137
            Data*                   ifd,
138
            ScanLineProcessGroup*   lineg,
139
            const FrameBuffer*      outfb,
140
            const exr_chunk_info_t& cinfo,
141
            int                     fby,
142
            int                     endScan)
143
763
            : Task (group)
144
763
            , _outfb (outfb)
145
763
            , _ifd (ifd)
146
763
            , _fby (fby)
147
763
            , _last_fby (endScan)
148
763
            , _line (lineg->pop ())
149
763
            , _line_group (lineg)
150
763
        {
151
763
            _line->cinfo = cinfo;
152
763
        }
153
154
        ~LineBufferTask () override
155
763
        {
156
763
            _line_group->push (_line);
157
763
        }
158
159
        void execute () override;
160
161
    private:
162
        void run_decode ();
163
164
        const FrameBuffer*    _outfb;
165
        Data*                 _ifd;
166
        int                   _fby;
167
        int                   _last_fby;
168
        ScanLineProcess*      _line;
169
        ScanLineProcessGroup* _line_group;
170
    };
171
#endif
172
};
173
174
ScanLineInputFile::ScanLineInputFile (InputPartData* part)
175
2.69k
    : _ctxt (part->context),
176
2.69k
      _data (std::make_shared<Data> (&_ctxt, part->partNumber, part->numThreads))
177
2.69k
{
178
2.69k
    _data->initialize ();
179
2.69k
}
180
181
ScanLineInputFile::ScanLineInputFile (
182
    const char*               filename,
183
    const ContextInitializer& ctxtinit,
184
    int                       numThreads)
185
0
    : _ctxt (filename, ctxtinit, Context::read_mode_t{})
186
0
    , _data (std::make_shared<Data> (&_ctxt, 0, numThreads))
187
0
{
188
0
    _data->initialize ();
189
0
}
190
191
ScanLineInputFile::ScanLineInputFile (
192
        OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is,
193
        int numThreads)
194
0
    : ScanLineInputFile (
195
0
        is.fileName (),
196
0
        ContextInitializer ()
197
0
        .silentHeaderParse (true)
198
0
        .strictHeaderValidation (false)
199
0
        .setInputStream (&is),
200
0
        numThreads)
201
0
{
202
0
}
203
204
ScanLineInputFile::ScanLineInputFile (const char filename[], int numThreads)
205
0
    : ScanLineInputFile (
206
0
        filename,
207
0
        ContextInitializer ()
208
0
        .silentHeaderParse (true)
209
0
        .strictHeaderValidation (false),
210
0
        numThreads)
211
0
{
212
0
}
213
214
const char*
215
ScanLineInputFile::fileName () const
216
7
{
217
7
    return _ctxt.fileName ();
218
7
}
219
220
const Header&
221
ScanLineInputFile::header () const
222
0
{
223
0
#if ILMTHREAD_THREADING_ENABLED
224
0
    std::lock_guard<std::mutex> lock (_data->_mx);
225
0
#endif
226
0
    if (!_data->header_filled)
227
0
    {
228
0
        _data->header = _ctxt.header (_data->partNumber);
229
0
        _data->header_filled = true;
230
0
    }
231
0
    return _data->header;
232
0
}
233
234
int
235
ScanLineInputFile::version () const
236
0
{
237
0
    return _ctxt.version ();
238
0
}
239
240
void
241
ScanLineInputFile::setFrameBuffer (const FrameBuffer& frameBuffer)
242
3.23k
{
243
3.23k
#if ILMTHREAD_THREADING_ENABLED
244
3.23k
    std::lock_guard<std::mutex> lock (_data->_mx);
245
3.23k
#endif
246
3.23k
    _data->fill_list.clear ();
247
3.23k
    _data->singleScan.reset();
248
249
3.23k
    for (FrameBuffer::ConstIterator j = frameBuffer.begin ();
250
12.8k
         j != frameBuffer.end ();
251
9.58k
         ++j)
252
9.59k
    {
253
9.59k
        const exr_attr_chlist_entry_t* curc = _ctxt.findChannel (
254
9.59k
            _data->partNumber, j.name ());
255
256
9.59k
        if (!curc)
257
6.97k
        {
258
6.97k
            _data->fill_list.push_back (j.slice ());
259
6.97k
            continue;
260
6.97k
        }
261
262
2.61k
        if (curc->x_sampling != j.slice ().xSampling ||
263
2.61k
            curc->y_sampling != j.slice ().ySampling)
264
7
            THROW (
265
2.61k
                IEX_NAMESPACE::ArgExc,
266
2.61k
                "X and/or y subsampling factors "
267
2.61k
                "of \""
268
2.61k
                    << j.name ()
269
2.61k
                    << "\" channel "
270
2.61k
                       "of input file \""
271
2.61k
                    << fileName ()
272
2.61k
                    << "\" are "
273
2.61k
                       "not compatible with the frame buffer's "
274
2.61k
                       "subsampling factors.");
275
2.61k
    }
276
277
3.23k
    _data->frameBuffer = frameBuffer;
278
3.23k
}
279
280
const FrameBuffer&
281
ScanLineInputFile::frameBuffer () const
282
44.4k
{
283
44.4k
#if ILMTHREAD_THREADING_ENABLED
284
44.4k
    std::lock_guard<std::mutex> lock (_data->_mx);
285
44.4k
#endif
286
44.4k
    return _data->frameBuffer;
287
44.4k
}
288
289
bool
290
ScanLineInputFile::isComplete () const
291
0
{
292
0
    return _ctxt.chunkTableValid (_data->partNumber);
293
0
}
294
295
bool
296
ScanLineInputFile::isOptimizationEnabled () const
297
0
{
298
    // TODO: the core library has a number of special cased patterns,
299
    // this is all kind of ... not useful? for now, return a pattern
300
    // similar to legacy version
301
0
    return _ctxt.channels (_data->partNumber)->num_channels != 2;
302
0
}
303
304
void
305
ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
306
44.4k
{
307
44.4k
    _data->readPixels (frameBuffer (), scanLine1, scanLine2);
308
44.4k
}
309
310
void
311
ScanLineInputFile::readPixels (
312
    const FrameBuffer& frame, int scanLine1, int scanLine2)
313
0
{
314
0
    _data->readPixels (frame, scanLine1, scanLine2);
315
0
}
316
317
////////////////////////////////////////
318
319
void
320
ScanLineInputFile::readPixels (int scanLine)
321
0
{
322
0
    readPixels (scanLine, scanLine);
323
0
}
324
325
////////////////////////////////////////
326
327
void
328
ScanLineInputFile::rawPixelData (
329
    int firstScanLine, const char*& pixelData, int& pixelDataSize)
330
0
{
331
0
    uint64_t maxsize = 0;
332
0
    if (EXR_ERR_SUCCESS !=
333
0
        exr_get_chunk_unpacked_size (_ctxt, _data->partNumber, &maxsize))
334
0
    {
335
0
        THROW (
336
0
            IEX_NAMESPACE::ArgExc,
337
0
            "Unable to query data size of chunk in file '" << fileName ()
338
0
                                                           << "'");
339
0
    }
340
341
    // again, doesn't actually provide any safety given we're handing
342
    // back a pointer... but will at least prevent two threads
343
    // allocating at the same time and getting sliced
344
0
#if ILMTHREAD_THREADING_ENABLED
345
0
    std::lock_guard<std::mutex> lock (_data->_mx);
346
0
#endif
347
0
    _data->_pixel_data_scratch.resize (maxsize);
348
349
0
    pixelData     = _data->_pixel_data_scratch.data ();
350
0
    pixelDataSize = static_cast<int> (maxsize);
351
352
0
    rawPixelDataToBuffer (
353
0
        firstScanLine, _data->_pixel_data_scratch.data (), pixelDataSize);
354
0
}
355
356
void
357
ScanLineInputFile::rawPixelDataToBuffer (
358
    int scanLine, char* pixelData, int& pixelDataSize) const
359
0
{
360
0
    exr_chunk_info_t cinfo;
361
0
    if (EXR_ERR_SUCCESS == exr_read_scanline_chunk_info (
362
0
                               _ctxt, _data->partNumber, scanLine, &cinfo))
363
0
    {
364
0
        if (pixelDataSize < 0 ||
365
0
            cinfo.packed_size > static_cast<uint64_t> (pixelDataSize))
366
0
        {
367
0
            THROW (
368
0
                IEX_NAMESPACE::ArgExc,
369
0
                "Error reading pixel data from image "
370
0
                "file \""
371
0
                    << fileName ()
372
0
                    << "\". Provided buffer is too small to read raw pixel data:"
373
0
                    << pixelDataSize << " bytes.");
374
0
        }
375
376
0
        pixelDataSize = static_cast<int> (cinfo.packed_size);
377
378
0
        if (EXR_ERR_SUCCESS !=
379
0
            exr_read_chunk (_ctxt, _data->partNumber, &cinfo, pixelData))
380
0
        {
381
0
            THROW (
382
0
                IEX_NAMESPACE::ArgExc,
383
0
                "Error reading pixel data from image "
384
0
                "file \""
385
0
                    << fileName () << "\". Unable to read raw pixel data of "
386
0
                    << pixelDataSize << " bytes.");
387
0
        }
388
0
    }
389
0
    else
390
0
    {
391
0
        if (_ctxt.storage (_data->partNumber) == EXR_STORAGE_TILED)
392
0
        {
393
0
            THROW (
394
0
                IEX_NAMESPACE::ArgExc,
395
0
                "Error reading pixel data from image "
396
0
                "file \""
397
0
                    << fileName ()
398
0
                    << "\". Tried to read a raw scanline from a tiled image.");
399
0
        }
400
0
        else
401
0
        {
402
0
            THROW (
403
0
                IEX_NAMESPACE::ArgExc,
404
0
                "Error reading pixel data from image "
405
0
                "file \""
406
0
                    << fileName ()
407
0
                    << "\". Unable to query data block information.");
408
0
        }
409
0
    }
410
0
}
411
412
////////////////////////////////////////
413
414
void ScanLineInputFile::Data::readPixels (
415
    const FrameBuffer &fb, int scanLine1, int scanLine2)
416
44.4k
{
417
44.4k
    exr_attr_box2i_t dw = _ctxt->dataWindow (partNumber);
418
44.4k
    exr_chunk_info_t cinfo;
419
44.4k
    int32_t          scansperchunk = 1;
420
421
44.4k
    if (EXR_ERR_SUCCESS != exr_get_scanlines_per_chunk (*_ctxt, partNumber, &scansperchunk))
422
0
    {
423
0
        THROW (
424
0
            IEX_NAMESPACE::ArgExc,
425
0
            "Error querying scanline counts from image "
426
0
            "file \"" << _ctxt->fileName () << "\".");
427
0
    }
428
429
44.4k
    if (scanLine2 < scanLine1)
430
0
        std::swap (scanLine1, scanLine2);
431
432
44.4k
    if (scanLine1 < dw.min.y || scanLine2 > dw.max.y)
433
9
    {
434
9
        THROW (
435
9
            IEX_NAMESPACE::ArgExc,
436
9
            "Tried to read scan line outside "
437
9
            "the image file's data window: "
438
9
            << scanLine1 << " - " << scanLine2
439
9
            << " vs datawindow "
440
9
            << dw.min.y << " - " << dw.max.y);
441
9
    }
442
443
44.4k
#if ILMTHREAD_THREADING_ENABLED
444
44.4k
    int64_t nchunks;
445
44.4k
    nchunks = ((int64_t) scanLine2 - (int64_t) scanLine1);
446
44.4k
    nchunks /= (int64_t) scansperchunk;
447
44.4k
    nchunks += 1;
448
449
44.4k
    if (nchunks > 1 && numThreads > 1)
450
989
    {
451
        // we need the lifetime of this to last longer than the
452
        // lifetime of the task group below such that we don't get use
453
        // after free type error, so use scope rules to accomplish
454
        // this
455
989
        ScanLineProcessGroup sg (numThreads);
456
457
989
        {
458
989
            ILMTHREAD_NAMESPACE::TaskGroup tg;
459
460
1.75k
            for (int y = scanLine1; y <= scanLine2; )
461
1.59k
            {
462
1.59k
                if (EXR_ERR_SUCCESS != exr_read_scanline_chunk_info (*_ctxt, partNumber, y, &cinfo))
463
831
                    throw IEX_NAMESPACE::InputExc ("Unable to query scanline information");
464
465
763
                ILMTHREAD_NAMESPACE::ThreadPool::addGlobalTask (
466
763
                    new LineBufferTask (&tg, this, &sg, &fb, cinfo, y, scanLine2) );
467
468
763
                y += scansperchunk - (y - cinfo.start_y);
469
763
            }
470
989
        }
471
472
158
        sg.throw_on_failure ();
473
158
    }
474
43.4k
    else
475
43.4k
#endif
476
43.4k
    {
477
43.4k
        std::unique_ptr<ScanLineProcess> sp = checkoutScan ();
478
479
86.8k
        for (int y = scanLine1; y <= scanLine2; )
480
43.4k
        {
481
43.4k
            if (EXR_ERR_SUCCESS != exr_read_scanline_chunk_info (*_ctxt, partNumber, y, &cinfo))
482
145
                throw IEX_NAMESPACE::InputExc ("Unable to query scanline information");
483
484
            // check if we have the same chunk where we can just
485
            // re-run the unpack (i.e. people reading 1 scan at a time
486
            // in a multi-scanline chunk)
487
43.3k
            if (!sp->first && sp->cinfo.idx == cinfo.idx &&
488
41.7k
                sp->last_decode_err == EXR_ERR_SUCCESS)
489
41.7k
            {
490
41.7k
                sp->run_unpack (
491
41.7k
                    *_ctxt,
492
41.7k
                    partNumber,
493
41.7k
                    &fb,
494
41.7k
                    y,
495
41.7k
                    scanLine2,
496
41.7k
                    fill_list);
497
41.7k
            }
498
1.60k
            else
499
1.60k
            {
500
1.60k
                sp->cinfo = cinfo;
501
1.60k
                sp->run_decode (
502
1.60k
                    *_ctxt,
503
1.60k
                    partNumber,
504
1.60k
                    &fb,
505
1.60k
                    y,
506
1.60k
                    scanLine2,
507
1.60k
                    fill_list);
508
1.60k
            }
509
510
43.3k
            y += scansperchunk - (y - cinfo.start_y);
511
43.3k
        }
512
513
43.3k
        checkinScan (sp);
514
43.3k
    }
515
44.4k
}
516
517
////////////////////////////////////////
518
519
#if ILMTHREAD_THREADING_ENABLED
520
void ScanLineInputFile::Data::LineBufferTask::execute ()
521
763
{
522
763
    try
523
763
    {
524
763
        _line->run_decode (
525
763
            *(_ifd->_ctxt),
526
763
            _ifd->partNumber,
527
763
            _outfb,
528
763
            _fby,
529
763
            _last_fby,
530
763
            _ifd->fill_list);
531
763
    }
532
763
    catch (std::exception &e)
533
763
    {
534
295
        _line_group->record_failure (e.what ());
535
295
    }
536
763
    catch (...)
537
763
    {
538
0
        _line_group->record_failure ("Unknown exception");
539
0
    }
540
763
}
541
#endif
542
543
////////////////////////////////////////
544
545
void ScanLineProcess::run_decode (
546
    exr_const_context_t ctxt,
547
    int pn,
548
    const FrameBuffer *outfb,
549
    int fbY,
550
    int fbLastY,
551
    const std::vector<Slice> &filllist)
552
2.36k
{
553
2.36k
    last_decode_err = EXR_ERR_UNKNOWN;
554
    // stash the flag off to make sure to clean up in the event
555
    // of an exception by changing the flag after init...
556
2.36k
    bool isfirst = first;
557
2.36k
    if (first)
558
2.25k
    {
559
2.25k
        if (EXR_ERR_SUCCESS !=
560
2.25k
            exr_decoding_initialize (ctxt, pn, &cinfo, &decoder))
561
0
        {
562
0
            throw IEX_NAMESPACE::IoExc ("Unable to initialize decode pipeline");
563
0
        }
564
565
2.25k
        first = false;
566
2.25k
    }
567
119
    else
568
119
    {
569
119
        if (EXR_ERR_SUCCESS !=
570
119
            exr_decoding_update (ctxt, pn, &cinfo, &decoder))
571
0
        {
572
0
            throw IEX_NAMESPACE::IoExc ("Unable to update decode pipeline");
573
0
        }
574
119
    }
575
576
2.36k
    update_pointers (outfb, fbY, fbLastY);
577
578
2.36k
    if (isfirst)
579
2.24k
    {
580
2.24k
        if (EXR_ERR_SUCCESS !=
581
2.24k
            exr_decoding_choose_default_routines (ctxt, pn, &decoder))
582
0
        {
583
0
            throw IEX_NAMESPACE::IoExc ("Unable to choose decoder routines");
584
0
        }
585
2.24k
    }
586
587
2.36k
    last_decode_err = exr_decoding_run (ctxt, pn, &decoder);
588
2.36k
    if (EXR_ERR_SUCCESS != last_decode_err)
589
723
        throw IEX_NAMESPACE::IoExc ("Unable to run decoder");
590
591
1.64k
    run_fill (outfb, fbY, filllist);
592
1.64k
}
593
594
////////////////////////////////////////
595
596
void ScanLineProcess::run_unpack (
597
    exr_const_context_t ctxt,
598
    int pn,
599
    const FrameBuffer *outfb,
600
    int fbY,
601
    int fbLastY,
602
    const std::vector<Slice> &filllist)
603
41.7k
{
604
41.7k
    update_pointers (outfb, fbY, fbLastY);
605
606
    /* won't work for deep where we need to re-allocate the number of
607
     * samples but for normal scanlines is fine to just bypass pipe
608
     * and run the unpacker */
609
41.7k
    if (decoder.chunk.unpacked_size > 0 && decoder.unpack_and_convert_fn)
610
41.7k
    {
611
41.7k
        last_decode_err = decoder.unpack_and_convert_fn (&decoder);
612
41.7k
        if (EXR_ERR_SUCCESS != last_decode_err)
613
0
            throw IEX_NAMESPACE::IoExc ("Unable to run decoder");
614
41.7k
    }
615
616
41.7k
    run_fill (outfb, fbY, filllist);
617
41.7k
}
618
619
////////////////////////////////////////
620
621
void ScanLineProcess::update_pointers (
622
    const FrameBuffer *outfb, int fbY, int fbLastY)
623
44.1k
{
624
44.1k
    decoder.user_line_begin_skip = fbY - cinfo.start_y;
625
44.1k
    decoder.user_line_end_ignore = 0;
626
44.1k
    int64_t endY = (int64_t)cinfo.start_y + (int64_t)cinfo.height - 1;
627
44.1k
    if ((int64_t)fbLastY < endY)
628
41.6k
        decoder.user_line_end_ignore = (int32_t)(endY - fbLastY);
629
630
102k
    for (int c = 0; c < decoder.channel_count; ++c)
631
58.1k
    {
632
58.1k
        exr_coding_channel_info_t& curchan = decoder.channels[c];
633
58.1k
        uint8_t*                   ptr;
634
58.1k
        const Slice*               fbslice;
635
636
58.1k
        fbslice = outfb->findSlice (curchan.channel_name);
637
638
58.1k
        if (curchan.height == 0 || !fbslice)
639
14.3k
        {
640
14.3k
            curchan.decode_to_ptr     = NULL;
641
14.3k
            curchan.user_pixel_stride = 0;
642
14.3k
            curchan.user_line_stride  = 0;
643
14.3k
            continue;
644
14.3k
        }
645
646
43.8k
        curchan.user_bytes_per_element = (fbslice->type == HALF) ? 2 : 4;
647
43.8k
        curchan.user_data_type         = (exr_pixel_type_t)fbslice->type;
648
43.8k
        curchan.user_pixel_stride      = fbslice->xStride;
649
43.8k
        curchan.user_line_stride       = fbslice->yStride;
650
651
43.8k
        ptr  = reinterpret_cast<uint8_t*> (fbslice->base);
652
43.8k
        ptr += int64_t (cinfo.start_x / fbslice->xSampling) * int64_t (fbslice->xStride);
653
43.8k
        ptr += int64_t (fbY / fbslice->ySampling) * int64_t (fbslice->yStride);
654
655
43.8k
        curchan.decode_to_ptr = ptr;
656
43.8k
    }
657
44.1k
}
658
659
////////////////////////////////////////
660
661
void ScanLineProcess::run_fill (
662
    const FrameBuffer *outfb,
663
    int fbY,
664
    const std::vector<Slice> &filllist)
665
43.3k
{
666
43.3k
    for (auto& s: filllist)
667
128k
    {
668
128k
        uint8_t*       ptr;
669
670
128k
        ptr  = reinterpret_cast<uint8_t*> (s.base);
671
128k
        ptr += int64_t (cinfo.start_x / s.xSampling) * int64_t (s.xStride);
672
128k
        ptr += int64_t (fbY / s.ySampling) * int64_t (s.yStride);
673
674
        // TODO: update ImfMisc, lift fill type / value
675
128k
        int stop = cinfo.start_y + cinfo.height - decoder.user_line_end_ignore;
676
324k
        for ( int start = fbY; start < stop; ++start )
677
154k
        {
678
154k
            if (start % s.ySampling) continue;
679
680
132k
            uint8_t* outptr = ptr;
681
132k
            for ( int sx = cinfo.start_x, ex = cinfo.start_x + cinfo.width;
682
590M
                  sx < ex; ++sx )
683
590M
            {
684
590M
                if (sx % s.xSampling) continue;
685
686
461M
                switch (s.type)
687
461M
                {
688
0
                    case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
689
0
                    {
690
0
                        unsigned int fillVal = (unsigned int) (s.fillValue);
691
0
                        *(unsigned int*)outptr = fillVal;
692
0
                        break;
693
0
                    }
694
695
461M
                    case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
696
461M
                    {
697
461M
                        half fillVal = half (s.fillValue);
698
461M
                        *(half*)outptr = fillVal;
699
461M
                        break;
700
0
                    }
701
702
0
                    case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
703
0
                    {
704
0
                        float fillVal = float (s.fillValue);
705
0
                        *(float*)outptr = fillVal;
706
0
                        break;
707
0
                    }
708
0
                    default:
709
0
                        throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
710
461M
                }
711
461M
                outptr += s.xStride;
712
461M
            }
713
714
173k
            ptr += s.yStride;
715
173k
        }
716
128k
    }
717
43.3k
}
718
719
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT