fn read_rle_data_step()

in image/src/codecs/bmp/decoder.rs [1242:1387]


    fn read_rle_data_step(
        &mut self,
        mut pixel_data: &mut [u8],
        image_type: ImageType,
        skip_pixels: u8,
        skip_rows: u8,
    ) -> ImageResult<(u8, u8, bool)> {
        let num_channels = self.num_channels();

        let mut delta_rows_left = 0;
        let mut delta_pixels_left = skip_pixels;
        let mut eof_hit = false;

        // Scope the borrowing of pixel_data by the row iterator.
        {
            // Handling deltas in the RLE scheme means that we need to manually
            // iterate through rows and pixels.  Even if we didn't have to handle
            // deltas, we have to ensure that a single runlength doesn't straddle
            // two rows.
            let mut row_iter = self.rows(&mut pixel_data);
            // If we have previously hit a delta value,
            // blank the rows that are to be skipped.
            blank_bytes((&mut row_iter).take(skip_rows.into()));
            let mut insns_iter = RLEInsnIterator {
                r: &mut self.reader,
                image_type,
            };
            let p = self.palette.as_ref().unwrap();

            'row_loop: while let Some(row) = row_iter.next() {
                let mut pixel_iter = row.chunks_mut(num_channels);
                // Blank delta skipped pixels if any.
                blank_bytes((&mut pixel_iter).take(delta_pixels_left.into()));
                delta_pixels_left = 0;

                'rle_loop: loop {
                    if let Some(insn) = insns_iter.next() {
                        match insn {
                            RLEInsn::EndOfFile => {
                                blank_bytes(pixel_iter);
                                blank_bytes(row_iter);
                                eof_hit = true;
                                break 'row_loop;
                            }
                            RLEInsn::EndOfRow => {
                                blank_bytes(pixel_iter);
                                break 'rle_loop;
                            }
                            RLEInsn::Delta(x_delta, y_delta) => {
                                if y_delta > 0 {
                                    for n in 1..y_delta {
                                        if let Some(row) = row_iter.next() {
                                            // The msdn site on bitmap compression doesn't specify
                                            // what happens to the values skipped when encountering
                                            // a delta code, however IE and the windows image
                                            // preview seems to replace them with black pixels,
                                            // so we stick to that.
                                            for b in row {
                                                *b = 0;
                                            }
                                        } else {
                                            delta_pixels_left = x_delta;
                                            // We've reached the end of the buffer.
                                            delta_rows_left = y_delta - n;
                                            break 'row_loop;
                                        }
                                    }
                                }

                                for _ in 0..x_delta {
                                    if let Some(pixel) = pixel_iter.next() {
                                        for b in pixel {
                                            *b = 0;
                                        }
                                    } else {
                                        // We can't go any further in this row.
                                        break;
                                    }
                                }
                            }
                            RLEInsn::Absolute(length, indices) => {
                                // Absolute mode cannot span rows, so if we run
                                // out of pixels to process, we should stop
                                // processing the image.
                                match image_type {
                                    ImageType::RLE8 => {
                                        if !set_8bit_pixel_run(
                                            &mut pixel_iter,
                                            p,
                                            indices.iter(),
                                            length as usize,
                                        ) {
                                            break 'row_loop;
                                        }
                                    }
                                    ImageType::RLE4 => {
                                        if !set_4bit_pixel_run(
                                            &mut pixel_iter,
                                            p,
                                            indices.iter(),
                                            length as usize,
                                        ) {
                                            break 'row_loop;
                                        }
                                    }
                                    _ => panic!(),
                                }
                            }
                            RLEInsn::PixelRun(n_pixels, palette_index) => {
                                // A pixel run isn't allowed to span rows, but we
                                // simply continue on to the next row if we run
                                // out of pixels to set.
                                match image_type {
                                    ImageType::RLE8 => {
                                        if !set_8bit_pixel_run(
                                            &mut pixel_iter,
                                            p,
                                            repeat(&palette_index),
                                            n_pixels as usize,
                                        ) {
                                            break 'rle_loop;
                                        }
                                    }
                                    ImageType::RLE4 => {
                                        if !set_4bit_pixel_run(
                                            &mut pixel_iter,
                                            p,
                                            repeat(&palette_index),
                                            n_pixels as usize,
                                        ) {
                                            break 'rle_loop;
                                        }
                                    }
                                    _ => panic!(),
                                }
                            }
                        }
                    } else {
                        // We ran out of data while we still had rows to fill in.
                        return Err(DecoderError::RleDataTooShort.into());
                    }
                }
            }
        }
        Ok((delta_pixels_left, delta_rows_left, eof_hit))
    }