eth_blockies/
lib.rs

1//! A lightweight library in pure Rust to get Ethereum-style blocky identicon data,
2//! which can be used for generating blockies icon images, printing to terminal, etc.
3//!
4//! Useful when getting raw RGB data of Ethereum-style blockies, as well as complete png image files.
5//!
6//!
7//! # Basic Usage
8//!
9//!
10//! 1. Define a blockies type (size) to use
11//!
12//!    * Make an alias type of [`Blockies`]
13//!    ```
14//!    use eth_blockies::{Blockies, BlockiesGenerator};
15//!  
16//!    // Blockies < size (const), T >
17//!    type Icon<T> = Blockies<15, T>;
18//!    ```
19//!   
20//!    * *Cf)* For Ethereum address blockies, [`EthBlockies`] is predefined as follows
21//!    ```
22//!    // use statement for Ethereum address blockies
23//!    use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
24//!    //   type 'EthBlockies<T>' is predefined as 'Blockies<8, T>'
25//!    ```   
26//! ---
27//!
28//!
29//! 2. Select an input seed type
30//!
31//!    * Check for [`SeedInput`] to get full list of input seed types
32//!    ```
33//!    # use eth_blockies::{Blockies, BlockiesGenerator};
34//!    #
35//!    # type Icon<T> = Blockies<15, T>;
36//!    #
37//!    // generate blockies from various input type
38//!    let from_string = Icon::data("eth-blockies".to_string());
39//!    let from_byte_vec = Icon::data(vec![0x0c, 0x93, 0xa3, 0x2e]);
40//!    ```
41//!   
42//!    * *Cf)* For Ethereum address seeds, apply [`to_ethaddr_seed()`](global_type_helper::SeedInput::to_ethaddr_seed) before passing as input seed
43//!    ```
44//!    # use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
45//!    #
46//!    // generate Ethereum address blockies from various input type
47//!
48//!    let seed_from_str = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
49//!        .to_ethaddr_seed();
50//!    let from_str = EthBlockies::data(seed_from_str);
51//!
52//!    let seed_from_bytes = [
53//!          0xe6, 0x86, 0xc1, 0x4f, 0xf9, 0xc1, 0x10, 0x38, 0xf2, 0xb1,
54//!          0xc9, 0xad, 0x61, 0x7f, 0x23, 0x46, 0xcf, 0xb8, 0x17, 0xdc,
55//!        ].to_ethaddr_seed();
56//!    let from_bytes = EthBlockies::data(seed_from_bytes);
57//!    ```
58//! ---
59//!
60//!
61//! 3. Select an output data type
62//!
63//!    * Check for [`BlockiesGenerator`] to get full list of output data types
64//!    ```
65//!    # use eth_blockies::{Blockies, BlockiesGenerator};
66//!    #
67//!    # type Icon<T> = Blockies<15, T>;
68//!    #
69//!    # fn to_gray((r, g, b): (u8, u8, u8)) -> u8 {
70//!    #     (r as f64 * 0.299 + g as f64 * 0.587 + b as f64 * 0.114) as u8
71//!    # }
72//!    #
73//!    // generate blockies in various forms
74//!    let in_rgb_2d_arr = Icon::data("eth-blockies");
75//!    let in_indexed_2d_arr = Icon::indexed_data("eth-blockies");
76//!    let in_gray_2d_arr = Icon::data_mapped("eth-blockies", to_gray);
77//!    let in_png_data_vec = Icon::png_data("eth-blockies", (128, 128));
78//!    ```
79//!
80//!
81//! # Example
82//!
83//! * Generate an Ethereum address blockies (with [`to_ethaddr_seed()`](global_type_helper::SeedInput::to_ethaddr_seed))
84//!
85//!   ```no_run
86//!   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
87//!
88//!   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
89//!       .to_ethaddr_seed(); // required for Ethereum address blockies
90//!
91//!   // 8x8 2D-array of (r, g, b)
92//!   {
93//!       let eth_blockies_from_addr = EthBlockies::data(&seed);
94//!   }
95//!
96//!   // uncompressed png data in byte vector
97//!   {
98//!       let eth_blockies_png_from_addr =
99//!           EthBlockies::png_data(&seed, (128, 128));
100//!           // use below for compressed png
101//!           // EthBlockies::compressed_png_data(&seed, (128, 128));
102//!
103//!       // write data as png file
104//!       use std::io::Write;
105//!       std::fs::File::create("eth-blockies.png").unwrap()
106//!           .write_all(&eth_blockies_png_from_addr);
107//!   }
108//!   ```
109//!
110//!
111//! * Generate an html `img` blockies element, on wasm target
112//!   ```ignore
113//!   // addr to blockies data uri scheme,
114//!   // which can be used directly in img elem 'src' or css 'url()'
115//!   fn eth_blockies_data_uri(addr: &str) -> String {
116//!      use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
117//!
118//!      let addr_input = addr.to_ethaddr_seed();
119//!      let output_dim = (128, 128);
120//!      let data_uri_output = true;
121//!
122//!      EthBlockies::png_data_base64(
123//!         addr_input, output_dim, data_uri_output)
124//!   }
125//!
126//!   use web_sys::*;
127//!
128//!   let addr = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC";
129//!
130//!   window()
131//!      .and_then(|w| w.document())
132//!      .and_then(|doc| doc.body().zip(doc.create_element("img").ok()))
133//!      .and_then(|(body, img)| {
134//!         // create a new img html element with generated data_uri
135//!         img.set_attribute("src", &eth_blockies_data_uri(addr))
136//!            // then attach to body
137//!            .and_then(|_| body.append_child(&img))
138//!            .ok()
139//!      });
140//!   ```
141//!
142//!
143//! # Cargo Features
144//!
145//! * `compressed_png` (Enabled by default)
146//!   * This feature enables following functions:
147//!     * [`compressed_png_data()`](BlockiesGenerator::compressed_png_data)
148//!     * [`compressed_png_data_base64()`](BlockiesGenerator::compressed_png_data_base64)
149//!   * This feature adds a following external dependency:
150//!     * [`deflate`] crate
151//!   * If png compression is not needed,
152//!     disable this feature as follows when adding the crate:
153//!     * E.g.
154//!       * Shell: `cargo add eth-blockies@1.1 --no-default-features`
155//!       * Cargo.toml: `eth-blockies = { version = "1.1", default-features = false }`
156
157#![no_std]
158#![cfg_attr(docsrs, feature(doc_cfg))]
159
160mod blockies;
161pub use blockies::{Blockies, BlockiesHelper};
162mod global_type_helper;
163pub use global_type_helper::*;
164mod data_encoder;
165use data_encoder::*;
166
167extern crate alloc;
168use alloc::string::String;
169use alloc::vec::Vec;
170
171/// ( Alias of [`Blockies`]`<8, T>` ) Predefined [`Blockies`] for identicon of Ethereum address
172pub type EthBlockies<T> = Blockies<8, T>;
173
174/// Trait for generating a new [`Blockies`]
175///
176/// Used for generating data of a new blocky identicon in various form, including:
177/// * Raw blockies data
178/// * Terminal printable string (ANSI sequence)
179/// * Image file data (png)
180pub trait BlockiesGenerator<const S: usize> {
181    /// Generate an Ethereum-style blockies data
182    ///
183    /// # Arguments
184    ///
185    /// * `seed` - Input seed
186    ///
187    /// # Return
188    ///
189    /// * Blockies RGB data, in 2D [`RgbPixel`] array
190    ///
191    /// # Example
192    ///
193    /// * Generate RGB blockies data
194    ///
195    ///   * General identicon
196    ///   ```
197    ///   use eth_blockies::{Blockies, BlockiesGenerator};
198    ///   type Identicon<T> = Blockies<15, T>; // user-defined blockies type
199    ///
200    ///   // args
201    ///   let seed = "general string seed";
202    ///
203    ///   // generate blockies
204    ///   let icon_data_rgb = Blockies::<15>::data(seed);
205    ///   let icon_data_rgb_alias = Identicon::data(seed);
206    ///
207    ///   // test
208    ///   {
209    ///       assert_eq!(icon_data_rgb, icon_data_rgb_alias);
210    ///   }
211    ///   ```
212    ///
213    ///   * Ethereum blockies
214    ///   ```
215    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
216    ///
217    ///   // args
218    ///   let addr = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
219    ///       .to_ethaddr_seed();
220    ///
221    ///   // generate blockies
222    ///   let blockies_data_rgb = EthBlockies::data(addr);
223    ///
224    ///   // test
225    ///   {
226    ///       const P: eth_blockies::RgbPalette =
227    ///           [(38, 173, 52), (132, 222, 77), (4, 201, 40)];
228    ///
229    ///       assert_eq!(blockies_data_rgb, [
230    ///               [ P[1], P[1], P[1], P[1], P[1], P[1], P[1], P[1] ],
231    ///               [ P[1], P[0], P[0], P[2], P[2], P[0], P[0], P[1] ],
232    ///               [ P[2], P[1], P[1], P[0], P[0], P[1], P[1], P[2] ],
233    ///               [ P[0], P[0], P[2], P[0], P[0], P[2], P[0], P[0] ],
234    ///               [ P[1], P[0], P[1], P[2], P[2], P[1], P[0], P[1] ],
235    ///               [ P[1], P[2], P[1], P[2], P[2], P[1], P[2], P[1] ],
236    ///               [ P[0], P[2], P[1], P[2], P[2], P[1], P[2], P[0] ],
237    ///               [ P[1], P[0], P[0], P[1], P[1], P[0], P[0], P[1] ],
238    ///           ]);
239    ///   }
240    ///   ```
241    ///
242    fn data<I: SeedInput>(seed: I) -> Blockies<S, RgbPixel>;
243
244    /// Generate an Ethereum-style blockies data, mapping each RGB color with `map_fn`
245    ///
246    /// Same with [`BlockiesGenerator::data`],  
247    /// except that each [`RgbPixel`] output is mapped
248    /// with the function `map_fn` \(element mapping function\)
249    ///
250    /// # Arguments
251    ///
252    /// * `seed` - Input seed
253    /// * `map_fn` - Mapping function for each [`RgbPixel`] element in the returned array
254    ///
255    /// # Return
256    ///
257    /// * Mapped blockies data, in 2D `T` array  
258    ///   (`T`: type of each element returned by `map_fn`)
259    ///
260    /// # Example
261    ///
262    /// * Generate grayscale blockies data
263    ///
264    ///   * General identicon
265    ///   ```
266    ///   use eth_blockies::{Blockies, BlockiesGenerator};
267    ///   type Identicon<T> = Blockies<19, T>; // user-defined blockies type
268    ///
269    ///   // args
270    ///   let seed = "general string seed";
271    ///   fn to_gray((r, g, b): (u8, u8, u8)) -> u8 {
272    ///       (r as f64 * 0.299 + g as f64 * 0.587 + b as f64 * 0.114) as u8
273    ///   }
274    ///  
275    ///   // generate blockies
276    ///   let icon_data_gray = Blockies::<19>::data_mapped(seed, to_gray);
277    ///   let icon_data_gray_alias = Identicon::data_mapped(seed, to_gray);
278    ///
279    ///   // test
280    ///   {
281    ///       assert_eq!(icon_data_gray, icon_data_gray_alias);
282    ///   }
283    ///   ```
284    ///
285    ///   * Ethereum blockies
286    ///   ```
287    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
288    ///
289    ///   // args
290    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
291    ///       .to_ethaddr_seed();
292    ///   fn to_gray((r, g, b): (u8, u8, u8)) -> u8 {
293    ///       (r as f64 * 0.299 + g as f64 * 0.587 + b as f64 * 0.114) as u8
294    ///   }
295    ///
296    ///   // generate blockies
297    ///   let blockies_data_gray = EthBlockies::data_mapped(seed, to_gray);
298    ///
299    ///   // test
300    ///   {
301    ///       assert_eq!(blockies_data_gray, [
302    ///              [ 178, 178, 178, 178, 178, 178, 178, 178 ],
303    ///              [ 178, 118, 118, 123, 123, 118, 118, 178 ],
304    ///              [ 123, 178, 178, 118, 118, 178, 178, 123 ],
305    ///              [ 118, 118, 123, 118, 118, 123, 118, 118 ],
306    ///              [ 178, 118, 178, 123, 123, 178, 118, 178 ],
307    ///              [ 178, 123, 178, 123, 123, 178, 123, 178 ],
308    ///              [ 118, 123, 178, 123, 123, 178, 123, 118 ],
309    ///              [ 178, 118, 118, 178, 178, 118, 118, 178 ],
310    ///          ]);
311    ///   }
312    ///   ```
313    ///
314    fn data_mapped<I: SeedInput, T: Clone, F: Fn(RgbPixel) -> T>(
315        seed: I,
316        map_fn: F,
317    ) -> Blockies<S, T>;
318
319    /// Generate an Ethereum-style blockies data in indexed image format
320    ///
321    /// # Arguments
322    ///
323    /// * `seed` - Input seed
324    ///
325    /// # Return
326    ///
327    /// * A tuple of [(](tuple) `RgbPalette`, `Blockies<S, ColorClass>` [)](tuple)  
328    ///   * `RgbPalette`: Array of [`RgbPixel`]  
329    ///   * `Blockies<S, ColorClass>`: 2D array of palette indices
330    ///
331    /// # Example
332    ///
333    /// * Get RGB blockies data, composed of (RGB palette, palette indices for each element)
334    ///
335    ///   * General identicon
336    ///   ```
337    ///   use eth_blockies::{Blockies, BlockiesGenerator};
338    ///   type Identicon<T> = Blockies<6, T>; // user-defined blockies type
339    ///
340    ///   // args
341    ///   let seed = "general string seed";
342    ///
343    ///   // generate blockies
344    ///   let (rgb_palette, palette_idx_bitmap) =
345    ///       Blockies::<6>::indexed_data(seed);
346    ///   let (rgb_palette_alias, palette_idx_bitmap_alias) =
347    ///       Identicon::indexed_data(seed);
348    ///
349    ///   // test
350    ///   {
351    ///       assert_eq!(rgb_palette, rgb_palette_alias);
352    ///       assert_eq!(palette_idx_bitmap, palette_idx_bitmap_alias);
353    ///   }
354    ///   ```
355    ///
356    ///   * Ethereum blockies
357    ///   ```
358    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
359    ///
360    ///   // args
361    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
362    ///       .to_ethaddr_seed();
363    ///
364    ///   // generate blockies
365    ///   let (palette, palette_idx_bitmap) =
366    ///       EthBlockies::indexed_data(seed);
367    ///
368    ///   // test
369    ///   {
370    ///       use eth_blockies::ColorClass;
371    ///
372    ///       // get (r, g, b) from palette
373    ///       assert_eq!(palette[ColorClass::BgColor], (38, 173, 52));
374    ///       assert_eq!(palette[ColorClass::Color], (132, 222, 77));
375    ///       assert_eq!(palette[ColorClass::SpotColor], (4, 201, 40));
376    ///
377    ///       // get color class from pixels
378    ///       assert_eq!(palette_idx_bitmap[0][0], ColorClass::Color);
379    ///       assert_eq!(palette_idx_bitmap[2][0], ColorClass::SpotColor);
380    ///       assert_eq!(palette_idx_bitmap[1][1], ColorClass::BgColor);
381    ///
382    ///       // get (r, g, b) from pixels
383    ///       assert_eq!(palette[palette_idx_bitmap[0][0]], (132, 222, 77));
384    ///       assert_eq!(palette[palette_idx_bitmap[2][0]], (4, 201, 40));
385    ///       assert_eq!(palette[palette_idx_bitmap[1][1]], (38, 173, 52));
386    ///   }
387    ///   ```
388    ///
389    fn indexed_data<I: SeedInput>(seed: I) -> (RgbPalette, Blockies<S, ColorClass>);
390
391    /// Generate an Ethereum-style blockies data in indexed image format, mapping each RGB palette color with `map_fn`
392    ///
393    /// Same with [`BlockiesGenerator::indexed_data`],  
394    /// except that each [`RgbPixel`] output in [`Palette`] is mapped
395    /// with the function `map_fn` \(element mapping function\)
396    ///
397    /// # Arguments
398    ///
399    /// * `seed` - Input seed
400    /// * `map_fn` - Mapping function for each [`RgbPixel`] element in the returned array
401    ///
402    /// # Return
403    ///
404    /// * A tuple of [(](tuple) `Palette<T>`, `Blockies<S, ColorClass>` [)](tuple)  
405    ///   * `Palette<T>`: Array of `T` returned by `map_fn`  
406    ///   * `Blockies<S, ColorClass>`: 2D array of palette indices
407    ///
408    /// # Example
409    ///
410    /// * Get grayscale blockies data, composed of (grayscale palette, palette indices for each element)
411    ///
412    ///   * General identicon
413    ///   ```
414    ///   use eth_blockies::{Blockies, BlockiesGenerator};
415    ///   type Identicon<T> = Blockies<6, T>; // user-defined blockies type
416    ///
417    ///   // args
418    ///   let seed = "general string seed";
419    ///   fn to_gray((r, g, b): (u8, u8, u8)) -> u8 {
420    ///       (r as f64 * 0.299 + g as f64 * 0.587 + b as f64 * 0.114) as u8
421    ///   }
422    ///  
423    ///   // generate blockies
424    ///   let (gray_palette, palette_idx_bitmap) =
425    ///       Blockies::<6>::indexed_data_mapped(seed, to_gray);
426    ///   let (gray_palette_alias, palette_idx_bitmap_alias) =
427    ///       Identicon::indexed_data_mapped(seed, to_gray);
428    ///
429    ///   // test
430    ///   {
431    ///       assert_eq!(gray_palette, gray_palette_alias);
432    ///       assert_eq!(palette_idx_bitmap, palette_idx_bitmap_alias);
433    ///   }
434    ///   ```
435    ///
436    ///   * Ethereum blockies
437    ///   ```
438    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
439    ///
440    ///   // args
441    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
442    ///       .to_ethaddr_seed();
443    ///   fn to_gray((r, g, b): (u8, u8, u8)) -> u8 {
444    ///       (r as f64 * 0.299 + g as f64 * 0.587 + b as f64 * 0.114) as u8
445    ///   }
446    ///
447    ///   // generate blockies
448    ///   let (palette, palette_idx_bitmap) =
449    ///       EthBlockies::indexed_data_mapped(seed, to_gray);
450    ///
451    ///   // test
452    ///   {
453    ///       use eth_blockies::ColorClass;
454    ///
455    ///       // get grayscale value from palette
456    ///       assert_eq!(palette[ColorClass::BgColor], 118);
457    ///       assert_eq!(palette[ColorClass::Color], 178);
458    ///       assert_eq!(palette[ColorClass::SpotColor], 123);
459    ///
460    ///       // get color class from pixels
461    ///       assert_eq!(palette_idx_bitmap[0][0], ColorClass::Color);
462    ///       assert_eq!(palette_idx_bitmap[2][0], ColorClass::SpotColor);
463    ///       assert_eq!(palette_idx_bitmap[1][1], ColorClass::BgColor);
464    ///
465    ///       // get grayscale value from pixels
466    ///       assert_eq!(palette[palette_idx_bitmap[0][0]], 178);
467    ///       assert_eq!(palette[palette_idx_bitmap[2][0]], 123);
468    ///       assert_eq!(palette[palette_idx_bitmap[1][1]], 118);
469    ///   }
470    ///   ```
471    ///
472    fn indexed_data_mapped<I: SeedInput, T: Clone, F: Fn(RgbPixel) -> T>(
473        seed: I,
474        map_fn: F,
475    ) -> (Palette<T>, Blockies<S, ColorClass>);
476
477    /// Generate an Ethereum-style blockies data in ANSI sequence format (terminal-printable)
478    ///
479    /// # Arguments
480    ///
481    /// * `seed` - Input seed
482    /// * `output_dim` - (width, height) of output png binary data.
483    ///                  Multiples of `const S` ([`SIZE`](BlockiesHelper::SIZE)) recommended for both width and height.
484    /// * `is_utf8` - Determine whether to print using UTF-8 characters.
485    ///   * [`true`]: Output data contain UTF-8 characters,
486    ///     which makes blockies printed in compact size.
487    ///   * [`false`]: Output data do not contain any UTF-8 character,
488    ///     but its size is bigger as one unit block is represented as two spaces ('0x20').
489    ///
490    /// # Return
491    ///
492    /// * A vector of ANSI sequnce string. Each string in the vector represents each line.
493    ///
494    /// # Example
495    ///
496    /// * Get RGB blockies data in ANSI sequence for terminal output
497    ///
498    ///   * General identicon
499    ///   ```
500    ///   use eth_blockies::{Blockies, BlockiesGenerator};
501    ///   type Identicon<T> = Blockies<20, T>; // user-defined blockies type
502    ///
503    ///   // args
504    ///   let seed = "general string seed";
505    ///   let output_dim = (40, 40); // multiples of size recommended
506    ///   let is_utf8 = true; // if false, print in less-compact format
507    ///
508    ///   // generate blockies
509    ///   let icon_ansiseq_string_joined =
510    ///       Blockies::<20>::ansiseq_data(seed, output_dim, is_utf8)
511    ///       .join("\n");
512    ///   let icon_ansiseq_string_alias_joined =
513    ///       Identicon::ansiseq_data(seed, output_dim, is_utf8)
514    ///       .join("\n");
515    ///
516    ///   // test
517    ///   {
518    ///       assert_eq!(icon_ansiseq_string_joined,
519    ///                  icon_ansiseq_string_alias_joined);
520    ///
521    ///       println!("{}", icon_ansiseq_string_joined);
522    ///   }
523    ///   ```
524    ///
525    ///   * Ethereum blockies
526    ///   ```
527    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
528    ///
529    ///   // args
530    ///   let seed = "0xe686c14ff9c11038f2b1c9ad617f2346cfb817dc"
531    ///       .to_ethaddr_seed();
532    ///   let output_dim = (8, 8); // multiples of size recommended
533    ///   let is_utf8 = true; // if false, print in less-compact format
534    ///
535    ///   // generate blockies
536    ///   let ansi_string_joined = EthBlockies::ansiseq_data(
537    ///       seed, output_dim, is_utf8).join("\n");
538    ///
539    ///   // print
540    ///   {
541    ///       println!("{}", ansi_string_joined);
542    ///
543    ///       // print to terminal in different manner
544    ///       // use std::io::Write;
545    ///       // writeln!(std::io::stdout(), "{}", ansi_string_joined);
546    ///   }
547    ///   ```
548    fn ansiseq_data<I: SeedInput>(
549        seed: I,
550        output_dim: (usize, usize),
551        is_utf8: bool,
552    ) -> Vec<String>;
553
554    /// Generate an Ethereum-style blockies data in uncompressed indexed png format
555    ///
556    /// # Arguments
557    ///
558    /// * `seed` - Input seed
559    /// * `output_dim` - (width, height) of output png binary data.
560    ///                  Multiples of `const S` ([`SIZE`](BlockiesHelper::SIZE)) recommended for both width and height.
561    ///
562    /// # Return
563    ///
564    /// * A byte vector of png binary data
565    ///
566    /// # Example
567    ///
568    /// * Get uncompressed png data of RGB blockies
569    ///
570    ///   * General identicon
571    ///   ```
572    ///   use eth_blockies::{Blockies, BlockiesGenerator};
573    ///   type Identicon<T> = Blockies<11, T>; // user-defined blockies type
574    ///
575    ///   // args
576    ///   let seed = "general string seed";
577    ///   let output_dim = (64, 64); // multiples of size recommended
578    ///
579    ///   // generate blockies
580    ///   let icon_png_data = Blockies::<11>::png_data(seed, output_dim);
581    ///   let icon_png_data_alias = Identicon::png_data(seed, output_dim);
582    ///
583    ///   // test
584    ///   {
585    ///       assert_eq!(icon_png_data, icon_png_data_alias);
586    ///
587    ///       // uncomment below to write to file
588    ///       // use std::io::Write;
589    ///       // std::fs::File::create("icon.png").unwrap()
590    ///       //     .write_all(&icon_png_data);
591    ///   }
592    ///   ```
593    ///
594    ///   * Ethereum blockies
595    ///   ```
596    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
597    ///
598    ///   // args
599    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
600    ///       .to_ethaddr_seed();
601    ///   let output_dim = (16, 16); // multiples of size recommended
602    ///
603    ///   // generate blockies
604    ///   let img_png_data = EthBlockies::png_data(seed, output_dim);
605    ///
606    ///   // test
607    ///   {
608    ///       assert_eq!(img_png_data,
609    ///           b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\
610    ///             \x48\x44\x52\x00\x00\x00\x10\x00\x00\x00\x10\x02\x03\
611    ///             \x00\x00\x00\x62\x9d\x17\xf2\x00\x00\x00\x09\x50\x4c\
612    ///             \x54\x45\x26\xad\x34\x84\xde\x4d\x04\xc9\x28\xed\xf2\
613    ///             \x1a\xc2\x00\x00\x00\x5b\x49\x44\x41\x54\x78\x01\x01\
614    ///             \x50\x00\xaf\xff\x00\x55\x55\x55\x55\x00\x55\x55\x55\
615    ///             \x55\x00\x50\x0a\xa0\x05\x00\x50\x0a\xa0\x05\x00\xa5\
616    ///             \x50\x05\x5a\x00\xa5\x50\x05\x5a\x00\x00\xa0\x0a\x00\
617    ///             \x00\x00\xa0\x0a\x00\x00\x50\x5a\xa5\x05\x00\x50\x5a\
618    ///             \xa5\x05\x00\x5a\x5a\xa5\xa5\x00\x5a\x5a\xa5\xa5\x00\
619    ///             \x0a\x5a\xa5\xa0\x00\x0a\x5a\xa5\xa0\x00\x50\x05\x50\
620    ///             \x05\x00\x50\x05\x50\x05\x10\x15\x13\xed\x46\x70\x22\
621    ///             \x4a\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82");
622    ///
623    ///       // uncomment below to write to file
624    ///       // use std::io::Write;
625    ///       // std::fs::File::create("test.png").unwrap()
626    ///       //     .write_all(&img_png_data);
627    ///   }
628    ///   ```
629    fn png_data<I: SeedInput>(seed: I, output_dim: (usize, usize)) -> Vec<u8>;
630
631    /// Generate an Ethereum-style blockies data in compressed indexed png format
632    ///
633    /// # Arguments
634    ///
635    /// * `seed` - Input seed
636    /// * `output_dim` - (width, height) of output png binary data.
637    ///                  Multiples of `const S` ([`SIZE`](BlockiesHelper::SIZE)) recommended for both width and height.
638    ///
639    /// # Return
640    ///
641    /// * A byte vector of png binary data
642    ///
643    /// # Example
644    ///
645    /// * Get compressed png data of RGB blockies
646    ///
647    ///   * General identicon
648    ///   ```
649    ///   use eth_blockies::{Blockies, BlockiesGenerator};
650    ///   type Identicon<T> = Blockies<9, T>; // user-defined blockies type
651    ///
652    ///   // args
653    ///   let seed = "general string seed";
654    ///   let output_dim = (64, 64); // multiples of size recommended
655    ///
656    ///   // generate blockies
657    ///   let icon_compressed_png_data =
658    ///       Blockies::<9>::compressed_png_data(seed, output_dim);
659    ///   let icon_compressed_png_data_alias =
660    ///       Identicon::compressed_png_data(seed, output_dim);
661    ///
662    ///   // test
663    ///   {
664    ///       assert_eq!(icon_compressed_png_data,
665    ///                  icon_compressed_png_data_alias);
666    ///
667    ///       // uncomment below to write to file
668    ///       // use std::io::Write;
669    ///       // std::fs::File::create("icon.png").unwrap()
670    ///       //     .write_all(&icon_compressed_png_data);
671    ///   }
672    ///   ```
673    ///
674    ///   * Ethereum blockies
675    ///   ```
676    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
677    ///
678    ///   // args
679    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
680    ///       .to_ethaddr_seed();
681    ///   let output_dim = (16, 16); // multiples of size recommended
682    ///
683    ///   // generate blockies
684    ///   let img_png_data =
685    ///       EthBlockies::compressed_png_data(seed, output_dim);
686    ///
687    ///   // print
688    ///   {
689    ///       // uncomment below to write to file
690    ///       // use std::io::Write;
691    ///       // std::fs::File::create("test.png").unwrap()
692    ///       //     .write_all(&img_png_data);
693    ///   }
694    ///   ```
695    #[cfg(feature = "compressed_png")]
696    #[cfg_attr(docsrs, doc(cfg(feature = "compressed_png")))]
697    fn compressed_png_data<I: SeedInput>(seed: I, output_dim: (usize, usize)) -> Vec<u8>;
698
699    /// Generate an Ethereum-style blockies data in base64 format of uncompressed indexed png
700    ///
701    /// # Arguments
702    ///
703    /// * `seed` - Input seed
704    /// * `output_dim` - (width, height) of output png binary data.
705    ///                  Multiples of `const S` ([`SIZE`](BlockiesHelper::SIZE)) recommended for both width and height.
706    /// * `data_uri_output` - Determine if the result output is prefixed with data URI scheme
707    ///
708    /// # Return
709    ///
710    /// * A string of base64-encoded png data
711    ///
712    /// # Example
713    ///
714    /// * Get uncompressed png data of RGB blockies in base64 format
715    ///
716    ///   * General identicon
717    ///   ```
718    ///   use eth_blockies::{Blockies, BlockiesGenerator};
719    ///   type Identicon<T> = Blockies<7, T>; // user-defined blockies type
720    ///
721    ///   // args
722    ///   let seed = "general string seed";
723    ///   let output_dim = (64, 64); // multiples of size recommended
724    ///   let data_uri = false; // true: prepend "data:image/png;base64,"
725    ///
726    ///   // generate blockies
727    ///   let icon_png_data_base64_string =
728    ///       Blockies::<7>::png_data_base64(seed, output_dim, data_uri);
729    ///   let icon_png_data_base64_alias_string =
730    ///       Identicon::png_data_base64(seed, output_dim, data_uri);
731    ///
732    ///   // test
733    ///   {
734    ///       assert_eq!(icon_png_data_base64_string,
735    ///                  icon_png_data_base64_alias_string);
736    ///   }
737    ///   ```
738    ///
739    ///   * Ethereum blockies
740    ///   ```
741    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
742    ///
743    ///   // args
744    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
745    ///       .to_ethaddr_seed();
746    ///   let output_dim = (16, 16); // multiples of size recommended
747    ///
748    ///   // generate blockies
749    ///   {
750    ///       // base64 data only
751    ///       let data_uri = false;
752    ///       let img_png_data_base64_string =
753    ///           EthBlockies::png_data_base64(&seed, output_dim, data_uri);
754    ///
755    ///       // test
756    ///       assert_eq!(img_png_data_base64_string,
757    ///           "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEU\
758    ///            mrTSE3k0EySjt8hrCAAAAW0lEQVR4AQFQAK//AFVVVVUAVVVVVQBQCq\
759    ///            AFAFAKoAUApVAFWgClUAVaAACgCgAAAKAKAABQWqUFAFBapQUAWlqlp\
760    ///            QBaWqWlAApapaAAClqloABQBVAFAFAFUAUQFRPtRnAiSgAAAABJRU5E\
761    ///            rkJggg==");
762    ///   }
763    ///   {
764    ///       // base64 data with data uri scheme prefix
765    ///       let data_uri = true;
766    ///       let img_png_data_base64_uri_scheme_string =
767    ///           EthBlockies::png_data_base64(&seed, output_dim, data_uri);
768    ///
769    ///       // test
770    ///       assert_eq!(img_png_data_base64_uri_scheme_string,
771    ///           "data:image/png;base64,\
772    ///            iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEU\
773    ///            mrTSE3k0EySjt8hrCAAAAW0lEQVR4AQFQAK//AFVVVVUAVVVVVQBQCq\
774    ///            AFAFAKoAUApVAFWgClUAVaAACgCgAAAKAKAABQWqUFAFBapQUAWlqlp\
775    ///            QBaWqWlAApapaAAClqloABQBVAFAFAFUAUQFRPtRnAiSgAAAABJRU5E\
776    ///            rkJggg==");
777    ///   }
778    ///   ```
779    fn png_data_base64<I: SeedInput>(
780        seed: I,
781        output_dim: (usize, usize),
782        data_uri_output: bool,
783    ) -> String;
784
785    /// Generate an Ethereum-style blockies data in base64 format of compressed indexed png
786    ///
787    /// # Arguments
788    ///
789    /// * `seed` - Input seed
790    /// * `output_dim` - (width, height) of output png binary data.
791    ///                  Multiples of `const S` ([`SIZE`](BlockiesHelper::SIZE)) recommended for both width and height.
792    /// * `data_uri_output` - Determine if the result output is prefixed with data URI scheme
793    ///
794    /// # Return
795    ///
796    /// * A string of base64-encoded png data
797    ///
798    /// # Example
799    ///
800    /// * Get compressed png data of RGB blockies in base64 format
801    ///
802    ///   * General identicon
803    ///   ```
804    ///   use eth_blockies::{Blockies, BlockiesGenerator};
805    ///   type Identicon<T> = Blockies<12, T>; // user-defined blockies type
806    ///
807    ///   // args
808    ///   let seed = "general string seed";
809    ///   let output_dim = (64, 64); // multiples of size recommended
810    ///   let data_uri = false; // true: prepend "data:image/png;base64,"
811    ///
812    ///   // generate blockies
813    ///   let icon_png_data_base64_string =
814    ///       Blockies::<12>::compressed_png_data_base64(
815    ///           seed, output_dim, data_uri);
816    ///   let icon_png_data_base64_alias_string =
817    ///       Identicon::compressed_png_data_base64(
818    ///           seed, output_dim, data_uri);
819    ///
820    ///   // test
821    ///   {
822    ///       assert_eq!(icon_png_data_base64_string,
823    ///                  icon_png_data_base64_alias_string);
824    ///   }
825    ///   ```
826    ///
827    ///   * Ethereum blockies
828    ///   ```
829    ///   use eth_blockies::{EthBlockies, SeedInput, BlockiesGenerator};
830    ///
831    ///   // args
832    ///   let seed = "0xe686c14FF9C11038F2B1c9aD617F2346CFB817dC"
833    ///       .to_ethaddr_seed();
834    ///   let output_dim = (16, 16); // multiples of size recommended
835    ///
836    ///   // generate blockies
837    ///   {
838    ///       // base64 data only
839    ///       let data_uri_output = false;
840    ///       let img_png_data_base64_string =
841    ///           EthBlockies::compressed_png_data_base64(
842    ///               &seed, output_dim, data_uri_output);
843    ///   }
844    ///   {
845    ///       // base64 data with data uri scheme prefix
846    ///       let data_uri_output = true;
847    ///       let img_png_data_base64_uri_scheme_string =
848    ///           EthBlockies::compressed_png_data_base64(
849    ///               &seed, output_dim, data_uri_output);
850    ///   }
851    ///   ```
852    #[cfg(feature = "compressed_png")]
853    #[cfg_attr(docsrs, doc(cfg(feature = "compressed_png")))]
854    fn compressed_png_data_base64<I: SeedInput>(
855        seed: I,
856        output_dim: (usize, usize),
857        data_uri_output: bool,
858    ) -> String;
859}
860
861impl<const S: usize> BlockiesGenerator<S> for Blockies<S> {
862    fn data<I: SeedInput>(seed: I) -> Blockies<S, RgbPixel> {
863        Blockies::data_mapped(seed, |rgb_pixel| rgb_pixel)
864    }
865
866    fn data_mapped<I: SeedInput, T: Clone, F: Fn(RgbPixel) -> T>(
867        seed: I,
868        map_fn: F,
869    ) -> Blockies<S, T> {
870        let (palette, class_bitmap) = Blockies::indexed_data_mapped(seed, map_fn);
871
872        class_bitmap.map_2d(|class, _| palette[class].clone())
873    }
874
875    fn indexed_data<I: SeedInput>(seed: I) -> (RgbPalette, Blockies<S, ColorClass>) {
876        blockies::new_blockies(seed.as_seed_bytes())
877    }
878
879    fn indexed_data_mapped<I: SeedInput, T: Clone, F: Fn(RgbPixel) -> T>(
880        seed: I,
881        map_fn: F,
882    ) -> (Palette<T>, Blockies<S, ColorClass>) {
883        let (rgb_palette, class_bitmap) = Blockies::indexed_data(seed.as_seed_bytes());
884
885        (rgb_palette.map(map_fn), class_bitmap)
886    }
887
888    fn ansiseq_data<I: SeedInput>(
889        seed: I,
890        output_dim: (usize, usize),
891        is_utf8: bool,
892    ) -> Vec<String> {
893        let (palette, bitmap) = Blockies::<S>::indexed_data(seed);
894        match is_utf8 {
895            true => ansi_seq::indexed_data_to_ansiseq_utf8(
896                palette,
897                bitmap.scale(output_dim),
898                output_dim,
899            ),
900            false => ansi_seq::indexed_data_to_ansiseq_ascii(
901                palette,
902                bitmap.scale(output_dim),
903                output_dim,
904            ),
905        }
906    }
907
908    fn png_data<I: SeedInput>(seed: I, output_dim: (usize, usize)) -> Vec<u8> {
909        let (palette, bitmap) = Blockies::<S>::indexed_data(seed);
910        indexed_png::indexed_data_to_png(palette, bitmap.scale(output_dim), output_dim, false)
911    }
912
913    #[cfg(feature = "compressed_png")]
914    fn compressed_png_data<I: SeedInput>(seed: I, output_dim: (usize, usize)) -> Vec<u8> {
915        let (palette, bitmap) = Blockies::<S>::indexed_data(seed);
916        indexed_png::indexed_data_to_png(palette, bitmap.scale(output_dim), output_dim, true)
917    }
918
919    fn png_data_base64<I: SeedInput>(
920        seed: I,
921        output_dim: (usize, usize),
922        data_uri_output: bool,
923    ) -> String {
924        indexed_png::base64_wrapper(&Blockies::<S>::png_data(seed, output_dim), data_uri_output)
925    }
926
927    #[cfg(feature = "compressed_png")]
928    fn compressed_png_data_base64<I: SeedInput>(
929        seed: I,
930        output_dim: (usize, usize),
931        data_uri_output: bool,
932    ) -> String {
933        indexed_png::base64_wrapper(
934            &Blockies::<S>::compressed_png_data(seed, output_dim),
935            data_uri_output,
936        )
937    }
938}
939
940// deprecated functions from v1.0.0
941mod compat;
942pub use compat::*;