// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
let upsample_stage = Upsample8x::new(&self.decoder_state.file_header.transform_data, 0);
let mut upsample_state = upsample_stage.init_local_state(0)?.unwrap();
let xyb_stage = XybStage::new(0, output_color_info.clone());
let from_linear_stage = FromLinearStage::new(0, output_tf.clone());
let src = if self.header.frame_type == FrameType::RegularFrame {
self.decoder_state.lf_frames[0].as_ref().unwrap()
} else {
self.lf_frame_data.as_ref().unwrap()
};
const LF_ROW_OFFSET: usize = 8;
let x0 = rect.origin.0;
let x1 = rect.end().0;
let y0 = rect.origin.1 as isize - 2;
let y1 = rect.end().1 as isize + 2;
let lf_size = src[0].size();
for yy in y0..y1 {
let sy = mirror(yy, lf_size.1);
// Fill in input.
for c in 0..3 {
let bufy = (yy + LF_ROW_OFFSET as isize) as usize;
let row = lf_rows[c].get_row_mut::<f32>(bufy);
let srow = src[c].row(sy);
let off = RowBuffer::x0_offset::<f32>();
row[off..off + len].copy_from_slice(&srow[x0..x1]);
row[off - 1] = srow[mirror(x0 as isize - 1, lf_size.0)];
row[off - 2] = srow[mirror(x0 as isize - 2, lf_size.0)];
row[off + len] = srow[mirror(x1 as isize, lf_size.0)];
row[off + len + 1] = srow[mirror(x1 as isize + 1, lf_size.0)];
}
if yy < y0 + 4 {
continue;
}
let y = yy as usize - 2;
// Upsample.
for c in 0..3 {
let off = RowBuffer::x0_offset::<f32>() - 2;
let input_rows_refs = [
&lf_rows[c].get_row::<f32>(y + LF_ROW_OFFSET - 2)[off..],
&lf_rows[c].get_row::<f32>(y + LF_ROW_OFFSET - 1)[off..],
&lf_rows[c].get_row::<f32>(y + LF_ROW_OFFSET)[off..],
&lf_rows[c].get_row::<f32>(y + LF_ROW_OFFSET + 1)[off..],
&lf_rows[c].get_row::<f32>(y + LF_ROW_OFFSET + 2)[off..],
]
.into_iter()
.collect();
let input_channels = Channels::new(input_rows_refs, 1, 5);
let output_rows_refs =
upsampled_rows[c].get_rows_mut(y * 8..y * 8 + 8, RowBuffer::x0_offset::<f32>());
let mut output_channels = ChannelsMut::new(output_rows_refs, 1, 8);
let image_metadata = &self.decoder_state.file_header.image_metadata;
if !image_metadata.xyb_encoded || !image_metadata.extra_channel_info.is_empty() {
// We only render LF frames for XYB VarDCT images with no extra channels.
// TODO(veluca): we might want to relax this to "no alpha".
return Ok(false);
}
let color_type = pixel_format.color_type;
let data_format = pixel_format.color_data_format.unwrap();
if pixel_format.color_data_format.is_none()
|| output_buffers.is_empty()
|| !matches!(
color_type,
JxlColorType::Rgb | JxlColorType::Rgba | JxlColorType::Bgr | JxlColorType::Bgra,
)
{
// We only render color data, and only to 3- or 4- channel output buffers.
return Ok(false);
}
// We already have a fully-rendered frame and we are not requesting to re-render
// specific regions.
if self.decoder_state.lf_frame_was_rendered && changed_regions.is_none() {
return Ok(false);
}
if changed_regions.is_none() {
self.decoder_state.lf_frame_was_rendered = true;
}
let sz = &self.decoder_state.file_header.size;
let xsize = sz.xsize() as usize;
let ysize = sz.ysize() as usize;
let mut regions_storage;
let regions = if let Some(regions) = changed_regions {
regions
} else {
regions_storage = vec![];
for i in (0..xsize.div_ceil(8)).step_by(256) {
let x0 = i;
let x1 = (i + 256).min(xsize.div_ceil(8));
regions_storage.push(Rect {
origin: (x0, 0),
size: (x1 - x0, ysize.div_ceil(8)),
});
}
®ions_storage[..]
};
let orientation = image_metadata.orientation;
let info = SaveStageBufferInfo {
downsample: (0, 0),
orientation,
byte_size: data_format.bytes_per_sample() * color_type.samples_per_pixel(),
after_extend: false,
};
let info = [Some(info)];
let mut bufs = [Some(JxlOutputBuffer::reborrow(&mut output_buffers[0]))];
let mut bufs = BufferSplitter::new(&mut bufs);
for r in regions {
let upsampled_rect = Rect {
size: (r.size.0 * 8, r.size.1 * 8),
origin: (r.origin.0 * 8, r.origin.1 * 8),
};
let upsampled_rect = upsampled_rect.clip((xsize, ysize));
let mut bufs = bufs.get_local_buffers(
&info,
upsampled_rect,
false,
(xsize, ysize),
(xsize, ysize),
(0, 0),
);
self.render_lf_frame_rect(
color_type,
data_format,
*r,
upsampled_rect,
orientation,
&mut bufs,
(xsize, ysize),
&output_color_info,
&output_tf,
)?;
}
Ok(!regions.is_empty())
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet am 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.