c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

thumbnail.rs (4319B)


      1 // Copyright 2022 Adobe. All rights reserved.
      2 // This file is licensed to you under the Apache License,
      3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
      4 // or the MIT license (http://opensource.org/licenses/MIT),
      5 // at your option.
      6 
      7 // Unless required by applicable law or agreed to in writing,
      8 // this software is distributed on an "AS IS" BASIS, WITHOUT
      9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
     10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the
     11 // specific language governing permissions and limitations under
     12 // each license.
     13 
     14 use serde::Serialize;
     15 
     16 use crate::{
     17     assertion::{
     18         get_thumbnail_image_type, Assertion, AssertionBase, AssertionData, AssertionDecodeError,
     19     },
     20     assertions::labels,
     21     error::Result,
     22 };
     23 
     24 /// A Thumbnail assertion
     25 #[derive(Serialize)]
     26 pub struct Thumbnail {
     27     pub data: Vec<u8>,
     28     pub label: String,
     29     pub content_type: String,
     30 }
     31 
     32 impl Thumbnail {
     33     pub fn new(label: &str, data: Vec<u8>) -> Self {
     34         let image_type = get_thumbnail_image_type(label);
     35         let content_type = match image_type.as_str() {
     36             "jpeg" | "jpk2" => "image/jpeg",
     37             "png" => "image/png",
     38             "bmp" => "image/bmp",
     39             "gif" => "image/gif",
     40             "tiff" => "image/tiff",
     41             "ico" => "image/x-icon",
     42             "webp" => "image/webp",
     43             _ => "application/octet-stream",
     44         }
     45         .to_string();
     46 
     47         Thumbnail {
     48             data,
     49             label: label.to_owned(),
     50             content_type,
     51         }
     52     }
     53 }
     54 
     55 impl AssertionBase for Thumbnail {
     56     /// returns the base label type for this thumbnail
     57     fn label(&self) -> &str {
     58         if self.label.starts_with(labels::CLAIM_THUMBNAIL) {
     59             labels::CLAIM_THUMBNAIL
     60         } else {
     61             labels::INGREDIENT_THUMBNAIL
     62         }
     63     }
     64 
     65     fn to_assertion(&self) -> Result<Assertion> {
     66         let data = AssertionData::Binary(self.data.to_owned());
     67         Ok(Assertion::new(&self.label, None, data).set_content_type(&self.content_type))
     68     }
     69 
     70     fn from_assertion(assertion: &Assertion) -> Result<Thumbnail> {
     71         match assertion.decode_data() {
     72             AssertionData::Binary(data) => Ok(Self {
     73                 data: data.to_owned(),
     74                 label: assertion.label(),
     75                 content_type: assertion.content_type(),
     76             }),
     77             ad => Err(AssertionDecodeError::from_assertion_unexpected_data_type(
     78                 assertion, ad, "binary",
     79             )
     80             .into()),
     81         }
     82     }
     83 }
     84 
     85 #[cfg(test)]
     86 pub mod tests {
     87     #![allow(clippy::expect_used)]
     88     #![allow(clippy::unwrap_used)]
     89 
     90     use super::*;
     91 
     92     // a binary assertion  ('deadbeefadbeadbe')
     93     fn some_binary_data() -> Vec<u8> {
     94         vec![
     95             0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, 0x0a, 0x0d, 0x0b, 0x0e, 0x0a, 0x0d,
     96             0x0b, 0x0e,
     97         ]
     98     }
     99 
    100     fn thumbnail_test(label: &str, content_type: &str) {
    101         let original = Thumbnail::new(label, some_binary_data());
    102         let assertion = original.to_assertion().expect("build_assertion");
    103         assert_eq!(assertion.content_type(), content_type);
    104         assert_eq!(assertion.label(), label);
    105         let result = Thumbnail::from_assertion(&assertion).expect("from_assertion");
    106         assert_eq!(original.label, result.label);
    107         assert_eq!(original.content_type, result.content_type);
    108         assert_eq!(original.data, result.data);
    109     }
    110 
    111     #[test]
    112     fn assertion_thumbnail_valid() {
    113         thumbnail_test(labels::JPEG_CLAIM_THUMBNAIL, "image/jpeg");
    114         thumbnail_test(labels::PNG_CLAIM_THUMBNAIL, "image/png");
    115         thumbnail_test(labels::JPEG_INGREDIENT_THUMBNAIL, "image/jpeg");
    116         thumbnail_test(labels::PNG_INGREDIENT_THUMBNAIL, "image/png");
    117         // unrecognized labels will be formatted as octet_streams
    118         thumbnail_test("foo", "application/octet-stream");
    119     }
    120 
    121     #[test]
    122     fn assertion_thumbnail_invalid_from() {
    123         // only current error is if the assertion data is the wrong type, so use JSON
    124         let data = AssertionData::Json("foo".to_owned());
    125         let assertion = Assertion::new(labels::JPEG_CLAIM_THUMBNAIL, None, data);
    126         let result = Thumbnail::from_assertion(&assertion);
    127         assert!(result.is_err())
    128     }
    129 }