mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Add jpeg and webp support to canvas.toDataURL() (#34861)
Signed-off-by: webbeef <me@webbeef.org>
This commit is contained in:
parent
4f8dcfe6f9
commit
f220d6d3a5
3 changed files with 77 additions and 9 deletions
|
@ -7,7 +7,9 @@ use canvas_traits::webgl::{GLContextAttributes, WebGLVersion};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use euclid::default::{Rect, Size2D};
|
use euclid::default::{Rect, Size2D};
|
||||||
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
||||||
|
use image::codecs::jpeg::JpegEncoder;
|
||||||
use image::codecs::png::PngEncoder;
|
use image::codecs::png::PngEncoder;
|
||||||
|
use image::codecs::webp::WebPEncoder;
|
||||||
use image::{ColorType, ImageEncoder};
|
use image::{ColorType, ImageEncoder};
|
||||||
use ipc_channel::ipc::IpcSharedMemory;
|
use ipc_channel::ipc::IpcSharedMemory;
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
|
@ -397,8 +399,8 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
|
||||||
fn ToDataURL(
|
fn ToDataURL(
|
||||||
&self,
|
&self,
|
||||||
_context: JSContext,
|
_context: JSContext,
|
||||||
_mime_type: Option<DOMString>,
|
mime_type: Option<DOMString>,
|
||||||
_quality: HandleValue,
|
quality: HandleValue,
|
||||||
) -> Fallible<USVString> {
|
) -> Fallible<USVString> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
if !self.origin_is_clean() {
|
if !self.origin_is_clean() {
|
||||||
|
@ -436,17 +438,75 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Only handle image/png for now.
|
enum ImageType {
|
||||||
let mut url = "data:image/png;base64,".to_owned();
|
Png,
|
||||||
|
Jpeg,
|
||||||
|
Webp,
|
||||||
|
}
|
||||||
|
|
||||||
|
// From: https://html.spec.whatwg.org/multipage/#serialising-bitmaps-to-a-file
|
||||||
|
// User agents must support PNG ("image/png"). User agents may support other types.
|
||||||
|
// If the user agent does not support the requested type, then it must create the file using the PNG format.
|
||||||
|
// Anything different than image/jpeg is thus treated as PNG.
|
||||||
|
let (image_type, url) = match mime_type {
|
||||||
|
Some(mime) => {
|
||||||
|
let mime = mime.to_string().to_lowercase();
|
||||||
|
if mime == "image/jpeg" {
|
||||||
|
(ImageType::Jpeg, "data:image/jpeg;base64,")
|
||||||
|
} else if mime == "image/webp" {
|
||||||
|
(ImageType::Webp, "data:image/webp;base64,")
|
||||||
|
} else {
|
||||||
|
(ImageType::Png, "data:image/png;base64,")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (ImageType::Png, "data:image/png;base64,"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut url = url.to_owned();
|
||||||
|
|
||||||
let mut encoder = base64::write::EncoderStringWriter::from_consumer(
|
let mut encoder = base64::write::EncoderStringWriter::from_consumer(
|
||||||
&mut url,
|
&mut url,
|
||||||
&base64::engine::general_purpose::STANDARD,
|
&base64::engine::general_purpose::STANDARD,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
match image_type {
|
||||||
|
ImageType::Png => {
|
||||||
// FIXME(nox): https://github.com/image-rs/image-png/issues/86
|
// FIXME(nox): https://github.com/image-rs/image-png/issues/86
|
||||||
// FIXME(nox): https://github.com/image-rs/image-png/issues/87
|
// FIXME(nox): https://github.com/image-rs/image-png/issues/87
|
||||||
PngEncoder::new(&mut encoder)
|
PngEncoder::new(&mut encoder)
|
||||||
.write_image(&file, self.Width(), self.Height(), ColorType::Rgba8)
|
.write_image(&file, self.Width(), self.Height(), ColorType::Rgba8)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
},
|
||||||
|
ImageType::Jpeg => {
|
||||||
|
let jpeg_encoder = if quality.is_number() {
|
||||||
|
let quality = quality.to_number();
|
||||||
|
// The specification allows quality to be in [0.0..1.0] but the JPEG encoder
|
||||||
|
// expects it to be in [1..100]
|
||||||
|
if (0.0..=1.0).contains(&quality) {
|
||||||
|
JpegEncoder::new_with_quality(
|
||||||
|
&mut encoder,
|
||||||
|
(quality * 100.0).round().clamp(1.0, 100.0) as u8,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
JpegEncoder::new(&mut encoder)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JpegEncoder::new(&mut encoder)
|
||||||
|
};
|
||||||
|
|
||||||
|
jpeg_encoder
|
||||||
|
.write_image(&file, self.Width(), self.Height(), ColorType::Rgba8)
|
||||||
|
.unwrap();
|
||||||
|
},
|
||||||
|
|
||||||
|
ImageType::Webp => {
|
||||||
|
// No quality support because of https://github.com/image-rs/image/issues/1984
|
||||||
|
WebPEncoder::new_lossless(&mut encoder)
|
||||||
|
.write_image(&file, self.Width(), self.Height(), ColorType::Rgba8)
|
||||||
|
.unwrap();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
encoder.into_inner();
|
encoder.into_inner();
|
||||||
Ok(USVString(url))
|
Ok(USVString(url))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toDataURL.jpeg.alpha.html]
|
||||||
|
[toDataURL with JPEG composites onto black]
|
||||||
|
expected: FAIL
|
|
@ -90,3 +90,8 @@
|
||||||
[WebGL test #55: should draw with 255,192,128,1\nat (0, 0) expected: 255,192,128,1 was 0,0,0,255]
|
[WebGL test #55: should draw with 255,192,128,1\nat (0, 0) expected: 255,192,128,1 was 0,0,0,255]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #62: should draw with 128,128,128,255\nat (0, 0) expected: 128,128,128,255 was 255,255,255,255]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #69: should draw with 128,128,128,255\nat (0, 0) expected: 128,128,128,255 was 255,255,255,255]
|
||||||
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue