1use std::hash::{BuildHasher, Hasher};
18
19use rusqlite::OptionalExtension;
20use rusqlite::types::Value;
21
22use crate::clip::ClipFile;
23use crate::database::{has_column, quote, value_as_text};
24use crate::error::{Error, Result, bail};
25use crate::image::RgbaImage;
26use crate::model::{LAYER_TYPE_PAPER, LAYER_TYPE_RASTER, LAYER_TYPE_ROOT, LayerKind};
27use crate::offscreen::{Attribute, InitColor, Parameter, PixelKind, encode};
28use crate::render::{BlendMode, render_like_preview};
29
30pub fn new_uuid() -> [u8; 16] {
32 let mut bytes = [0u8; 16];
33 for half in bytes.chunks_mut(8) {
34 let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
35 hasher.write_u128(
36 std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_nanos(),
37 );
38 half.copy_from_slice(&hasher.finish().to_be_bytes());
39 }
40 bytes[6] = (bytes[6] & 0x0f) | 0x40;
41 bytes[8] = (bytes[8] & 0x3f) | 0x80;
42 bytes
43}
44
45pub fn new_external_id() -> String {
47 let mut text = String::from("extrnlid");
48 for byte in new_uuid() {
49 text.push_str(&format!("{byte:02X}"));
50 }
51 text
52}
53
54impl ClipFile {
55 pub fn renew_file_id(&mut self) {
57 self.set_file_id(new_uuid());
58 }
59
60 pub fn set_layer_pixels(&mut self, layer_id: i64, image: &RgbaImage, position: (i64, i64)) -> Result<()> {
64 let layer = self.layers.get(layer_id).ok_or_else(|| Error::format(format!("No layer {layer_id}")))?.clone();
65 let mipmap = self
66 .mipmap(layer.render_mipmap)?
67 .ok_or_else(|| Error::format(format!("Layer {layer_id} has no render mipmap")))?;
68 let origin = layer.pixel_origin();
69 let mut level_image: Option<RgbaImage> = None;
70 for level in &mipmap.levels {
71 let row = self
72 .row("Offscreen", level.offscreen)?
73 .ok_or_else(|| Error::format(format!("No Offscreen {}", level.offscreen)))?;
74 let mut attribute = Attribute::parse(row.blob("Attribute").unwrap_or_default())?;
75 let parameter = attribute.parameter()?;
76 if parameter.kind() != PixelKind::Color {
77 bail!("Layer {layer_id} is not a colour layer ({:?})", parameter.kind());
78 }
79 let pixels = match level_image.take() {
80 None => {
81 let mut full = RgbaImage::new(parameter.width, parameter.height);
82 full.paste(image, position.0 - origin.0, position.1 - origin.1);
83 full
84 }
85 Some(above) => {
86 let mut halved = above.halve();
87 if (halved.width, halved.height) != (parameter.width, parameter.height) {
88 halved = halved.resize_area(parameter.width, parameter.height);
89 }
90 halved
91 }
92 };
93 let data = encode(¶meter, Some(&pixels), None)?;
94 attribute.set_block_sizes(&data.record_sizes());
95 let old = row.get("BlockData").and_then(value_as_text).filter(|id| !id.is_empty());
96 let id = new_external_id();
97 if let Some(old) = &old {
98 self.remove_external(old);
99 }
100 self.set_external(&id, data.to_bytes());
101 self.database().execute(
102 "UPDATE Offscreen SET Attribute = ?1, BlockData = ?2 WHERE MainId = ?3",
103 (attribute.to_bytes(), Value::Blob(id.into_bytes()), level.offscreen),
104 )?;
105 level_image = Some(pixels);
106 }
107 Ok(())
108 }
109
110 pub fn set_layer_value(&mut self, layer_id: i64, column: &str, value: Value) -> Result<()> {
112 if !crate::database::has_column(self.database(), "Layer", column)? {
113 bail!("Layer has no column {column}");
114 }
115 let sql = format!("UPDATE Layer SET {} = ?1 WHERE MainId = ?2", crate::database::quote(column));
116 if self.database().execute(&sql, (value, layer_id))? == 0 {
117 bail!("No layer {layer_id}");
118 }
119 self.reload()
120 }
121
122 pub fn set_layer_name(&mut self, layer_id: i64, name: &str) -> Result<()> {
124 self.set_layer_value(layer_id, "LayerName", Value::Text(name.to_owned()))
125 }
126
127 pub fn set_layer_opacity(&mut self, layer_id: i64, opacity: f64) -> Result<()> {
129 let stored = (opacity.clamp(0.0, 1.0) * crate::model::OPACITY_FULL as f64).round() as i64;
130 self.set_layer_value(layer_id, "LayerOpacity", Value::Integer(stored))
131 }
132
133 pub fn set_layer_blend(&mut self, layer_id: i64, mode: BlendMode) -> Result<()> {
135 self.set_layer_value(layer_id, "LayerComposite", Value::Integer(mode.code()))
136 }
137
138 pub fn set_layer_visible(&mut self, layer_id: i64, visible: bool) -> Result<()> {
140 let layer = self.layers.get(layer_id).ok_or_else(|| Error::format(format!("No layer {layer_id}")))?;
141 let value = (layer.row.int("LayerVisibility") & !1) | visible as i64;
142 self.set_layer_value(layer_id, "LayerVisibility", Value::Integer(value))
143 }
144
145 pub fn set_layer_clipping(&mut self, layer_id: i64, clipping: bool) -> Result<()> {
147 self.set_layer_value(layer_id, "LayerClip", Value::Integer(clipping as i64))
148 }
149
150 pub fn update_preview(&mut self) -> Result<bool> {
153 let Some((image, _, _)) = render_like_preview(self)? else { return Ok(false) };
154 let png = image.to_png()?;
155 self.database().execute(
156 "UPDATE CanvasPreview SET ImageData = ?1, ImageWidth = ?2, ImageHeight = ?3",
157 (png, image.width as i64, image.height as i64),
158 )?;
159 Ok(true)
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub enum NewLayer {
166 Raster,
168 Folder,
170 Paper([u8; 3]),
172 Root,
174}
175
176const THUMBNAIL_SIZE: u32 = 512;
178
179const LIGHT_TABLE_INFO: [u8; 15] = [1, 1, 1, 8, b't', b'y', b'p', b'e', b'n', b'a', b'm', b'e', 6, 0, 0];
181
182fn monochrome_fill_info() -> Vec<u8> {
184 let name = "MonochromeSetting";
185 let mut data = Vec::new();
186 data.extend(0u32.to_be_bytes());
187 data.extend(1u32.to_be_bytes());
188 data.extend((name.len() as u32).to_be_bytes());
189 for unit in name.encode_utf16() {
190 data.extend(unit.to_be_bytes());
191 }
192 data.extend([0u8; 12]);
193 data.extend(1u32.to_be_bytes());
194 let total = data.len() as u32;
195 data[..4].copy_from_slice(&total.to_be_bytes());
196 data
197}
198
199fn color_word(value: u8) -> i64 {
202 value as i64 * 0x0101_0101
203}
204
205pub(crate) fn layer_uuid() -> String {
207 let hex: String = new_uuid().iter().map(|b| format!("{b:02x}")).collect();
208 format!("{}-{}-{}-{}-{}", &hex[..10], &hex[10..14], &hex[14..18], &hex[18..22], &hex[22..])
209}
210
211pub fn mipmap_sizes(width: u32, height: u32) -> Vec<(u32, u32)> {
214 let mut sizes = vec![(width.max(1), height.max(1))];
215 loop {
216 let (w, h) = *sizes.last().expect("one level");
217 if sizes.len() >= 4 && w.max(h) <= 128 {
218 break;
219 }
220 sizes.push(((w / 2).max(1), (h / 2).max(1)));
221 }
222 sizes
223}
224
225impl ClipFile {
226 pub fn next_main_id(&self, table: &str) -> Result<i64> {
229 let database = self.database();
230 let max_index: Option<i64> = database
231 .query_row("SELECT MaxIndex FROM ElemScheme WHERE TableName = ?1", [table], |row| row.get(0))
232 .optional()?
233 .flatten();
234 let largest: i64 =
235 database
236 .query_row(&format!("SELECT COALESCE(MAX(MainId), 0) FROM {}", quote(table)), [], |row| row.get(0))?;
237 let id = max_index.unwrap_or(0).max(largest) + 1;
238 database.execute("UPDATE ElemScheme SET MaxIndex = ?1 WHERE TableName = ?2", (id, table))?;
239 Ok(id)
240 }
241
242 fn insert_row(&self, table: &str, values: &[(&str, Value)]) -> Result<()> {
244 let mut names = Vec::new();
245 let mut kept = Vec::new();
246 for (name, value) in values {
247 if has_column(self.database(), table, name)? {
248 names.push(quote(name));
249 kept.push(value.clone());
250 }
251 }
252 let marks: Vec<String> = (1..=kept.len()).map(|i| format!("?{i}")).collect();
253 let sql = format!("INSERT INTO {} ({}) VALUES ({})", quote(table), names.join(", "), marks.join(", "));
254 self.database().execute(&sql, rusqlite::params_from_iter(kept))?;
255 Ok(())
256 }
257
258 fn new_offscreen(&mut self, layer_id: i64, size: (u32, u32), init: Option<&InitColor>, store: bool) -> Result<i64> {
261 let id = self.next_main_id("Offscreen")?;
262 let parameter = Parameter::new(PixelKind::Color, size.0, size.1);
263 let mut attribute = Attribute::new(¶meter, init);
264 let external = new_external_id();
265 if store {
266 let data = encode(¶meter, Some(&RgbaImage::new(size.0, size.1)), None)?;
267 attribute.set_block_sizes(&data.record_sizes());
268 self.set_external(&external, data.to_bytes());
269 }
270 self.insert_row(
271 "Offscreen",
272 &[
273 ("MainId", Value::Integer(id)),
274 ("CanvasId", Value::Integer(self.canvas.main_id)),
275 ("LayerId", Value::Integer(layer_id)),
276 ("Attribute", Value::Blob(attribute.to_bytes())),
277 ("BlockData", Value::Blob(external.into_bytes())),
278 ],
279 )?;
280 Ok(id)
281 }
282
283 pub(crate) fn new_mipmap(&mut self, layer_id: i64, init: Option<&InitColor>, store_base: bool) -> Result<i64> {
288 self.new_mipmap_sized(layer_id, (self.canvas.width_px, self.canvas.height_px), init, store_base)
289 }
290
291 pub(crate) fn new_mipmap_sized(
294 &mut self,
295 layer_id: i64,
296 size: (u32, u32),
297 init: Option<&InitColor>,
298 store_base: bool,
299 ) -> Result<i64> {
300 let sizes = mipmap_sizes(size.0, size.1);
301 let mipmap = self.next_main_id("Mipmap")?;
302 let infos = sizes.iter().map(|_| self.next_main_id("MipmapInfo")).collect::<Result<Vec<_>>>()?;
303 for (level, size) in sizes.iter().enumerate() {
304 let offscreen = self.new_offscreen(layer_id, *size, init, store_base && level == 0)?;
305 self.insert_row(
306 "MipmapInfo",
307 &[
308 ("MainId", Value::Integer(infos[level])),
309 ("CanvasId", Value::Integer(self.canvas.main_id)),
310 ("LayerId", Value::Integer(layer_id)),
311 ("ThisScale", Value::Real(100.0 / (1u64 << level) as f64)),
312 ("Offscreen", Value::Integer(offscreen)),
313 ("NextIndex", Value::Integer(infos.get(level + 1).copied().unwrap_or(0))),
314 ],
315 )?;
316 }
317 self.insert_row(
318 "Mipmap",
319 &[
320 ("MainId", Value::Integer(mipmap)),
321 ("CanvasId", Value::Integer(self.canvas.main_id)),
322 ("LayerId", Value::Integer(layer_id)),
323 ("MipmapCount", Value::Integer(sizes.len() as i64)),
324 ("BaseMipmapInfo", Value::Integer(infos[0])),
325 ],
326 )?;
327 Ok(mipmap)
328 }
329
330 pub(crate) fn new_thumbnail(&mut self, layer_id: i64) -> Result<i64> {
332 let id = self.next_main_id("LayerThumbnail")?;
333 let offscreen = self.new_offscreen(layer_id, (THUMBNAIL_SIZE, THUMBNAIL_SIZE), None, true)?;
334 let int = Value::Integer;
335 let mut values = vec![("MainId", int(id)), ("CanvasId", int(self.canvas.main_id)), ("LayerId", int(layer_id))];
336 for column in [
337 "ThumbnailSmallerNeedRefresh",
338 "ThumbnailSmallNeedRefresh",
339 "ThumbnailMiddleNeedRefresh",
340 "ThumbnailLargeNeedRefresh",
341 "ThumbnailLargerNeedRefresh",
342 "ThumbnailMiddle2xNeedRefresh",
343 "ThumbnailLarger2xNeedRefresh",
344 "ThumbnailSmallerNeedRefresh1",
345 "ThumbnailSmallNeedRefresh1",
346 "ThumbnailMiddleNeedRefresh1",
347 "ThumbnailLargeNeedRefresh1",
348 "ThumbnailLargerNeedRefresh1",
349 "ThumbnailMiddle2xNeedRefresh1",
350 "ThumbnailLarger2xNeedRefresh1",
351 ] {
352 values.push((column, int(5)));
353 }
354 values.extend([
355 ("ThumbnailDrewMode", int(0)),
356 ("ThumbnailFixMode", int(-1)),
357 ("ThumbnailCanvasWidth", int(self.canvas.width_px as i64)),
358 ("ThumbnailCanvasHeight", int(self.canvas.height_px as i64)),
359 ("ThumbnailUseDrawColor", int(0)),
360 ("ThumbnailMainColorRed", int(0)),
361 ("ThumbnailMainColorGreen", int(0)),
362 ("ThumbnailMainColorBlue", int(0)),
363 ("ThumbnailSubColorRed", int(0)),
364 ("ThumbnailSubColorGreen", int(0)),
365 ("ThumbnailSubColorBlue", int(0)),
366 ("ThumbnailOffscreen", int(offscreen)),
367 ("ThumbnailColorTypeIndex", int(0)),
368 ("ThumbnailColorTypeBlack", int(1)),
369 ("ThumbnailColorTypeWhite", int(1)),
370 ("ThumbnailPrewviewColorTypeIndex", int(0)),
371 ("ThumbnailPrewviewColorTypeBlack", int(1)),
372 ("ThumbnailPrewviewColorTypeWhite", int(1)),
373 ("ThumbnailPrewviewColorTypeOpacity", int(1)),
374 ("ThumbnailPrewviewColorTypeImage", int(0x8000_0000)),
375 ("ThumbnailPrewviewColorTypeAlpha", int(0x8000_0000)),
376 ("ThumbnailPrewviewMaskBinarize", int(0)),
377 ("ThumbnailPrewviewMaskThreshold", int(0x8000_0000)),
378 ("ThumbnailDrewUseCanvasAspect0", int(1)),
379 ("ThumbnailDrewUseCanvasAspect1", int(1)),
380 ]);
381 self.insert_row("LayerThumbnail", &values)?;
382 Ok(id)
383 }
384
385 pub fn add_layer(&mut self, parent: i64, kind: NewLayer, name: &str) -> Result<i64> {
388 let id = self.next_main_id("Layer")?;
389 self.insert_layer_row(id, kind, name)?;
390 if kind != NewLayer::Root {
391 self.link_on_top(parent, id)?;
392 }
393 if kind == NewLayer::Raster {
394 self.database().execute("UPDATE Canvas SET CanvasCurrentLayer = ?1", [id])?;
395 }
396 self.reload()?;
397 Ok(id)
398 }
399
400 pub fn add_raster_layer(&mut self, name: &str, image: &RgbaImage, position: (i64, i64)) -> Result<i64> {
403 let id = self.add_layer(self.canvas.root_folder, NewLayer::Raster, name)?;
404 self.set_layer_pixels(id, image, position)?;
405 Ok(id)
406 }
407
408 pub(crate) fn insert_layer_row(&mut self, id: i64, kind: NewLayer, name: &str) -> Result<()> {
409 let paper_init = InitColor { do_initialize: true, alpha: 0xffff_ffff, image_values: vec![0; 4] };
410 let init = matches!(kind, NewLayer::Paper(_)).then_some(&paper_init);
411 let mipmap = self.new_mipmap(id, init, kind == NewLayer::Raster)?;
412 let thumbnail = self.new_thumbnail(id)?;
413 let int = Value::Integer;
414 let (layer_type, folder, masking) = match kind {
415 NewLayer::Raster => (LAYER_TYPE_RASTER, 0, 0),
416 NewLayer::Folder => (0, 1, 32),
417 NewLayer::Paper(_) => (LAYER_TYPE_PAPER, 0, 0),
418 NewLayer::Root => (LAYER_TYPE_ROOT, 1, 32),
419 };
420 let mut values = vec![
421 ("MainId", int(id)),
422 ("CanvasId", int(self.canvas.main_id)),
423 ("LayerName", Value::Text(name.to_owned())),
424 ("LayerType", int(layer_type)),
425 ("LayerLock", int(0)),
426 ("LayerClip", int(0)),
427 ("LayerMasking", int(masking)),
428 ];
429 for column in [
430 "LayerOffsetX",
431 "LayerOffsetY",
432 "LayerRenderOffscrOffsetX",
433 "LayerRenderOffscrOffsetY",
434 "LayerMaskOffsetX",
435 "LayerMaskOffsetY",
436 "LayerMaskOffscrOffsetX",
437 "LayerMaskOffscrOffsetY",
438 ] {
439 values.push((column, int(0)));
440 }
441 values.extend([
442 ("LayerOpacity", int(crate::model::OPACITY_FULL)),
443 ("LayerComposite", int(0)),
444 ("LayerUsePaletteColor", int(0)),
445 ("LayerNoticeablePaletteColor", int(0)),
446 ("LayerPaletteRed", int(0)),
447 ("LayerPaletteGreen", int(0)),
448 ("LayerPaletteBlue", int(0)),
449 ("LayerFolder", int(folder)),
450 ("LayerVisibility", int(1)),
451 ("LayerSelect", int(0)),
452 ("LayerNextIndex", int(0)),
453 ("LayerFirstChildIndex", int(0)),
454 ("LayerUuid", Value::Text(layer_uuid())),
455 ("LayerRenderMipmap", int(mipmap)),
456 ("LayerLayerMaskMipmap", int(0)),
457 ("LayerRenderThumbnail", int(thumbnail)),
458 ("LayerLayerMaskThumbnail", int(0)),
459 ]);
460 if kind != NewLayer::Root {
461 values.push(("LightTableInfo", Value::Blob(LIGHT_TABLE_INFO.to_vec())));
462 }
463 if kind == NewLayer::Raster {
464 values.extend([
465 ("LayerColorTypeIndex", int(0)),
466 ("LayerColorTypeBlackChecked", int(1)),
467 ("LayerColorTypeWhiteChecked", int(1)),
468 ]);
469 }
470 if let NewLayer::Paper(color) = kind {
471 values.extend([
472 ("DrawColorMainRed", int(color_word(color[0]))),
473 ("DrawColorMainGreen", int(color_word(color[1]))),
474 ("DrawColorMainBlue", int(color_word(color[2]))),
475 ("DrawColorEnable", int(1)),
476 ("DrawToRenderOffscreenType", int(61)),
477 ("SpecialRenderType", int(20)),
478 ("DrawToRenderMipmapType", int(31)),
479 ("MoveOffsetAndExpandType", int(31)),
480 ("FixOffsetAndExpandType", int(31)),
481 ("RenderBoundForLayerMoveType", int(31)),
482 ("SetRenderThumbnailInfoType", int(31)),
483 ("DrawRenderThumbnailType", int(31)),
484 ("MonochromeFillInfo", Value::Blob(monochrome_fill_info())),
485 ]);
486 }
487 self.insert_row("Layer", &values)
488 }
489
490 pub(crate) fn link_on_top(&mut self, parent: i64, id: i64) -> Result<()> {
492 let database = self.database();
493 let first: i64 = database
494 .query_row("SELECT LayerFirstChildIndex FROM Layer WHERE MainId = ?1", [parent], |row| row.get(0))
495 .optional()?
496 .ok_or_else(|| Error::format(format!("No layer {parent}")))?;
497 if first == 0 {
498 database.execute("UPDATE Layer SET LayerFirstChildIndex = ?1 WHERE MainId = ?2", (id, parent))?;
499 return Ok(());
500 }
501 let mut last = first;
502 loop {
503 let next: i64 =
504 database.query_row("SELECT LayerNextIndex FROM Layer WHERE MainId = ?1", [last], |row| row.get(0))?;
505 if next == 0 || next == id {
506 break;
507 }
508 last = next;
509 }
510 database.execute("UPDATE Layer SET LayerNextIndex = ?1 WHERE MainId = ?2", (id, last))?;
511 Ok(())
512 }
513
514 pub fn remove_layer(&mut self, layer_id: i64) -> Result<()> {
518 let layer = self.layers.get(layer_id).ok_or_else(|| Error::format(format!("No layer {layer_id}")))?.clone();
519 if layer.kind == LayerKind::Root {
520 bail!("The root folder cannot be removed");
521 }
522 let next = layer.next;
524 let database = self.database();
525 database
526 .execute("UPDATE Layer SET LayerFirstChildIndex = ?1 WHERE LayerFirstChildIndex = ?2", (next, layer_id))?;
527 database.execute("UPDATE Layer SET LayerNextIndex = ?1 WHERE LayerNextIndex = ?2", (next, layer_id))?;
528 let mut doomed = vec![layer_id];
529 let mut child = layer.first_child;
530 let mut stack = Vec::new();
531 while child != 0 || !stack.is_empty() {
532 if child == 0 {
533 child = stack.pop().unwrap_or(0);
534 continue;
535 }
536 doomed.push(child);
537 let (first, next): (i64, i64) = database.query_row(
538 "SELECT LayerFirstChildIndex, LayerNextIndex FROM Layer WHERE MainId = ?1",
539 [child],
540 |row| Ok((row.get(0)?, row.get(1)?)),
541 )?;
542 stack.push(next);
543 child = first;
544 }
545 for id in doomed {
546 let mut externals = Vec::new();
547 {
548 let mut statement = self.database().prepare("SELECT BlockData FROM Offscreen WHERE LayerId = ?1")?;
549 let rows = statement.query_map([id], |row| row.get::<_, Value>(0))?;
550 for value in rows {
551 if let Some(text) = value_as_text(&value?) {
552 externals.push(text);
553 }
554 }
555 }
556 for external in externals {
557 self.remove_external(&external);
558 }
559 for table in ["Offscreen", "MipmapInfo", "Mipmap", "LayerThumbnail"] {
560 if crate::database::has_table(self.database(), table)? {
561 self.database().execute(&format!("DELETE FROM {} WHERE LayerId = ?1", quote(table)), [id])?;
562 }
563 }
564 self.database().execute("DELETE FROM Layer WHERE MainId = ?1", [id])?;
565 }
566 let current: i64 = self.database().query_row("SELECT CanvasCurrentLayer FROM Canvas", [], |row| row.get(0))?;
567 if self
568 .database()
569 .query_row("SELECT COUNT(*) FROM Layer WHERE MainId = ?1", [current], |row| row.get::<_, i64>(0))?
570 == 0
571 {
572 self.database().execute("UPDATE Canvas SET CanvasCurrentLayer = 0", [])?;
573 }
574 self.reload()
575 }
576}
577
578#[cfg(test)]
579mod tests {
580 use super::*;
581
582 #[test]
583 fn external_ids_have_csp_shape() {
584 let id = new_external_id();
585 assert!(crate::container::is_external_id(&id), "{id}");
586 assert_ne!(id, new_external_id());
587 }
588}