Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SVG rendering #256

Merged
merged 3 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ Use `cargo release` to create a new release.

- Update dependencies.

### Fixed

- Fix SVG rendering:
- Correctly enable SVG rendering and image processing features by default in `mdcat` (see [GH-256]).
- Ignore `charset` and other mime type parameters when checking for `image/svg+xml` (see [GH-256]).

[GH-256]: https://github.com/swsnr/mdcat/pull/256

## [2.0.1] – 2023-04-16

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ system_proxy = { version = "0.3.2", default-features = false }
# Our own crates; pinned to an exact version because we release all of this repo
# in a single version. cargo release takes care of updating these.
mdcat-http-reqwest = { version = "=2.0.1", path = "mdcat-http-reqwest", default-features = false}
pulldown-cmark-mdcat = { version = "=2.0.1", path = "pulldown-cmark-mdcat", default-features = false }
pulldown-cmark-mdcat = { version = "=2.0.1", path = "pulldown-cmark-mdcat" }

[dev-dependencies]
pretty_assertions = "1.3.0"
Expand Down
3 changes: 2 additions & 1 deletion mdcat-http-reqwest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ impl HttpResourceHandler {
}

impl ResourceUrlHandler for HttpResourceHandler {
#[instrument(level = "debug", skip(self))]
#[instrument(level = "debug", skip(self), fields(url = %url))]
fn read_resource(&self, url: &Url) -> Result<MimeData> {
filter_schemes(&["http", "https"], url).and_then(|url| {
event!(Level::DEBUG, "Requesting remote HTTP resource {}", url);
let response = self
.http_client
.get(url.clone())
Expand Down
9 changes: 9 additions & 0 deletions pulldown-cmark-mdcat/src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ pub struct MimeData {
pub data: Vec<u8>,
}

impl MimeData {
/// Get the essence of the mime type, if any.
///
/// The essence is roughly the mime type without parameters.
pub fn mime_type_essence(&self) -> Option<&str> {
self.mime_type.as_ref().map(|m| m.essence_str())
}
}

/// Handle resource URLs.
pub trait ResourceUrlHandler: Send + Sync + Debug {
/// Read a resource.
Expand Down
5 changes: 5 additions & 0 deletions pulldown-cmark-mdcat/src/resources/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ impl ResourceUrlHandler for FileResourceHandler {
filter_schemes(&["file"], url).and_then(|url| {
match url.to_file_path() {
Ok(path) => {
event!(
Level::DEBUG,
"Reading from resource file {}",
path.display()
);
let mut buffer = Vec::new();
File::open(&path)?
// Read a byte more than the limit differentiate an expected EOF from hitting the limit
Expand Down
11 changes: 10 additions & 1 deletion pulldown-cmark-mdcat/src/terminal/capabilities/iterm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::io::{self, Result, Write};

use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use tracing::{event, instrument, Level};

use crate::resources::{svg, InlineImageProtocol};
use crate::terminal::osc::write_osc;
Expand All @@ -39,6 +40,7 @@ impl ITerm2 {
/// supported by macOS, this may yield false positives, i.e. this implementation might not return
/// an error even though iTerm2 cannot actually display the image.
impl InlineImageProtocol for ITerm2 {
#[instrument(skip(self, writer, _terminal_size), fields(url = %url))]
fn write_inline_image(
&self,
writer: &mut dyn Write,
Expand All @@ -47,9 +49,16 @@ impl InlineImageProtocol for ITerm2 {
_terminal_size: &crate::TerminalSize,
) -> Result<()> {
let mime_data = resource_handler.read_resource(url)?;
let contents = if mime_data.mime_type == Some(mime::IMAGE_SVG) {
event!(
Level::DEBUG,
"Received data of mime type {:?}",
mime_data.mime_type
);
let contents = if let Some("image/svg+xml") = mime_data.mime_type_essence() {
event!(Level::DEBUG, "Rendering SVG from {}", url);
Cow::Owned(svg::render_svg_to_png(&mime_data.data)?)
} else {
event!(Level::DEBUG, "Rendering mime data literally");
Cow::Borrowed(&mime_data.data)
};
// Determine the local file name to use, by taking the last segment of the URL.
Expand Down
11 changes: 9 additions & 2 deletions pulldown-cmark-mdcat/src/terminal/capabilities/kitty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::str;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use thiserror::Error;
use tracing::{event, Level};
use tracing::{event, instrument, Level};

use crate::resources::{InlineImageProtocol, MimeData};
use crate::terminal::size::PixelSize;
Expand Down Expand Up @@ -128,7 +128,8 @@ impl KittyImages {
terminal_size: PixelSize,
) -> Result<KittyImage, KittyImageError> {
use image::{GenericImageView, ImageFormat};
let image = if mime_data.mime_type == Some(mime::IMAGE_SVG) {
let image = if let Some("image/svg+xml") = mime_data.mime_type_essence() {
event!(Level::DEBUG, "Rendering mime data to SVG");
let png_data = crate::resources::svg::render_svg_to_png(&mime_data.data)?;
image::load_from_memory_with_format(&png_data, ImageFormat::Png)?
} else {
Expand Down Expand Up @@ -288,6 +289,7 @@ impl KittyImages {
/// See <https://sw.kovidgoyal.net/kitty/graphics-protocol.html#control-data-reference>
/// for reference.
impl InlineImageProtocol for KittyImages {
#[instrument(skip(self, writer, terminal_size))]
fn write_inline_image(
&self,
writer: &mut dyn Write,
Expand All @@ -302,6 +304,11 @@ impl InlineImageProtocol for KittyImages {
)
})?;
let mime_data = resource_handler.read_resource(url)?;
event!(
Level::DEBUG,
"Received data of mime type {:?}",
mime_data.mime_type
);
let image = self.render(mime_data, pixel_size)?;
image.write_to(writer)
}
Expand Down