mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
Merge pull request #62 from neocturne/webp
core, viewer: add support for WebP output
This commit is contained in:
commit
ec309dc15f
11 changed files with 232 additions and 20 deletions
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased] - ReleaseDate
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for rendering tiles WebP format using the `--image-format` option
|
||||
|
||||
## [2.3.1] - 2025-01-06
|
||||
|
||||
### Fixed
|
||||
|
|
177
Cargo.lock
generated
177
Cargo.lock
generated
|
@ -125,9 +125,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
|
@ -313,6 +313,16 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
|
@ -461,10 +471,21 @@ checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
|
|||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"image-webp",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.0"
|
||||
|
@ -546,9 +567,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "3d6ea2a48c204030ee31a7d7fc72c93294c92fe87ecb1789881c9543516e1a0d"
|
||||
dependencies = [
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
|
@ -800,6 +824,12 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
|
@ -850,7 +880,7 @@ version = "0.5.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -900,7 +930,7 @@ version = "0.38.43"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.7.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
@ -948,6 +978,15 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_fmt"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.135"
|
||||
|
@ -1009,10 +1048,88 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.95"
|
||||
name = "sval"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
||||
checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8"
|
||||
|
||||
[[package]]
|
||||
name = "sval_buffer"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f"
|
||||
dependencies = [
|
||||
"sval",
|
||||
"sval_ref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_dynamic"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4"
|
||||
dependencies = [
|
||||
"sval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_fmt"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"sval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_json"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"sval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_nested"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f"
|
||||
dependencies = [
|
||||
"sval",
|
||||
"sval_buffer",
|
||||
"sval_ref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_ref"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa"
|
||||
dependencies = [
|
||||
"sval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sval_serde"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"sval",
|
||||
"sval_nested",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1107,6 +1224,12 @@ dependencies = [
|
|||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
|
@ -1125,6 +1248,42 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
|
||||
dependencies = [
|
||||
"value-bag-serde1",
|
||||
"value-bag-sval2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag-serde1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
"serde_fmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag-sval2"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a"
|
||||
dependencies = [
|
||||
"sval",
|
||||
"sval_buffer",
|
||||
"sval_dynamic",
|
||||
"sval_fmt",
|
||||
"sval_json",
|
||||
"sval_ref",
|
||||
"sval_serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
@ -44,7 +44,7 @@ enum-map = "2.7.3"
|
|||
fastnbt = "2.3.2"
|
||||
futures-util = "0.3.28"
|
||||
git-version = "0.3.5"
|
||||
image = { version = "0.25.1", default-features = false, features = ["png"] }
|
||||
image = { version = "0.25.1", default-features = false, features = ["png", "webp"] }
|
||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||
lru = "0.12.0"
|
||||
minedmap-nbt = { version = "0.1.1", path = "crates/nbt", default-features = false }
|
||||
|
|
11
README.md
11
README.md
|
@ -55,9 +55,18 @@ a proper webserver like [nginx](https://nginx.org/) or upload the viewer togethe
|
|||
the generated map files to public webspace to make the map available to others.
|
||||
|
||||
If you are uploading the directory to a remote webserver, you do not need to upload the
|
||||
`<viewer>/data/processed` directory, as that is only used locally to allow processing
|
||||
`<viewer>/data/processed` directory, as it is only used locally to allow processing
|
||||
updates more quickly.
|
||||
|
||||
### Image formats
|
||||
|
||||
MinedMap renders map tiles as PNG by default. Pass `--image-format webp` to select
|
||||
WebP instead. For typical Minecraft worlds, using WebP reduces file sizes by 10-15%
|
||||
without increasing processing time.
|
||||
|
||||
MinedMap always uses lossless compression for tile images, regardless of the
|
||||
image format.
|
||||
|
||||
### Signs
|
||||
|
||||

|
||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::ValueEnum;
|
||||
use indexmap::IndexSet;
|
||||
use regex::{Regex, RegexSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -150,6 +151,8 @@ pub struct Config {
|
|||
pub viewer_info_path: PathBuf,
|
||||
/// Path of viewer entities file
|
||||
pub viewer_entities_path: PathBuf,
|
||||
/// Format of generated map tiles
|
||||
pub image_format: ImageFormat,
|
||||
/// Sign text filter patterns
|
||||
pub sign_patterns: RegexSet,
|
||||
/// Sign text transformation pattern
|
||||
|
@ -189,6 +192,7 @@ impl Config {
|
|||
entities_path_final,
|
||||
viewer_info_path,
|
||||
viewer_entities_path,
|
||||
image_format: args.image_format,
|
||||
sign_patterns,
|
||||
sign_transforms,
|
||||
})
|
||||
|
@ -264,14 +268,39 @@ impl Config {
|
|||
[&self.output_dir, Path::new(&dir)].iter().collect()
|
||||
}
|
||||
|
||||
/// Returns the file extension for the configured image format
|
||||
pub fn tile_extension(&self) -> &'static str {
|
||||
match self.image_format {
|
||||
ImageFormat::Png => "png",
|
||||
ImageFormat::Webp => "webp",
|
||||
}
|
||||
}
|
||||
/// Returns the configurured image format for the image library
|
||||
pub fn tile_image_format(&self) -> image::ImageFormat {
|
||||
match self.image_format {
|
||||
ImageFormat::Png => image::ImageFormat::Png,
|
||||
ImageFormat::Webp => image::ImageFormat::WebP,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs the path of an output tile image
|
||||
pub fn tile_path(&self, kind: TileKind, level: usize, coords: TileCoords) -> PathBuf {
|
||||
let filename = coord_filename(coords, "png");
|
||||
let filename = coord_filename(coords, self.tile_extension());
|
||||
let dir = self.tile_dir(kind, level);
|
||||
[Path::new(&dir), Path::new(&filename)].iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Format of generated map tiles
|
||||
#[derive(Debug, Clone, Copy, Default, ValueEnum)]
|
||||
pub enum ImageFormat {
|
||||
/// Generate PNG images
|
||||
#[default]
|
||||
Png,
|
||||
/// Generate WebP images
|
||||
Webp,
|
||||
}
|
||||
|
||||
/// Copies a chunk image into a region tile
|
||||
pub fn overlay_chunk<I, J>(image: &mut I, chunk: &J, coords: ChunkCoords)
|
||||
where
|
||||
|
|
|
@ -61,6 +61,8 @@ struct Metadata<'t> {
|
|||
spawn: Spawn,
|
||||
/// Enabled MinedMap features
|
||||
features: Features,
|
||||
/// Format of generated map tiles
|
||||
tile_extension: &'static str,
|
||||
}
|
||||
|
||||
/// Viewer entity JSON data structure
|
||||
|
@ -205,6 +207,7 @@ impl<'a> MetadataWriter<'a> {
|
|||
mipmaps: Vec::new(),
|
||||
spawn: Self::spawn(&level_dat),
|
||||
features,
|
||||
tile_extension: self.config.tile_extension(),
|
||||
};
|
||||
|
||||
for tile_map in self.tiles.iter() {
|
||||
|
|
|
@ -16,7 +16,7 @@ use anyhow::{Context, Result};
|
|||
use clap::Parser;
|
||||
use git_version::git_version;
|
||||
|
||||
use common::Config;
|
||||
use common::{Config, ImageFormat};
|
||||
use metadata_writer::MetadataWriter;
|
||||
use region_processor::RegionProcessor;
|
||||
use tile_mipmapper::TileMipmapper;
|
||||
|
@ -47,6 +47,9 @@ pub struct Args {
|
|||
/// Enable verbose messages
|
||||
#[arg(short, long)]
|
||||
pub verbose: bool,
|
||||
/// Format of generated map tiles
|
||||
#[arg(long, value_enum, default_value_t)]
|
||||
pub image_format: ImageFormat,
|
||||
/// Prefix for text of signs to show on the map
|
||||
#[arg(long)]
|
||||
pub sign_prefix: Vec<String>,
|
||||
|
|
|
@ -79,6 +79,8 @@ struct SingleRegionProcessor<'a> {
|
|||
lightmap: image::GrayAlphaImage,
|
||||
/// Processed entity intermediate data
|
||||
entities: ProcessedEntities,
|
||||
/// Format of generated map tiles
|
||||
image_format: image::ImageFormat,
|
||||
/// True if any unknown block or biome types were encountered during processing
|
||||
has_unknown: bool,
|
||||
}
|
||||
|
@ -127,6 +129,7 @@ impl<'a> SingleRegionProcessor<'a> {
|
|||
processed_region,
|
||||
lightmap,
|
||||
entities,
|
||||
image_format: processor.config.tile_image_format(),
|
||||
has_unknown: false,
|
||||
})
|
||||
}
|
||||
|
@ -179,7 +182,7 @@ impl<'a> SingleRegionProcessor<'a> {
|
|||
self.input_timestamp,
|
||||
|file| {
|
||||
self.lightmap
|
||||
.write_to(file, image::ImageFormat::Png)
|
||||
.write_to(file, self.image_format)
|
||||
.context("Failed to save image")
|
||||
},
|
||||
)
|
||||
|
|
|
@ -144,7 +144,7 @@ where
|
|||
}
|
||||
|
||||
image
|
||||
.write_to(file, image::ImageFormat::Png)
|
||||
.write_to(file, self.config.tile_image_format())
|
||||
.context("Failed to save image")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ impl<'a> TileRenderer<'a> {
|
|||
processed_timestamp,
|
||||
|file| {
|
||||
image
|
||||
.write_to(file, image::ImageFormat::Png)
|
||||
.write_to(file, self.config.tile_image_format())
|
||||
.context("Failed to save image")
|
||||
},
|
||||
)?;
|
||||
|
|
|
@ -73,7 +73,7 @@ function signIcon(material, kind) {
|
|||
}
|
||||
|
||||
const MinedMapLayer = L.TileLayer.extend({
|
||||
initialize: function (mipmaps, layer) {
|
||||
initialize: function (mipmaps, layer, tile_extension) {
|
||||
L.TileLayer.prototype.initialize.call(this, '', {
|
||||
detectRetina: true,
|
||||
tileSize: 512,
|
||||
|
@ -88,6 +88,7 @@ const MinedMapLayer = L.TileLayer.extend({
|
|||
|
||||
this.mipmaps = mipmaps;
|
||||
this.layer = layer;
|
||||
this.ext = tile_extension;
|
||||
},
|
||||
|
||||
createTile: function (coords, done) {
|
||||
|
@ -112,7 +113,7 @@ const MinedMapLayer = L.TileLayer.extend({
|
|||
return L.Util.emptyImageUrl;
|
||||
|
||||
|
||||
return 'data/'+this.layer+'/'+z+'/r.'+coords.x+'.'+coords.y+'.png';
|
||||
return `data/${this.layer}/${z}/r.${coords.x}.${coords.y}.${this.ext}`;
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -332,6 +333,7 @@ window.createMap = function () {
|
|||
const res = await response.json();
|
||||
const {mipmaps, spawn} = res;
|
||||
const features = res.features || {};
|
||||
const tile_extension = res.tile_extension || 'png';
|
||||
|
||||
const updateParams = function () {
|
||||
const args = parseHash();
|
||||
|
@ -369,10 +371,10 @@ window.createMap = function () {
|
|||
|
||||
const overlayMaps = {};
|
||||
|
||||
const mapLayer = new MinedMapLayer(mipmaps, 'map');
|
||||
const mapLayer = new MinedMapLayer(mipmaps, 'map', tile_extension);
|
||||
mapLayer.addTo(map);
|
||||
|
||||
const lightLayer = new MinedMapLayer(mipmaps, 'light');
|
||||
const lightLayer = new MinedMapLayer(mipmaps, 'light', tile_extension);
|
||||
overlayMaps['Illumination'] = lightLayer;
|
||||
if (params.light)
|
||||
map.addLayer(lightLayer);
|
||||
|
|
Loading…
Add table
Reference in a new issue