Skip to content

Commit

Permalink
Remove icon loading feature (rust-windowing#799)
Browse files Browse the repository at this point in the history
  • Loading branch information
Osspial authored and kosyak committed Jul 10, 2019
1 parent 65e5293 commit c667ee7
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 149 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Expand Up @@ -51,11 +51,9 @@ install:
script:
- cargo build --target $TARGET --verbose
- cargo build --target $TARGET --features serde --verbose
- cargo build --target $TARGET --features icon_loading --verbose
# Running iOS apps on OSX requires the simulator so we skip that for now
- if [ "$TARGET" != "x86_64-apple-ios" ]; then cargo test --target $TARGET --verbose; fi
- if [ "$TARGET" != "x86_64-apple-ios" ]; then cargo test --target $TARGET --features serde --verbose; fi
- if [ "$TARGET" != "x86_64-apple-ios" ]; then cargo test --target $TARGET --features icon_loading --verbose; fi

after_success:
- |
Expand Down
3 changes: 1 addition & 2 deletions CHANGELOG.md
Expand Up @@ -38,8 +38,7 @@
- Removed `serde` implementations from `ControlFlow`.
- On Wayland, add `set_wayland_theme()` to control client decoration color theme
- Added serde serialization to `os::unix::XWindowType`.
- **Breaking:** `image` crate upgraded to 0.21. This is exposed as part of the `icon_loading` API.
- On X11, make event loop thread safe by replacing XNextEvent with select(2) and XCheckIfEvent
- **Breaking:** Remove the `icon_loading` feature and the associated `image` dependency.
- On Windows, fix malformed function pointer typecast that could invoke undefined behavior.
- Refactored Windows state/flag-setting code.
- On Windows, hiding the cursor no longer hides the cursor for all Winit windows - just the one `hide_cursor` was called on.
Expand Down
9 changes: 4 additions & 5 deletions Cargo.toml
Expand Up @@ -11,18 +11,17 @@ documentation = "https://docs.rs/winit"
categories = ["gui"]

[package.metadata.docs.rs]
features = ["icon_loading", "serde"]

[features]
icon_loading = ["image"]
features = ["serde"]

[dependencies]
lazy_static = "1"
libc = "0.2"
log = "0.4"
image = { version = "0.21", optional = true }
serde = { version = "1", optional = true, features = ["serde_derive"] }

[dev-dependencies]
image = "0.21"

[target.'cfg(target_os = "android")'.dependencies.android_glue]
version = "0.2"

Expand Down
1 change: 0 additions & 1 deletion README.md
Expand Up @@ -54,7 +54,6 @@ Winit is only officially supported on the latest stable version of the Rust comp
### Cargo Features

Winit provides the following features, which can be enabled in your `Cargo.toml` file:
* `icon_loading`: Enables loading window icons directly from files. Depends on the [`image` crate](https://crates.io/crates/image).
* `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).

### Platform-specific usage
Expand Down
1 change: 0 additions & 1 deletion appveyor.yml
Expand Up @@ -21,4 +21,3 @@ build: false
test_script:
- cargo test --verbose
- cargo test --features serde --verbose
- cargo test --features icon_loading --verbose
89 changes: 30 additions & 59 deletions examples/window_icon.rs
@@ -1,27 +1,30 @@
// Heads up: you need to compile this example with `--features icon_loading`.
// `Icon::from_path` won't be available otherwise, though for your own applications, you could use
// `Icon::from_rgba` if you don't want to depend on the `image` crate.

extern crate winit;
#[cfg(feature = "icon_loading")]
extern crate image;

#[cfg(feature = "icon_loading")]
use std::path::Path;
use winit::window::{WindowBuilder, Icon};
use winit::event::Event;
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
use winit::window::{WindowBuilder, Icon};
use winit::event::Event;
use winit::event_loop::{EventLoop, ControlFlow};

// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
// since it seems to work well enough in most cases. Be careful about going too high, or
// you'll be bitten by the low-quality downscaling built into the WM.
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");
// While `Icon::from_path` is the most straightforward, you have a few other options. If you
// want to use the `include_bytes` macro, then pass the result to `Icon::from_bytes`. See the
// docs for the full list of options (you'll have to generate the docs with the `icon_loading`
// feature enabled).
let icon = Icon::from_path(path).expect("Failed to open icon");

let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path).expect("Failed to open icon path");
use image::{GenericImageView, Pixel};
let (width, height) = image.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * 4);
for (_, _, pixel) in image.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().data);
}
(rgba, width, height)
};
let icon = Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon");

let event_loop = EventLoop::new();

Expand All @@ -42,56 +45,24 @@ fn main() {
DroppedFile(path) => {
use image::GenericImageView;

let icon_image = image::open(path).expect("Failed to open window icon");

let (width, height) = icon_image.dimensions();
const DESIRED_SIZE: u32 = 32;
let (new_width, new_height) = if width == height {
(DESIRED_SIZE, DESIRED_SIZE)
} else {
// Note that this will never divide by zero, due to the previous condition.
let aspect_adjustment = DESIRED_SIZE as f64
/ std::cmp::max(width, height) as f64;
(
(width as f64 * aspect_adjustment) as u32,
(height as f64 * aspect_adjustment) as u32,
)
};

// By scaling the icon ourselves, we get higher-quality filtering and save
// some memory.
let icon = image::imageops::resize(
&icon_image,
new_width,
new_height,
image::FilterType::Lanczos3,
);

let (offset_x, offset_y) = (
(DESIRED_SIZE - new_width) / 2,
(DESIRED_SIZE - new_height) / 2,
);

let mut canvas = image::ImageBuffer::new(DESIRED_SIZE, DESIRED_SIZE);
image::imageops::replace(
&mut canvas,
&icon,
offset_x,
offset_y,
);

window.set_window_icon(Some(canvas.into()));
window.set_window_icon(Some(load_icon(&path)));
},
_ => (),
}
}
});
}

#[cfg(not(feature = "icon_loading"))]
fn main() {
print!(
r#"This example requires the `icon_loading` feature:
cargo run --example window_icon --features icon_loading
"#);
fn load_icon(path: &Path) -> Icon {
let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path).expect("Failed to open icon path");
use image::{GenericImageView, Pixel};
let (width, height) = image.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * 4);
for (_, _, pixel) in image.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().data);
}
(rgba, width, height)
};
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}
77 changes: 0 additions & 77 deletions src/icon.rs
@@ -1,12 +1,5 @@
use std::{fmt, mem};
use std::error::Error;
#[cfg(feature = "icon_loading")]
use std::io::{BufRead, Seek};
#[cfg(feature = "icon_loading")]
use std::path::Path;

#[cfg(feature = "icon_loading")]
use image;

#[repr(C)]
#[derive(Debug)]
Expand Down Expand Up @@ -70,10 +63,6 @@ impl Error for BadIcon {

#[derive(Debug, Clone, PartialEq, Eq)]
/// An icon used for the window titlebar, taskbar, etc.
///
/// Enabling the `icon_loading` feature provides you with several convenience methods for creating
/// an `Icon` from any format supported by the [image](https://github.com/PistonDevelopers/image)
/// crate.
pub struct Icon {
pub(crate) rgba: Vec<u8>,
pub(crate) width: u32,
Expand Down Expand Up @@ -101,70 +90,4 @@ impl Icon {
Ok(Icon { rgba, width, height })
}
}

#[cfg(feature = "icon_loading")]
/// Loads an `Icon` from the path of an image on the filesystem.
///
/// Requires the `icon_loading` feature.
pub fn from_path<P: AsRef<Path>>(path: P) -> image::ImageResult<Self> {
image::open(path).map(Into::into)
}

#[cfg(feature = "icon_loading")]
/// Loads an `Icon` from anything implementing `BufRead` and `Seek`.
///
/// Requires the `icon_loading` feature.
pub fn from_reader<R: BufRead + Seek>(
reader: R,
format: image::ImageFormat,
) -> image::ImageResult<Self> {
image::load(reader, format).map(Into::into)
}

#[cfg(feature = "icon_loading")]
/// Loads an `Icon` from the unprocessed bytes of an image file.
/// Uses heuristics to determine format.
///
/// Requires the `icon_loading` feature.
pub fn from_bytes(bytes: &[u8]) -> image::ImageResult<Self> {
image::load_from_memory(bytes).map(Into::into)
}

#[cfg(feature = "icon_loading")]
/// Loads an `Icon` from the unprocessed bytes of an image.
///
/// Requires the `icon_loading` feature.
pub fn from_bytes_with_format(
bytes: &[u8],
format: image::ImageFormat,
) -> image::ImageResult<Self> {
image::load_from_memory_with_format(bytes, format).map(Into::into)
}
}

#[cfg(feature = "icon_loading")]
/// Requires the `icon_loading` feature.
impl From<image::DynamicImage> for Icon {
fn from(image: image::DynamicImage) -> Self {
use image::{GenericImageView, Pixel};
let (width, height) = image.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * PIXEL_SIZE);
for (_, _, pixel) in image.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().data);
}
Icon { rgba, width, height }
}
}

#[cfg(feature = "icon_loading")]
/// Requires the `icon_loading` feature.
impl From<image::RgbaImage> for Icon {
fn from(buf: image::RgbaImage) -> Self {
let (width, height) = buf.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * PIXEL_SIZE);
for (_, _, pixel) in buf.enumerate_pixels() {
rgba.extend_from_slice(&pixel.data);
}
Icon { rgba, width, height }
}
}
2 changes: 0 additions & 2 deletions src/lib.rs
Expand Up @@ -81,8 +81,6 @@ extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
#[cfg(feature = "icon_loading")]
extern crate image;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
Expand Down

0 comments on commit c667ee7

Please sign in to comment.