Skip to main content

csp_format/
lib.rs

1//! Read, verify and write CLIP STUDIO PAINT files (.clip / .cmc).
2//!
3//! The format is not published; everything here was learnt from real files
4//! and is written down in the repository's `docs/spec/`. Input files are
5//! never modified: files are read into memory, and changes are written only
6//! by an explicit save. This crate is not made or endorsed by CELSYS.
7//!
8//! # Reading
9//!
10//! [`ClipFile`] opens a .clip: the canvas settings, the layer tree, every
11//! table of the embedded SQLite database, and the pixels, vectors and texts
12//! of the layers. [`CmcFile`] opens a .cmc (a multi-page work) and lists its
13//! pages in reading order.
14//!
15//! ```no_run
16//! use csp_format::{ClipFile, CmcFile};
17//!
18//! let file = ClipFile::open("page0001.clip")?;
19//! for (layer, depth) in file.layers.flatten() {
20//!     println!("{}{} ({})", "  ".repeat(depth), layer.name, layer.kind.name());
21//!     if let Some((image, (x, y))) = file.layer_pixels(layer)? {
22//!         println!("  {}x{} px at ({x}, {y})", image.width, image.height);
23//!     }
24//! }
25//!
26//! let work = CmcFile::open("work.cmc")?;
27//! for path in work.page_paths(std::path::Path::new("."))? {
28//!     println!("{}", path.display());
29//! }
30//! # Ok::<(), csp_format::Error>(())
31//! ```
32//!
33//! # Writing
34//!
35//! A file saved without changes is byte-identical to the input. Changes go
36//! through [`ClipFile`]'s methods ([`edit`]) or straight into its database;
37//! new canvases and works are made with [`NewCanvas`] and [`NewWork`].
38//!
39//! ```
40//! use csp_format::{ClipFile, LayerKind, NewCanvas, RgbaImage};
41//!
42//! let mut file = ClipFile::create(&NewCanvas { width: 640, height: 480, ..NewCanvas::default() })?;
43//! let mut image = RgbaImage::new(64, 64);
44//! image.fill([200, 30, 30, 255]);
45//! let id = file.add_raster_layer("red square", &image, (10, 20))?;
46//! file.set_layer_opacity(id, 0.5)?;
47//!
48//! let reopened = ClipFile::from_bytes(file.to_bytes()?)?;
49//! let layer = reopened.layers.get(id).unwrap();
50//! assert_eq!(layer.kind, LayerKind::Raster);
51//! let (pixels, (x, y)) = reopened.layer_pixels(layer)?.unwrap();
52//! assert_eq!(pixels.pixel((10 - x) as u32, (20 - y) as u32), [200, 30, 30, 255]);
53//! assert_eq!(pixels.pixel((9 - x) as u32, (20 - y) as u32)[3], 0);
54//! # Ok::<(), csp_format::Error>(())
55//! ```
56//!
57//! # Rendering and checking
58//!
59//! [`render::render`] composites the layers (blend modes, clipping, masks,
60//! effects, corrections, gradients, vectors) into an image, and
61//! [`verify::check_clip`] runs every self-check (round trips of each part,
62//! references between tables and chunks).
63//!
64//! # Modules
65//!
66//! | Area | Modules |
67//! |---|---|
68//! | Files | [`clip`], [`cmc`], [`container`], [`database`], [`schema`], [`version`] |
69//! | Layers | [`model`], [`offscreen`], [`vector`], [`text`], [`gradient`], [`correction`], [`effect`], [`tone`], [`material`] |
70//! | Animation | [`animation`], [`cmt`] |
71//! | Writing | [`create`], [`edit`], [`copy`], [`work`], [`cmc_pages`], [`blank`], [`story`], [`vector_build`] |
72//! | Output | [`render`], [`verify`], [`image`] |
73//!
74//! Items hidden from these docs are used by the project's investigation
75//! tools and are not part of the stable API.
76
77#![deny(unsafe_code)]
78#![warn(missing_docs)]
79
80pub mod animation;
81#[doc(hidden)]
82pub mod binary;
83pub mod blank;
84pub mod clip;
85pub mod cmc;
86pub mod cmc_pages;
87pub mod cmt;
88pub mod container;
89pub mod copy;
90pub mod correction;
91pub mod create;
92mod curve;
93pub mod database;
94pub mod edit;
95pub mod effect;
96pub mod error;
97pub mod gradient;
98pub mod image;
99pub mod material;
100pub mod model;
101pub mod offscreen;
102pub mod render;
103pub mod schema;
104pub mod story;
105#[doc(hidden)]
106pub mod stroke;
107pub mod text;
108pub mod tone;
109pub mod vector;
110pub mod vector_build;
111pub mod verify;
112pub mod version;
113pub mod work;
114mod zlib;
115
116/// The SQLite binding this crate's database API uses (`rusqlite`), so that
117/// callers use the same version.
118pub use rusqlite;
119
120pub use clip::ClipFile;
121pub use cmc::CmcFile;
122pub use create::NewCanvas;
123pub use error::{Error, Result};
124pub use image::{GrayImage, RgbaImage};
125pub use model::{Canvas, Layer, LayerKind, LayerTree};
126pub use version::VersionInfo;
127pub use work::NewWork;