fix: image loading
This commit is contained in:
+37
-19
@@ -336,6 +336,7 @@ impl GraphicsCommand {
|
||||
}
|
||||
|
||||
// Decode base64 payload
|
||||
log::debug!("Parsing payload: len={}, content={:?}", payload_part.len(), std::str::from_utf8(payload_part).ok());
|
||||
if !payload_part.is_empty() {
|
||||
if let Ok(payload_str) = std::str::from_utf8(payload_part) {
|
||||
if let Ok(decoded) = base64_decode(payload_str) {
|
||||
@@ -449,7 +450,7 @@ pub fn decode_gif(
|
||||
looping: true,
|
||||
total_duration_ms,
|
||||
state: AnimationState::Running,
|
||||
loops_remaining: None,
|
||||
loops_remaining: DEFAULT_ANIMATION_LOOPS,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -628,7 +629,7 @@ pub fn decode_webm(
|
||||
looping: true,
|
||||
total_duration_ms,
|
||||
state: AnimationState::Running,
|
||||
loops_remaining: None,
|
||||
loops_remaining: DEFAULT_ANIMATION_LOOPS,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -704,6 +705,8 @@ impl ImageData {
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_ANIMATION_LOOPS: Option<u32> = None; // None = infinite
|
||||
|
||||
/// Animation state for playback control.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Default)]
|
||||
pub enum AnimationState {
|
||||
@@ -1162,7 +1165,7 @@ impl ImageStorage {
|
||||
looping: true,
|
||||
total_duration_ms: 100,
|
||||
state: AnimationState::Loading,
|
||||
loops_remaining: None,
|
||||
loops_remaining: DEFAULT_ANIMATION_LOOPS,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1359,6 +1362,7 @@ impl ImageStorage {
|
||||
log::debug!("Animation {} running ({} frames)", id, anim.frames.len());
|
||||
// Reset frame start when starting animation
|
||||
anim.frame_start = None;
|
||||
anim.looping = true;
|
||||
AnimationState::Running
|
||||
}
|
||||
_ => anim.state.clone(),
|
||||
@@ -1754,21 +1758,31 @@ impl ImageStorage {
|
||||
if anim.looping {
|
||||
// Check loop count
|
||||
if let Some(ref mut loops) = anim.loops_remaining {
|
||||
if *loops > 0 {
|
||||
*loops -= 1;
|
||||
anim.current_frame = 0;
|
||||
} else {
|
||||
// No more loops, stop
|
||||
anim.state = AnimationState::Stopped;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Infinite looping
|
||||
anim.current_frame = 0;
|
||||
}
|
||||
}
|
||||
// else: stay on last frame
|
||||
} else {
|
||||
if *loops > 0 {
|
||||
log::debug!("Animation {} looping, {} loops remaining", id, *loops - 1);
|
||||
*loops -= 1;
|
||||
anim.current_frame = 0;
|
||||
} else {
|
||||
log::debug!("Animation {} stopped: no more loops", id);
|
||||
// No more loops, stop
|
||||
anim.state = AnimationState::Stopped;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
log::debug!("Animation {} looping indefinitely", id);
|
||||
// Infinite looping
|
||||
anim.current_frame = 0;
|
||||
}
|
||||
|
||||
}
|
||||
log::debug!("Animation {} reached end, looping={}", id, anim.looping);
|
||||
if !anim.looping {
|
||||
log::debug!("Animation {} stopping (looping=false)", id);
|
||||
}
|
||||
// else: stay on last frame
|
||||
} else {
|
||||
|
||||
anim.current_frame = next_frame;
|
||||
}
|
||||
|
||||
@@ -1811,8 +1825,12 @@ impl ImageStorage {
|
||||
/// when using the STANDARD_NO_PAD engine with lenient decoding.
|
||||
fn base64_decode(input: &str) -> Result<Vec<u8>, GraphicsError> {
|
||||
// Use standard base64 with lenient decoding (ignores whitespace, handles missing padding)
|
||||
let mut input = input.to_string();
|
||||
while input.len() % 4 != 0 {
|
||||
input.push('=');
|
||||
}
|
||||
base64::engine::general_purpose::STANDARD
|
||||
.decode(input.as_bytes())
|
||||
.decode(&input)
|
||||
.map_err(|_| GraphicsError::Base64DecodeFailed)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user