///|
/// 配置对象的 JSON 序列化 / 反序列化,用于 CLI 与脚本持久化水印参数。
///
/// 注意:`seed`(Int64)与 `color`(Int)在 JSON 中表示为 Number;
/// Int64 超过 2^53 时会丢失精度(水印种子常规取值远小于该值,可忽略)。
///|
fn text_cfg_to_json(cfg : TextConfig) -> Json {
Json::object(
Map([
("text", Json::string(cfg.text)),
("x", Json::number(cfg.x.to_double())),
("y", Json::number(cfg.y.to_double())),
("font_size", Json::number(cfg.font_size.to_double())),
("opacity", Json::number(cfg.opacity)),
("angle", Json::number(cfg.angle)),
("color", Json::number(cfg.color.to_double())),
]),
)
}
///|
/// 将 `TextConfig` 序列化为 JSON 字符串。
pub fn text_config_to_json(cfg : TextConfig) -> String {
Json::stringify(text_cfg_to_json(cfg))
}
///|
/// 从 JSON 字符串解析 `TextConfig`;字段缺失或格式错误返回 `None`。
pub fn text_config_from_json(s : String) -> Option[TextConfig] {
try {
text_cfg_from_obj(@json.parse(s))
} catch {
_ => None
}
}
///|
fn text_cfg_from_obj(j : Json) -> Option[TextConfig] {
match j {
Object(m) => {
match (j_str(m, "text"), j_int(m, "x"), j_int(m, "y"), j_int(m, "font_size"), j_dbl(m, "opacity"), j_dbl(m, "angle"), j_int(m, "color")) {
(Some(text), Some(x), Some(y), Some(font_size), Some(opacity), Some(angle), Some(color)) =>
Some(
{
text: text,
x: x,
y: y,
font_size: font_size,
opacity: opacity,
angle: angle,
color: color,
},
)
_ => None
}
}
_ => None
}
}
///|
/// 将 `DotConfig` 序列化为 JSON 字符串。
pub fn dot_config_to_json(cfg : DotConfig) -> String {
Json::stringify(
Json::object(
Map([
("density", Json::number(cfg.density)),
("dot_size", Json::number(cfg.dot_size.to_double())),
("seed", Json::number(cfg.seed.to_double())),
("opacity", Json::number(cfg.opacity)),
("grid_offset_x", Json::number(cfg.grid_offset_x.to_double())),
("grid_offset_y", Json::number(cfg.grid_offset_y.to_double())),
]),
),
)
}
///|
/// 从 JSON 字符串解析 `DotConfig`;字段缺失或格式错误返回 `None`。
pub fn dot_config_from_json(s : String) -> Option[DotConfig] {
try {
dot_cfg_from_obj(@json.parse(s))
} catch {
_ => None
}
}
///|
fn dot_cfg_from_obj(j : Json) -> Option[DotConfig] {
match j {
Object(m) => {
match (j_dbl(m, "density"), j_int(m, "dot_size"), j_i64(m, "seed"), j_dbl(m, "opacity"), j_int(m, "grid_offset_x"), j_int(m, "grid_offset_y")) {
(Some(density), Some(dot_size), Some(seed), Some(opacity), Some(grid_offset_x), Some(grid_offset_y)) =>
Some(
{
density: density,
dot_size: dot_size,
seed: seed,
opacity: opacity,
grid_offset_x: grid_offset_x,
grid_offset_y: grid_offset_y,
},
)
_ => None
}
}
_ => None
}
}
///|
/// 将 `TiledConfig` 序列化为 JSON 字符串。
pub fn tiled_config_to_json(cfg : TiledConfig) -> String {
Json::stringify(
Json::object(
Map([
("text", Json::string(cfg.text)),
("font_size", Json::number(cfg.font_size.to_double())),
("spacing_x", Json::number(cfg.spacing_x.to_double())),
("spacing_y", Json::number(cfg.spacing_y.to_double())),
("opacity", Json::number(cfg.opacity)),
("color", Json::number(cfg.color.to_double())),
]),
),
)
}
///|
/// 从 JSON 字符串解析 `TiledConfig`;字段缺失或格式错误返回 `None`。
pub fn tiled_config_from_json(s : String) -> Option[TiledConfig] {
try {
tiled_cfg_from_obj(@json.parse(s))
} catch {
_ => None
}
}
///|
fn tiled_cfg_from_obj(j : Json) -> Option[TiledConfig] {
match j {
Object(m) => {
match (j_str(m, "text"), j_int(m, "font_size"), j_int(m, "spacing_x"), j_int(m, "spacing_y"), j_dbl(m, "opacity"), j_int(m, "color")) {
(Some(text), Some(font_size), Some(spacing_x), Some(spacing_y), Some(opacity), Some(color)) =>
Some(
{
text: text,
font_size: font_size,
spacing_x: spacing_x,
spacing_y: spacing_y,
opacity: opacity,
color: color,
},
)
_ => None
}
}
_ => None
}
}
///|
fn j_str(m : Map[String, Json], k : String) -> Option[String] {
match m.get(k) {
Some(j) => {
match j {
String(sv) => Some(sv)
_ => None
}
}
_ => None
}
}
///|
fn j_int(m : Map[String, Json], k : String) -> Option[Int] {
match m.get(k) {
Some(j) => {
match j {
Number(d, ..) => Some(d.to_int())
_ => None
}
}
_ => None
}
}
///|
fn j_dbl(m : Map[String, Json], k : String) -> Option[Double] {
match m.get(k) {
Some(j) => {
match j {
Number(d, ..) => Some(d)
_ => None
}
}
_ => None
}
}
///|
fn j_i64(m : Map[String, Json], k : String) -> Option[Int64] {
match m.get(k) {
Some(j) => {
match j {
Number(d, ..) => Some(d.to_int64())
_ => None
}
}
_ => None
}
}