Skip to main content

glycin_utils/api/
editor.rs

1use std::any::Any;
2use std::io::{Cursor, Read, Seek, SeekFrom, Write};
3use std::panic::RefUnwindSafe;
4
5use glycin_common::Operations;
6#[cfg(feature = "external")]
7use zbus::zvariant::{self, DeserializeDict, SerializeDict, Type, as_value};
8
9use crate::{
10    ByteData, EncodedImage, EncodingOptions, FungibleMemory, GenericContexts,
11    InitializationDetails, MemoryAllocationError, NewImage, ProcessError,
12};
13
14/// Implement this trait to create an image editor
15pub trait EditorImplementation: Send + Sync + Sized + RefUnwindSafe + 'static {
16    const USEABLE: bool = true;
17
18    fn edit<S: Read + Any>(
19        stream: S,
20        mime_type: String,
21        details: InitializationDetails,
22    ) -> Result<Self, ProcessError>;
23
24    fn create<B: ByteData>(
25        mime_type: String,
26        new_image: NewImage<B>,
27        encoding_options: EncodingOptions,
28    ) -> Result<EncodedImage<B>, ProcessError>;
29
30    fn apply_sparse<B: ByteData>(
31        &self,
32        operations: Operations,
33    ) -> Result<SparseEditorOutput<B>, ProcessError> {
34        let complete = Self::apply_complete(self, operations)?;
35
36        Ok(SparseEditorOutput::from(complete))
37    }
38
39    fn apply_complete<B: ByteData>(
40        &self,
41        operations: Operations,
42    ) -> Result<CompleteEditorOutput<B>, ProcessError>;
43}
44
45#[cfg(feature = "external")]
46/// Editable image
47#[derive(serde::Deserialize, serde::Serialize, Type, Debug, Clone)]
48pub struct RemoteEditableImage {
49    pub edit_request: zvariant::OwnedObjectPath,
50}
51
52#[cfg(feature = "external")]
53impl RemoteEditableImage {
54    pub fn new(frame_request: zvariant::OwnedObjectPath) -> Self {
55        Self {
56            edit_request: frame_request,
57        }
58    }
59}
60
61/// Result of a sparse editor operation
62///
63/// This either contains `byte_changes` or `data`, depending on whether a sparse
64/// application of the operations was possible.
65#[derive(Debug)]
66#[cfg_attr(
67    feature = "external",
68    derive(Type, serde::Serialize, serde::Deserialize)
69)]
70#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
71#[cfg_attr(
72    feature = "external",
73    serde(bound(
74        serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
75        deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
76    ))
77)]
78#[non_exhaustive]
79pub struct SparseEditorOutput<B: ByteData> {
80    #[cfg_attr(
81        feature = "external",
82        serde(
83            with = "as_value::optional",
84            skip_serializing_if = "Option::is_none",
85            default
86        )
87    )]
88    pub byte_changes: Option<ByteChanges>,
89    #[cfg_attr(
90        feature = "external",
91        serde(
92            with = "as_value::optional",
93            skip_serializing_if = "Option::is_none",
94            default
95        )
96    )]
97    pub data: Option<B>,
98    #[cfg_attr(feature = "external", serde(with = "as_value"))]
99    pub info: EditorOutputInfo,
100}
101
102impl<B: ByteData> SparseEditorOutput<B> {
103    pub fn byte_changes(byte_changes: ByteChanges) -> Self {
104        SparseEditorOutput {
105            byte_changes: Some(byte_changes),
106            data: None,
107            info: EditorOutputInfo { lossless: true },
108        }
109    }
110
111    pub fn into_fungible(self) -> SparseEditorOutput<FungibleMemory> {
112        SparseEditorOutput {
113            byte_changes: self.byte_changes,
114            data: self.data.map(|x| x.into_fungible()),
115            info: self.info,
116        }
117    }
118
119    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
120        if let Some(data) = &mut self.data {
121            data.initial_seal().await?;
122        }
123
124        Ok(())
125    }
126
127    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
128        if let Some(data) = &mut self.data {
129            data.final_seal().await?;
130        }
131
132        Ok(())
133    }
134}
135
136impl<B: ByteData> From<CompleteEditorOutput<B>> for SparseEditorOutput<B> {
137    fn from(value: CompleteEditorOutput<B>) -> Self {
138        Self {
139            byte_changes: None,
140            data: Some(value.data),
141            info: value.info,
142        }
143    }
144}
145
146#[derive(Debug, Clone)]
147#[cfg_attr(feature = "external", derive(DeserializeDict, SerializeDict, Type))]
148#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
149#[non_exhaustive]
150pub struct ByteChanges {
151    pub changes: Vec<ByteChange>,
152}
153
154#[derive(Debug, Clone)]
155#[cfg_attr(
156    feature = "external",
157    derive(serde::Deserialize, serde::Serialize, Type)
158)]
159pub struct ByteChange {
160    pub offset: u64,
161    pub new_value: u8,
162}
163
164impl ByteChanges {
165    pub fn from_slice(changes: &[(u64, u8)]) -> Self {
166        ByteChanges {
167            changes: changes
168                .iter()
169                .map(|(offset, new_value)| ByteChange {
170                    offset: *offset,
171                    new_value: *new_value,
172                })
173                .collect(),
174        }
175    }
176
177    pub fn apply(&self, data: &mut [u8]) -> std::io::Result<()> {
178        let mut cur = Cursor::new(data);
179        for change in self.changes.iter() {
180            cur.seek(SeekFrom::Start(change.offset))?;
181            cur.write_all(&[change.new_value])?;
182        }
183        Ok(())
184    }
185}
186
187#[derive(Debug)]
188#[cfg_attr(
189    feature = "external",
190    derive(Type, serde::Serialize, serde::Deserialize)
191)]
192#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
193#[cfg_attr(
194    feature = "external",
195    serde(bound(
196        serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
197        deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
198    ))
199)]
200#[non_exhaustive]
201pub struct CompleteEditorOutput<B: ByteData> {
202    #[cfg_attr(feature = "external", serde(with = "as_value"))]
203    pub data: B,
204    #[cfg_attr(feature = "external", serde(with = "as_value"))]
205    pub info: EditorOutputInfo,
206}
207
208/*
209#[cfg(feature = "external")]
210impl zvariant::Type for CompleteEditorOutput<crate::SharedMemory> {
211    const SIGNATURE: &'static zvariant::Signature = &zvariant::Signature::Dict {
212        key: zvariant::signature::Child::Static {
213            child: &zvariant::Signature::Str,
214        },
215        value: zvariant::signature::Child::Static {
216            child: &zvariant::Signature::Variant,
217        },
218    };
219}
220    */
221
222impl<B: ByteData> CompleteEditorOutput<B> {
223    pub fn new(data: B) -> Self {
224        Self {
225            data,
226            info: Default::default(),
227        }
228    }
229
230    pub fn new_lossless(data: Vec<u8>) -> Result<Self, ProcessError> {
231        let data = B::try_from_vec(data).expected_error()?;
232        let info = EditorOutputInfo { lossless: true };
233        Ok(Self { data, info })
234    }
235
236    pub fn into_fungible(self) -> CompleteEditorOutput<FungibleMemory> {
237        CompleteEditorOutput {
238            data: self.data.into_fungible(),
239            info: self.info,
240        }
241    }
242
243    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
244        self.data.initial_seal().await
245    }
246
247    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
248        self.data.final_seal().await
249    }
250}
251
252#[derive(Debug, Default, Clone)]
253#[cfg_attr(feature = "external", derive(DeserializeDict, SerializeDict, Type))]
254#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
255#[non_exhaustive]
256pub struct EditorOutputInfo {
257    /// Operation is considered to be lossless
258    ///
259    /// Operations are considered lossless when all metadata are kept, no image
260    /// data is lost, and no image quality is lost.
261    pub lossless: bool,
262}