当前位置: 首页 > news >正文

【printpdf】color.rs 文件解析

color.rs 文件定义了一个颜色处理模块,用于在PDF生成和处理中管理不同的颜色空间和颜色类型。源码如下:

use serde_derive::{Deserialize, Serialize};use crate::IccProfileId;/// Color space (enum for marking the number of bits a color has)
#[derive(Debug, Copy, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ColorSpace {Rgb,Rgba,Palette,Cmyk,Greyscale,GreyscaleAlpha,
}impl ColorSpace {pub fn as_string(&self) -> &'static str {use self::ColorSpace::*;match self {Rgb => "DeviceRGB",Cmyk => "DeviceCMYK",Greyscale => "DeviceGray",Palette => "Indexed",Rgba | GreyscaleAlpha => "DeviceN",}}
}impl From<image::ColorType> for ColorSpace {fn from(color_type: image::ColorType) -> Self {use image::ColorType::*;match color_type {L8 | L16 => ColorSpace::Greyscale,La8 | La16 => ColorSpace::GreyscaleAlpha,Rgb8 | Rgb16 => ColorSpace::Rgb,Rgba8 | Rgba16 => ColorSpace::Rgba,_ => ColorSpace::Greyscale, // unreachable}}
}/// How many bits does a color have?
#[derive(Debug, Copy, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ColorBits {Bit1,Bit8,Bit16,
}impl ColorBits {pub fn as_integer(&self) -> i64 {match self {ColorBits::Bit1 => 1,ColorBits::Bit8 => 8,ColorBits::Bit16 => 16,}}
}/// Wrapper for Rgb, Cmyk and other color types. Note: ALL color values are normalized from 0.0 to
/// 1.0 NOT 0 - 255!
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", tag = "type", content = "data")]
pub enum Color {/// RGB color, normalized from 0.0 to 1.0Rgb(Rgb),/// CMYK color, normalized from 0.0 to 1.0Cmyk(Cmyk),/// Greyscale color, normalized from 0.0 to 1.0Greyscale(Greyscale),/// (unimplemented) Spot color, currently encoded as CMYK, normalized from 0.0 to 1.0SpotColor(SpotColor),
}impl Color {/// Returns true if color is not in 0.0 - 1.0 rangepub fn is_out_of_range(&self) -> bool {match self {Color::Rgb(rgb) => rgb.is_out_of_range(),Color::Cmyk(cmyk) => cmyk.is_out_of_range(),Color::Greyscale(greyscale) => greyscale.is_out_of_range(),Color::SpotColor(spot_color) => spot_color.is_out_of_range(),}}/// Consumes the color and converts into into a vector of numberspub fn into_vec(&self) -> Vec<f32> {match self {Color::Rgb(rgb) => {vec![rgb.r, rgb.g, rgb.b]}Color::Cmyk(cmyk) => {vec![cmyk.c, cmyk.m, cmyk.y, cmyk.k]}Color::Greyscale(gs) => {vec![gs.percent]}Color::SpotColor(spot) => {vec![spot.c, spot.m, spot.y, spot.k]}}}pub fn get_svg_id(&self) -> String {match self {Color::Rgb(rgb) => {let r = (rgb.r * 255.0).round() as u8;let g = (rgb.g * 255.0).round() as u8;let b = (rgb.b * 255.0).round() as u8;format!("rgb({}, {}, {})", r, g, b)}Color::Cmyk(cmyk) => {let r = (1.0 - cmyk.c) * (1.0 - cmyk.k);let g = (1.0 - cmyk.m) * (1.0 - cmyk.k);let b = (1.0 - cmyk.y) * (1.0 - cmyk.k);let r = (r * 255.0).round() as u8;let g = (g * 255.0).round() as u8;let b = (b * 255.0).round() as u8;format!("rgb({}, {}, {})", r, g, b)}Color::Greyscale(gs) => {let gray = (gs.percent * 255.0).round() as u8;format!("rgb({}, {}, {})", gray, gray, gray)}Color::SpotColor(spot) => {// SpotColor is treated the same as CMYK.let r = (1.0 - spot.c) * (1.0 - spot.k);let g = (1.0 - spot.m) * (1.0 - spot.k);let b = (1.0 - spot.y) * (1.0 - spot.k);let r = (r * 255.0).round() as u8;let g = (g * 255.0).round() as u8;let b = (b * 255.0).round() as u8;format!("rgb({}, {}, {})", r, g, b)}}}/// Returns if the color has an icc profile attachedpub fn get_icc_profile(&self) -> Option<&Option<IccProfileId>> {match *self {Color::Rgb(ref rgb) => Some(&rgb.icc_profile),Color::Cmyk(ref cmyk) => Some(&cmyk.icc_profile),Color::Greyscale(ref gs) => Some(&gs.icc_profile),Color::SpotColor(_) => None,}}
}/// RGB color
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Rgb {/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub r: f32,/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub g: f32,/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub b: f32,#[serde(default, skip_serializing_if = "Option::is_none")]pub icc_profile: Option<IccProfileId>,
}impl Rgb {/// Creates a new RGB color, NOTE: RGB has to be 0.0 - 1.0, not 0 - 255!pub fn new(r: f32, g: f32, b: f32, icc_profile: Option<IccProfileId>) -> Self {Self {r,g,b,icc_profile,}}/// Checks whether the color will be out of range (0.0 - 1.0)/// and lead to errors in the PDF encodingpub fn is_out_of_range(&self) -> bool {self.r < 0.0 || self.r > 1.0 || self.g < 0.0 || self.g > 1.0 || self.b < 0.0 || self.b > 1.0}
}/// CMYK color
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Cmyk {/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub c: f32,/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub m: f32,/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub y: f32,/// Note: This has to be 0.0 - 1.0, not 0 - 255!pub k: f32,#[serde(default, skip_serializing_if = "Option::is_none")]pub icc_profile: Option<IccProfileId>,
}impl Cmyk {/// Creates a new CMYK color, NOTE: CMYK has to be 0.0 - 1.0, not 0 - 255!pub fn new(c: f32, m: f32, y: f32, k: f32, icc_profile: Option<IccProfileId>) -> Self {Self {c,m,y,k,icc_profile,}}/// Checks whether the color will be out of range (0.0 - 1.0)/// and lead to errors in the PDF encodingpub fn is_out_of_range(&self) -> bool {self.c < 0.0|| self.c > 1.0|| self.m < 0.0|| self.m > 1.0|| self.y < 0.0|| self.y > 1.0|| self.k < 0.0|| self.k > 1.0}
}/// Greyscale color
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Greyscale {pub percent: f32,#[serde(default, skip_serializing_if = "Option::is_none")]pub icc_profile: Option<IccProfileId>,
}impl Greyscale {/// Creates a new Greyscale color, NOTE: Greyscale has to be 0.0 - 1.0, not 0 - 255!pub fn new(percent: f32, icc_profile: Option<IccProfileId>) -> Self {Self {percent,icc_profile,}}/// Checks whether the color will be out of range (0.0 - 1.0)/// and lead to errors in the PDF encodingpub fn is_out_of_range(&self) -> bool {self.percent < 0.0 || self.percent > 1.0}
}/// Spot colors are like Cmyk, but without color space. They are essentially "named" colors
/// from specific vendors - currently they are the same as a CMYK color.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpotColor {pub c: f32,pub m: f32,pub y: f32,pub k: f32,
}impl SpotColor {/// Creates a new SpotColor, NOTE: SpotColor has to be 0.0 - 1.0, not 0 - 255!pub fn new(c: f32, m: f32, y: f32, k: f32) -> Self {Self { c, m, y, k }}/// Checks whether the color will be out of range (0.0 - 1.0)/// and lead to errors in the PDF encodingpub fn is_out_of_range(&self) -> bool {self.c < 0.0|| self.c > 1.0|| self.m < 0.0|| self.m > 1.0|| self.y < 0.0|| self.y > 1.0|| self.k < 0.0|| self.k > 1.0}
}/// Type of the icc profile
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IccProfileType {Cmyk,Rgb,Greyscale,
}/// Icc profile
#[derive(Debug, Clone, PartialEq)]
pub struct IccProfile {/// Binary Icc profilepub icc: Vec<u8>,/// CMYK or RGB or LAB icc profile?pub icc_type: IccProfileType,/// Does the ICC profile have an "Alternate" version or not?pub has_alternate: bool,/// Does the ICC profile have an "Range" dictionary/// Really not sure why this is needed, but this is needed on the documents Info dictionarypub has_range: bool,
}impl IccProfile {/// Creates a new Icc Profilepub fn new(icc: Vec<u8>, icc_type: IccProfileType) -> Self {Self {icc,icc_type,has_alternate: true,has_range: false,}}/// Does the ICC profile have an alternate version (such as "DeviceCMYk")?#[inline]pub fn with_alternate_profile(mut self, has_alternate: bool) -> Self {self.has_alternate = has_alternate;self}/// Does the ICC profile have an "Range" dictionary?#[inline]pub fn with_range(mut self, has_range: bool) -> Self {self.has_range = has_range;self}
}

主要枚举和结构体

ColorSpace 枚举

/// 颜色空间(用于标记颜色位数的枚举)
#[derive(Debug, Copy, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ColorSpace {Rgb,Rgba,Palette,Cmyk,Greyscale,GreyscaleAlpha,
}

功能:

  • 定义不同的颜色空间类型
  • 支持序列化/反序列化,使用kebab-case命名
  • 提供 as_string() 方法返回对应的设备颜色空间名称

从 image::ColorType 转换:

  • image crate 的颜色类型映射到本地的颜色空间

ColorBits 枚举

/// 颜色位数定义
#[derive(Debug, Copy, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ColorBits {Bit1,Bit8,Bit16,
}

功能:

  • 定义颜色的位深度
  • 提供 as_integer() 方法返回对应的整数值

Color 枚举

/// RGB、CMYK和其他颜色类型的包装器
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", tag = "type", content = "data")]
pub enum Color {/// RGB 颜色,归一化到 0.0 - 1.0Rgb(Rgb),/// CMYK 颜色,归一化到 0.0 - 1.0Cmyk(Cmyk),/// 灰度颜色,归一化到 0.0 - 1.0Greyscale(Greyscale),/// (未实现)专色,目前编码为CMYK,归一化到 0.0 - 1.0SpotColor(SpotColor),
}

重要特性:

  • 所有颜色值都归一化到 0.0 - 1.0,而不是 0-255!
  • 使用 tagged union 序列化格式

主要方法:

  • is_out_of_range() - 检查颜色值是否超出有效范围
  • into_vec() - 将颜色转换为数值向量
  • get_svg_id() - 生成SVG格式的颜色标识符
  • get_icc_profile() - 获取关联的ICC配置文件

具体颜色类型

Rgb 结构体

/// RGB 颜色
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Rgb {pub r: f32,  // 0.0 - 1.0pub g: f32,  // 0.0 - 1.0pub b: f32,  // 0.0 - 1.0pub icc_profile: Option<IccProfileId>,
}

Cmyk 结构体

/// CMYK 颜色
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Cmyk {pub c: f32,  // 0.0 - 1.0pub m: f32,  // 0.0 - 1.0pub y: f32,  // 0.0 - 1.0pub k: f32,  // 0.0 - 1.0pub icc_profile: Option<IccProfileId>,
}

Greyscale 结构体

/// 灰度颜色
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Greyscale {pub percent: f32,  // 0.0 - 1.0pub icc_profile: Option<IccProfileId>,
}

SpotColor 结构体

/// 专色类似于CMYK,但没有颜色空间
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpotColor {pub c: f32,pub m: f32,pub y: f32,pub k: f32,
}

ICC 配置文件支持

IccProfileType 枚举

/// ICC 配置文件类型
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IccProfileType {Cmyk,Rgb,Greyscale,
}

IccProfile 结构体

/// ICC 配置文件
#[derive(Debug, Clone, PartialEq)]
pub struct IccProfile {pub icc: Vec<u8>,           // 二进制ICC配置文件pub icc_type: IccProfileType, // 配置文件类型pub has_alternate: bool,    // 是否有"Alternate"版本pub has_range: bool,        // 是否有"Range"字典
}

设计特点

  1. 归一化值:所有颜色值都使用 0.0-1.0 的浮点数范围
  2. 序列化支持:完整的 serde 支持,便于配置和存储
  3. 范围验证:提供颜色值范围检查,防止PDF编码错误
  4. ICC支持:支持颜色配置文件管理
  5. SVG兼容:提供SVG颜色格式输出
  6. 图像库集成:与 image crate 的颜色类型转换

该模块为PDF生成提供了完整的颜色管理系统,支持多种颜色空间和专业的颜色管理功能。

http://www.dtcms.com/a/557161.html

相关文章:

  • Langchain4j 实战 【AI代码生成平台】:接入deepseek,开发AI服务并实现结构化输出
  • DNR6521x_VC1:革新音频体验的AI降噪处理器
  • 长沙做网站的公司哪家最好永久有效的代理ip
  • 技术准备九:FFmpeg
  • Jenkins 实战4:集群配置与分布式构建
  • 一人开公司做网站创业企业网站建设总结报告
  • android 15.0 app应用安装黑名单
  • N-158基于微信小程序学生社团管理系统
  • LeetCode算法日记 - Day 89: 最长递增子序列
  • 两学一做 网站帮别人建网站赚钱吗
  • 2025江苏省职业院校技能大赛网络系统管理赛项模块A:网络构建卷I(未公开)
  • 鸿蒙工程结构、开发指南
  • Python为什么能成为Ubuntu官方支持的脚本语言?
  • Studio Drummer 深度指南:从采样逻辑到风格化创作的实战手册
  • 一个专门做试题的网站商品seo关键词优化
  • 汽车ECU测试中边界值方法
  • 微信小程序开发工具软件网络优化策划书
  • 【GSR】皮肤电反应 数据分析全流程教程
  • 现代Python开发环境搭建(VSCode + Dev Containers)
  • 网站模版如何使用个人网站经营性备案查询
  • 理解计算机系统_程序计数器PC的实现
  • 在Unity中运行Yolo推理
  • php+redis基本操作及操作说明
  • 神经网络补充知识
  • 怎么在网站后台删除图片vps搭建网站教程
  • MySQL主从数据一致性校验工具:pt-table-checksum 详解
  • 源码分享:AI照片风格化小程序
  • 哪些行业做网站的多如何做二级域名子目录网站
  • jQuery Mobile 面板
  • Vulfocus---shiro反序列化漏洞