Skip to content

Commit 44a85de

Browse files
committed
chore: initial commit
0 parents  commit 44a85de

File tree

10 files changed

+370
-0
lines changed

10 files changed

+370
-0
lines changed

.github/workflows/build.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: build
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
build:
11+
name: Builds on ${{ matrix.os }}
12+
runs-on: ${{ matrix.os }}
13+
strategy:
14+
matrix:
15+
os: [
16+
ubuntu-latest,
17+
windows-latest,
18+
macOS-latest
19+
]
20+
21+
steps:
22+
- uses: actions/checkout@v1
23+
24+
- uses: actions-rs/toolchain@v1
25+
with:
26+
profile: minimal
27+
toolchain: stable
28+
29+
- name: Build
30+
run: cargo build --release --locked

.github/workflows/clippy.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: clippy
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
clippy:
10+
name: Runs "cargo clippy" on ${{ matrix.os }}
11+
runs-on: ${{ matrix.os }}
12+
strategy:
13+
matrix:
14+
os: [
15+
ubuntu-latest,
16+
windows-latest,
17+
macOS-latest
18+
]
19+
20+
steps:
21+
- uses: actions/checkout@v2
22+
23+
- uses: actions-rs/toolchain@v1
24+
with:
25+
profile: minimal
26+
toolchain: stable
27+
override: true
28+
components: clippy
29+
30+
- name: Cache .cargo and target
31+
uses: actions/cache@v2
32+
with:
33+
path: |
34+
~/.cargo
35+
./target
36+
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
37+
restore-keys: |
38+
${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
39+
${{ runner.os }}-cargo-clippy
40+
41+
- name: cargo clippy
42+
uses: actions-rs/cargo@v1
43+
with:
44+
command: clippy
45+
args: -- -D warnings

.github/workflows/fmt.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: fmt
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
fmt:
10+
name: Runs "cargo fmt" on ${{ matrix.os }}
11+
runs-on: ${{ matrix.os }}
12+
strategy:
13+
matrix:
14+
os: [
15+
ubuntu-latest,
16+
windows-latest,
17+
macOS-latest
18+
]
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v2
23+
24+
- uses: actions-rs/toolchain@v1
25+
with:
26+
profile: minimal
27+
toolchain: stable
28+
override: true
29+
components: rustfmt
30+
31+
- name: Cache .cargo and target
32+
uses: actions/cache@v2
33+
with:
34+
path: |
35+
~/.cargo
36+
./target
37+
key: ${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }}
38+
restore-keys: |
39+
${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }}
40+
${{ runner.os }}-cargo-fmt
41+
42+
- name: Run fmt
43+
uses: actions-rs/cargo@v1
44+
with:
45+
command: fmt
46+
args: --all -- --check

.github/workflows/release.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
publish-dry-run:
10+
name: "Runs cargo publish --dry-run"
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v1
14+
15+
- uses: actions-rs/toolchain@v1
16+
with:
17+
profile: minimal
18+
toolchain: stable
19+
20+
- name: publish crate
21+
run: cargo publish --dry-run
22+
23+
create-release:
24+
name: Create Release
25+
needs: publish-dry-run
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v2
30+
31+
- name: Create Release with Notes
32+
uses: actions/github-script@v5
33+
with:
34+
github-token: ${{secrets.GITHUB_TOKEN}}
35+
script: |
36+
await github.request(`POST /repos/${{ github.repository }}/releases`, {
37+
tag_name: "${{ github.ref }}",
38+
generate_release_notes: true
39+
});
40+
41+
publish-crate:
42+
name: Publish to crates.io
43+
needs: create-release
44+
runs-on: ubuntu-latest
45+
steps:
46+
- uses: actions/checkout@v1
47+
48+
- uses: actions-rs/toolchain@v1
49+
with:
50+
profile: minimal
51+
toolchain: stable
52+
- run: cargo login ${CRATES_IO_TOKEN}
53+
env:
54+
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
55+
56+
- name: publish crate
57+
run: cargo publish

.github/workflows/test.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: test
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
test:
10+
name: Runs "cargo test" on ${{ matrix.os }}
11+
runs-on: ${{ matrix.os }}
12+
strategy:
13+
matrix:
14+
os: [
15+
ubuntu-latest,
16+
windows-latest,
17+
macOS-latest
18+
]
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v2
23+
24+
- uses: actions-rs/toolchain@v1
25+
with:
26+
profile: minimal
27+
toolchain: stable
28+
override: true
29+
30+
- name: Cache .cargo and target
31+
uses: actions/cache@v2
32+
with:
33+
path: |
34+
~/.cargo
35+
./target
36+
key: ${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }}
37+
restore-keys: |
38+
${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }}
39+
${{ runner.os }}-cargo-fmt
40+
41+
- name: Run tests
42+
uses: actions-rs/cargo@v1
43+
with:
44+
command: test
45+
args: -- --nocapture

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
3+
/target
4+
/Cargo.lock

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "favicon"
3+
description = "Build favicons for your website"
4+
authors = ["Esteban Borai <estebanborai@gmail.com>"]
5+
version = "0.1.0-draft-1"
6+
edition = "2021"
7+
repository = "https://github.com/EstebanBorai/favicon"
8+
categories = ["web-programming"]
9+
homepage = "https://github.com/EstebanBorai/favicon"
10+
keywords = ["favicon", "images", "web", "website"]
11+
license = "MIT OR Apache-2.0"
12+
readme = "README.md"
13+
14+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15+
16+
[dependencies]
17+
image = "0.24.2"

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div>
2+
<h1 align="center">favicon</h1>
3+
<h4 align="center">
4+
Build favicons for your website
5+
</h4>
6+
</div>
7+
8+
<div align="center">
9+
10+
[![Crates.io](https://img.shields.io/crates/v/favicon.svg)](https://crates.io/crates/favicon)
11+
[![Documentation](https://docs.rs/favicon/badge.svg)](https://docs.rs/favicon)
12+
![Build](https://github.com/EstebanBorai/favicon/workflows/build/badge.svg)
13+
![Clippy](https://github.com/EstebanBorai/favicon/workflows/clippy/badge.svg)
14+
![Formatter](https://github.com/EstebanBorai/favicon/workflows/fmt/badge.svg)
15+
16+
</div>

fixtures/dice.png

223 KB
Loading

src/lib.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use image::imageops::FilterType;
2+
use image::{DynamicImage, ImageFormat};
3+
use std::fs::File;
4+
use std::path::Path;
5+
6+
pub const APPLE_TOUCH_ICON_57: Preset<'static> =
7+
Preset::new("apple_touch_icon-57.png", Format::Png, 57, 57);
8+
pub const APPLE_TOUCH_ICON_60: Preset<'static> =
9+
Preset::new("apple_touch_icon-60.png", Format::Png, 60, 60);
10+
pub const APPLE_TOUCH_ICON_72: Preset<'static> =
11+
Preset::new("apple_touch_icon-72.png", Format::Png, 70, 70);
12+
pub const APPLE_TOUCH_ICON_76: Preset<'static> =
13+
Preset::new("apple_touch_icon-76.png", Format::Png, 76, 76);
14+
pub const APPLE_TOUCH_ICON_114: Preset<'static> =
15+
Preset::new("apple_touch_icon-114.png", Format::Png, 114, 114);
16+
pub const APPLE_TOUCH_ICON_120: Preset<'static> =
17+
Preset::new("apple_touch_icon-120.png", Format::Png, 120, 120);
18+
pub const APPLE_TOUCH_ICON_144: Preset<'static> =
19+
Preset::new("apple_touch_icon-144.png", Format::Png, 144, 144);
20+
pub const APPLE_TOUCH_ICON_152: Preset<'static> =
21+
Preset::new("apple_touch_icon-152.png", Format::Png, 152, 152);
22+
23+
pub const FAVICON: Preset<'static> = Preset::new("favicon.ico", Format::Ico, 64, 64);
24+
pub const FAVICON_16: Preset<'static> = Preset::new("favicon-16.png", Format::Png, 16, 16);
25+
pub const FAVICON_32: Preset<'static> = Preset::new("favicon-32.png", Format::Png, 32, 32);
26+
pub const FAVICON_96: Preset<'static> = Preset::new("favicon-96.png", Format::Png, 96, 96);
27+
pub const FAVICON_128: Preset<'static> = Preset::new("favicon-128.png", Format::Png, 128, 128);
28+
pub const FAVICON_196: Preset<'static> = Preset::new("favicon-32.png", Format::Png, 196, 196);
29+
30+
pub const MS_TILE_70: Preset<'static> = Preset::new("mstile-70.png", Format::Png, 70, 70);
31+
pub const MS_TILE_144: Preset<'static> = Preset::new("mstile-144.png", Format::Png, 144, 144);
32+
pub const MS_TILE_150: Preset<'static> = Preset::new("mstile-150.png", Format::Png, 150, 150);
33+
pub const MS_TILE_310X150: Preset<'static> =
34+
Preset::new("mstile-310x150.png", Format::Png, 310, 150);
35+
pub const MS_TILE_310: Preset<'static> = Preset::new("mstile-310.png", Format::Png, 310, 310);
36+
37+
pub enum Format {
38+
Ico,
39+
Png,
40+
}
41+
42+
pub struct Preset<'a> {
43+
pub(crate) name: &'a str,
44+
pub(crate) format: Format,
45+
pub(crate) height: u32,
46+
pub(crate) width: u32,
47+
}
48+
49+
impl<'a> Preset<'a> {
50+
pub const fn new(name: &'a str, format: Format, height: u32, width: u32) -> Self {
51+
Self {
52+
name,
53+
format,
54+
height,
55+
width,
56+
}
57+
}
58+
}
59+
60+
pub struct Favicon<'a, P: AsRef<Path>> {
61+
pub(crate) image: DynamicImage,
62+
pub(crate) out_dir: P,
63+
pub(crate) presets: Vec<Preset<'a>>,
64+
}
65+
66+
impl<'a, P: AsRef<Path>> Favicon<'a, P> {
67+
pub fn new(file: P, out_dir: P, presets: Vec<Preset<'a>>) -> Self
68+
where
69+
P: AsRef<Path>,
70+
{
71+
let image = image::open(file).unwrap();
72+
73+
Self {
74+
image,
75+
out_dir,
76+
presets,
77+
}
78+
}
79+
80+
pub fn empty(file: P, out_dir: P) -> Self {
81+
let image = image::open(file).unwrap();
82+
83+
Self {
84+
image,
85+
out_dir,
86+
presets: Vec::default(),
87+
}
88+
}
89+
90+
pub fn scale_down(&self, preset: Preset<'a>) {
91+
let scaled = self
92+
.image
93+
.resize(preset.width, preset.height, FilterType::Nearest);
94+
let mut output = File::create(preset.name).unwrap();
95+
96+
scaled.write_to(&mut output, ImageFormat::Png).unwrap();
97+
}
98+
}
99+
100+
#[cfg(test)]
101+
mod tests {
102+
use super::*;
103+
104+
#[test]
105+
fn it_works() {
106+
let favicon = Favicon::empty("fixtures/dice.png", "output.png");
107+
108+
favicon.scale_down(APPLE_TOUCH_ICON_57);
109+
}
110+
}

0 commit comments

Comments
 (0)