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

【pdf-rs】color.rs 文件解析

color.rs 文件是一个用于PDF处理的颜色空间管理模块,主要实现了PDF标准中定义的各种颜色空间。内容如下:

use datasize::DataSize;
use crate as pdf;
use crate::object::*;
use crate::error::*;#[derive(Object, Debug, DataSize, DeepClone, ObjectWrite)]
pub struct IccInfo {#[pdf(key="N")]pub components: u32,#[pdf(key="Alternate")]pub alternate: Option<Box<ColorSpace>>,#[pdf(key="Range")]pub range: Option<Vec<f32>>,#[pdf(key="Metadata")]pub metadata: Option<Stream<()>>,
}#[derive(Debug, Clone, DeepClone)]
pub enum ColorSpace {DeviceGray,DeviceRGB,DeviceCMYK,DeviceN { names: Vec<Name>, alt: Box<ColorSpace>, tint: Function, attr: Option<Dictionary> },CalGray(Dictionary),CalRGB(Dictionary),CalCMYK(Dictionary),Indexed(Box<ColorSpace>, u8, Arc<[u8]>),Separation(Name, Box<ColorSpace>, Function),Icc(RcRef<Stream<IccInfo>>),Pattern,Named(Name),Other(Vec<Primitive>)
}
impl DataSize for ColorSpace {const IS_DYNAMIC: bool = true;const STATIC_HEAP_SIZE: usize = 0;#[inline]fn estimate_heap_size(&self) -> usize {match *self {ColorSpace::DeviceGray | ColorSpace::DeviceRGB | ColorSpace::DeviceCMYK => 0,ColorSpace::DeviceN { ref names, ref alt, ref tint, ref attr } => {names.estimate_heap_size() +alt.estimate_heap_size() +tint.estimate_heap_size() +attr.estimate_heap_size()}ColorSpace::CalGray(ref d) | ColorSpace::CalRGB(ref d) | ColorSpace::CalCMYK(ref d) => {d.estimate_heap_size()}ColorSpace::Indexed(ref cs, _, ref data) => {cs.estimate_heap_size() + data.estimate_heap_size()}ColorSpace::Separation(ref name, ref cs, ref f) => {name.estimate_heap_size() + cs.estimate_heap_size() + f.estimate_heap_size()}ColorSpace::Icc(ref s) => s.estimate_heap_size(),ColorSpace::Pattern => 0,ColorSpace::Other(ref v) => v.estimate_heap_size(),ColorSpace::Named(ref n) => n.estimate_heap_size()}}
}fn get_index(arr: &[Primitive], idx: usize) -> Result<&Primitive> {arr.get(idx).ok_or(PdfError::Bounds { index: idx, len: arr.len() })
}impl Object for ColorSpace {fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<ColorSpace> {ColorSpace::from_primitive_depth(p, resolve, 5)}
}
impl ColorSpace {fn from_primitive_depth(p: Primitive, resolve: &impl Resolve, depth: usize) -> Result<ColorSpace> {let p = p.resolve(resolve)?;if let Ok(name) = p.as_name() {let cs = match name {"DeviceGray" => ColorSpace::DeviceGray,"DeviceRGB" => ColorSpace::DeviceRGB,"DeviceCMYK" => ColorSpace::DeviceCMYK,"Pattern" => ColorSpace::Pattern,name => ColorSpace::Named(name.into()),};return Ok(cs);}let arr = t!(p.into_array());let typ_p = t!(get_index(&arr, 0)).clone().resolve(resolve)?;let typ = t!(typ_p.as_name());if depth == 0 {bail!("ColorSpace base recursion");}match typ {"Indexed" => {let base = Box::new(t!(ColorSpace::from_primitive_depth(t!(get_index(&arr, 1)).clone(), resolve, depth-1)));let hival = t!(t!(get_index(&arr, 2)).as_u8());let lookup = match t!(get_index(&arr, 3)) {&Primitive::Reference(r) => resolve.resolve(r)?,p => p.clone()};let lookup = match lookup {Primitive::String(string) => {let data: Vec<u8> = string.into_bytes().into();data.into()}Primitive::Stream(stream) => {let s: Stream::<()> = Stream::from_stream(stream, resolve)?;t!(s.data(resolve))},p => return Err(PdfError::UnexpectedPrimitive {expected: "String or Stream",found: p.get_debug_name()})};Ok(ColorSpace::Indexed(base, hival, lookup))}"Separation" => {let name = t!(t!(get_index(&arr, 1)).clone().into_name());let alternate = Box::new(t!(ColorSpace::from_primitive_depth(t!(get_index(&arr, 2)).clone(), resolve, depth-1)));let tint = t!(Function::from_primitive(t!(get_index(&arr, 3)).clone(), resolve));Ok(ColorSpace::Separation(name, alternate, tint))}"ICCBased" => {let s = t!(RcRef::from_primitive(t!(get_index(&arr, 1)).clone(), resolve));Ok(ColorSpace::Icc(s))}"DeviceN" => {let names = t!(Object::from_primitive(t!(get_index(&arr, 1)).clone(), resolve));let alt = t!(Object::from_primitive(t!(get_index(&arr, 2)).clone(), resolve));let tint = t!(Function::from_primitive(t!(get_index(&arr, 3)).clone(), resolve));let attr = arr.get(4).map(|p| Dictionary::from_primitive(p.clone(), resolve)).transpose()?;Ok(ColorSpace::DeviceN { names, alt, tint, attr})}"CalGray" => {let dict = Dictionary::from_primitive(t!(get_index(&arr, 1)).clone(), resolve)?;Ok(ColorSpace::CalGray(dict))}"CalRGB" => {let dict = Dictionary::from_primitive(t!(get_index(&arr, 1)).clone(), resolve)?;Ok(ColorSpace::CalRGB(dict))}"CalCMYK" => {let dict = Dictionary::from_primitive(t!(get_index(&arr, 1)).clone(), resolve)?;Ok(ColorSpace::CalCMYK(dict))}"Pattern" => {Ok(ColorSpace::Pattern)}_ => Ok(ColorSpace::Other(arr))}}
}
impl ObjectWrite for ColorSpace {fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {match *self {ColorSpace::DeviceCMYK => Ok(Primitive::name("DeviceCMYK")),ColorSpace::DeviceRGB => Ok(Primitive::name("DeviceRGB")),ColorSpace::Indexed(ref  base, hival, ref lookup) => {let base = base.to_primitive(update)?;let hival = Primitive::Integer(hival.into());let lookup = if lookup.len() < 100 {PdfString::new((**lookup).into()).into()} else {Stream::new((), lookup.clone()).to_primitive(update)?};Ok(Primitive::Array(vec![Primitive::name("Indexed"), base, hival, lookup]))}ref p => {dbg!(p);unimplemented!()}}}
}

主要结构

IccInfo 结构体

#[derive(Object, Debug, DataSize, DeepClone, ObjectWrite)]
pub struct IccInfo {#[pdf(key="N")]pub components: u32,#[pdf(key="Alternate")]pub alternate: Option<Box<ColorSpace>>,#[pdf(key="Range")]pub range: Option<Vec<f32>>,#[pdf(key="Metadata")]pub metadata: Option<Stream<()>>,
}

功能:

  • 存储ICC颜色配置文件的元信息
  • 支持PDF对象序列化/反序列化
  • 包含组件数量、备用颜色空间、数值范围和元数据

ColorSpace 枚举

#[derive(Debug, Clone, DeepClone)]
pub enum ColorSpace {DeviceGray,DeviceRGB,DeviceCMYK,DeviceN { names: Vec<Name>, alt: Box<ColorSpace>, tint: Function, attr: Option<Dictionary> },CalGray(Dictionary),CalRGB(Dictionary),CalCMYK(Dictionary),Indexed(Box<ColorSpace>, u8, Arc<[u8]>),Separation(Name, Box<ColorSpace>, Function),Icc(RcRef<Stream<IccInfo>>),Pattern,Named(Name),Other(Vec<Primitive>)
}

颜色空间类型详解

设备颜色空间

  • DeviceGray - 设备灰度空间
  • DeviceRGB - 设备RGB颜色空间
  • DeviceCMYK - 设备CMYK颜色空间

特殊颜色空间

  • DeviceN - 多组件设备颜色空间

    • names: 颜色组件名称
    • alt: 备用颜色空间
    • tint: 色调变换函数
    • attr: 附加属性
  • Indexed - 索引颜色空间

    • 基础颜色空间
    • 最大索引值(hival)
    • 颜色查找表数据
  • Separation - 专色分离

    • 颜色名称
    • 备用颜色空间
    • 色调变换函数

基于标准的颜色空间

  • CalGray - 校准灰度空间(带校准字典)
  • CalRGB - 校准RGB空间(带校准字典)
  • CalCMYK - 校准CMYK空间(带校准字典)

其他类型

  • Icc - ICC基于的颜色空间
  • Pattern - 图案颜色空间
  • Named - 命名颜色空间
  • Other - 其他未实现类型

核心功能实现

内存大小估算

impl DataSize for ColorSpace {const IS_DYNAMIC: bool = true;const STATIC_HEAP_SIZE: usize = 0;fn estimate_heap_size(&self) -> usize {// 为每种变体递归估算堆内存使用match *self {ColorSpace::DeviceGray | ColorSpace::DeviceRGB | ColorSpace::DeviceCMYK => 0,ColorSpace::DeviceN { ref names, ref alt, ref tint, ref attr } => {names.estimate_heap_size() +alt.estimate_heap_size() +tint.estimate_heap_size() +attr.estimate_heap_size()}// ... 其他变体的内存估算}}
}

PDF对象解析

impl Object for ColorSpace {fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<ColorSpace> {ColorSpace::from_primitive_depth(p, resolve, 5)}
}

解析特性:

  • 递归解析,最大深度为5层防止无限递归
  • 支持从名称或数组格式解析颜色空间
  • 处理索引颜色空间的查找表数据(字符串或流格式)

主要解析逻辑

  1. 名称解析:直接映射标准颜色空间名称
  2. 数组解析:根据第一个元素识别颜色空间类型
  3. 递归处理:处理嵌套的颜色空间定义
  4. 错误处理:完善的边界检查和错误类型

序列化支持

impl ObjectWrite for ColorSpace {fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {match *self {ColorSpace::DeviceCMYK => Ok(Primitive::name("DeviceCMYK")),ColorSpace::DeviceRGB => Ok(Primitive::name("DeviceRGB")),ColorSpace::Indexed(ref base, hival, ref lookup) => {// 将索引颜色空间转换为PDF数组格式let base = base.to_primitive(update)?;let hival = Primitive::Integer(hival.into());let lookup = if lookup.len() < 100 {PdfString::new((**lookup).into()).into()} else {Stream::new((), lookup.clone()).to_primitive(update)?};Ok(Primitive::Array(vec![Primitive::name("Indexed"), base, hival, lookup]))}// ... 其他变体的序列化}}
}

设计特点

  1. 完整的PDF标准支持:实现了PDF规范中定义的所有颜色空间类型
  2. 递归解析:支持嵌套颜色空间定义
  3. 内存管理:集成 datasize 用于内存使用统计
  4. 错误处理:详细的错误信息和边界检查
  5. 序列化支持:支持将颜色空间写回PDF格式
  6. 灵活性:通过 Other 变体支持未明确实现的颜色空间

该模块是一个完整的PDF颜色空间处理系统,专注于PDF文件的解析和生成,是PDF标准的完整实现。

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

相关文章:

  • 网站后台的功能手机触屏网站开发
  • 盐城建设网站国外优秀购物网站设计
  • ARP 欺骗深度解析:从原理到防御的全方位拆解
  • 7-1 最大子列和问题
  • day23_密码加密 前端验证码 监听器 svn版本控制
  • 做的网站不能放视频播放器wordpress清空数据
  • 【Microsoft Learn】Microsoft Azure 服务
  • MacCalendar:专为 Mac 用户打造的高效日历工具
  • 第10章:中断处理-6:Implementing a Handler
  • 伊利网站建设评价多少钱?
  • Spring集成Mybatis-Plus(适用于非Springboot项目)
  • 做网站需要服务器么wordpress弹幕播放器
  • uni-app 请求封装
  • Less-7 GET-Dump into outfile-String
  • Windows系统暂停强制更新的操作(超详细说明)
  • Leetcode 43
  • 力扣每日一题——接雨水
  • 基于AWS Lambda事件驱动架构与S3智能生命周期管理的制造数据自动化处理方案
  • 营商环境建设网站建设公司网站的必要性
  • 小网站广告投放网站做支付需要准备什么东西吗
  • 第六届“大湾区杯”粤港澳金融数学建模竞赛赛题浅析-助攻快速选题
  • 【车载Android】使用自定义插件实现多语言自动化适配
  • 学习网站建设要什么学历网站颜色表
  • C++ 分治 归并排序解决问题 力扣 315. 计算右侧小于当前元素的个数 题解 每日一题
  • Linux UdpSocket的应用
  • docker compose 创建MySQL8后在容器里备份数据到宿主机(.sql文件)的方式
  • 南昌网站外包几何图形生成网站
  • 《算法通关指南:数据结构和算法篇 --- 顺序表相关算法题》--- 询问学号,寄包柜,合并两个有序数组
  • OS_3 Memory、4 File、5 IO
  • Jenkins vs Tekton vs Arbess,CI/CD工具一文纵评