diff --git a/Cargo.lock b/Cargo.lock
index 1c515b40b..a78ca088f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -805,6 +805,7 @@ dependencies = [
"signal-hook-registry",
"smallvec",
"structopt",
+ "svg",
"termion",
"toml",
"unicode-segmentation",
@@ -1613,6 +1614,12 @@ dependencies = [
"syn",
]
+[[package]]
+name = "svg"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b65a64d32a41db2a8081aa03c1ccca26f246ff681add693f8b01307b137da79"
+
[[package]]
name = "syn"
version = "1.0.30"
diff --git a/Cargo.toml b/Cargo.toml
index eca68f9c7..f26581ef6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -50,6 +50,7 @@ smallvec = { version = "1.1.0", features = ["serde", ] }
bitflags = "1.0"
pcre2 = { version = "0.2.3", optional = true }
structopt = { version = "0.3.14", default-features = false }
+svg_crate = { version = "0.8.0", optional = true, package = "svg" }
[profile.release]
@@ -67,6 +68,7 @@ jmap = ["melib/jmap_backend",]
sqlite3 = ["melib/sqlite3"]
regexp = ["pcre2"]
cli-docs = []
+svgscreenshot = ["svg_crate"]
# Print tracing logs as meli runs in stderr
# enable for debug tracing logs: build with --features=debug-tracing
diff --git a/src/bin.rs b/src/bin.rs
index 3e32379d1..c9e1cedb2 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -323,6 +323,8 @@ fn run_app(opt: Opt) -> Result<()> {
state.register_component(Box::new(EnvelopeView::new(wrapper, None, None, 0)));
} else {
state = State::new(None, sender, receiver.clone())?;
+ #[cfg(feature = "svgscreenshot")]
+ state.register_component(Box::new(components::svg::SVGScreenshotFilter::new()));
let window = Box::new(Tabbed::new(
vec![
Box::new(listing::Listing::new(&mut state.context)),
diff --git a/src/components.rs b/src/components.rs
index e0ad87a79..8ec0085d5 100644
--- a/src/components.rs
+++ b/src/components.rs
@@ -40,6 +40,9 @@ pub use self::utilities::*;
pub mod contacts;
pub use crate::contacts::*;
+#[cfg(feature = "svgscreenshot")]
+pub mod svg;
+
use std::fmt;
use std::fmt::{Debug, Display};
diff --git a/src/components/svg.rs b/src/components/svg.rs
new file mode 100644
index 000000000..e7a490887
--- /dev/null
+++ b/src/components/svg.rs
@@ -0,0 +1,645 @@
+/*
+ * meli - svg screenshot
+ *
+ * Copyright Manos Pitsidianakis
+ *
+ * This file is part of meli.
+ *
+ * meli is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * meli is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with meli. If not, see .
+ */
+use super::*;
+use std::io::Write;
+
+#[derive(Debug)]
+pub struct SVGScreenshotFilter {
+ save_screenshot: bool,
+}
+
+impl fmt::Display for SVGScreenshotFilter {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "svg screenshot filter")
+ }
+}
+
+impl SVGScreenshotFilter {
+ pub fn new() -> Self {
+ SVGScreenshotFilter {
+ save_screenshot: false,
+ }
+ }
+}
+
+impl Component for SVGScreenshotFilter {
+ fn draw(&mut self, _grid: &mut CellBuffer, _area: Area, context: &mut Context) {
+ if !self.save_screenshot {
+ return;
+ }
+ self.save_screenshot = false;
+ let grid: &CellBuffer = _grid;
+ use svg_crate::node::element::{Definitions, Group, Rectangle, Style, Text, Use};
+ use svg_crate::node::Text as TextNode;
+ use svg_crate::Document;
+
+ let (width, height) = grid.size();
+ /*
+ * Format frame as follows:
+ * - The entire background is a big rectangle.
+ * - Every text piece with unified foreground color is a text element inserted into the
+ * `definitions` field of the svg, and then `use`ed as a reference
+ * - Every background piece (a slice of unified backgrund color) is a rectangle element
+ * inserted along with the `use` elements
+ *
+ * Each row is arbritarily set at 17px high, and each character cell is 8 pixels wide.
+ * Rectangle cells each have one extra pixel (so 18px * 9px) in their dimensions in order
+ * to cover the spacing between cells.
+ */
+ let mut definitions = Definitions::new();
+ let mut rows_group = Group::new();
+ let mut text = String::with_capacity(width);
+ for (row_idx, row) in grid.bounds_iter(((0, 0), (width, height))).enumerate() {
+ text.clear();
+ let mut row_group = Group::new().set("id", format!("g{}", row_idx + 1));
+ let mut cur_fg = Color::Default;
+ let mut cur_bg = Color::Default;
+ let mut cur_attrs = Attr::DEFAULT;
+ let mut prev_x_fg = 0;
+ let mut is_start = true;
+ let mut prev_x_bg = 0;
+ for (x, c) in row.enumerate() {
+ if cur_bg != grid[c].bg() || cur_fg != grid[c].fg() || cur_attrs != grid[c].attrs()
+ {
+ if cur_bg != Color::Default {
+ let mut rect = Rectangle::new()
+ .set("x", prev_x_bg * 8)
+ .set("y", 17 * row_idx)
+ .set("width", (x - prev_x_bg) * 8 + 1)
+ .set("bgname", format!("{:?}", cur_bg))
+ .set("height", 18);
+ match cur_bg {
+ Color::Rgb(r, g, b) => {
+ rect = rect
+ .set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ Color::Default => {
+ unreachable!();
+ }
+ c if c.as_byte() < 16 => {
+ rect = rect.set("class", format!("color{}", c.as_byte()).as_str());
+ }
+ c => {
+ let c = c.as_byte();
+ let (r, g, b) = XTERM_COLORS[c as usize];
+ rect = rect
+ .set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ }
+ rows_group = rows_group.add(rect);
+ }
+ prev_x_bg = x;
+ cur_bg = grid[c].bg();
+ if !text.is_empty() {
+ let text_length = text.split_graphemes().len();
+ let mut text_el = Text::new()
+ .add(TextNode::new(&text))
+ .set("x", prev_x_fg * 8)
+ .set("textLength", text_length * 8)
+ .set("fgname", format!("{:?}", cur_fg));
+ if cur_attrs.intersects(Attr::BOLD) {
+ text_el = text_el.set("font-weight", "bold");
+ }
+ if cur_attrs.intersects(Attr::ITALICS) {
+ text_el = text_el.set("font-style", "italic");
+ }
+ if cur_attrs.intersects(Attr::UNDERLINE) {
+ text_el = text_el.set("text-decoration", "underline");
+ }
+ if cur_attrs.intersects(Attr::DIM) {
+ text_el = text_el.set("font-weight", "lighter");
+ }
+ if cur_attrs.intersects(Attr::HIDDEN) {
+ text_el = text_el.set("display", "none");
+ }
+ match cur_fg {
+ Color::Default if cur_attrs.intersects(Attr::REVERSE) => {
+ text_el = text_el.set("class", "background");
+ }
+ Color::Default => {
+ text_el = text_el.set("class", "foreground");
+ }
+ Color::Rgb(r, g, b) => {
+ text_el = text_el
+ .set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ c if c.as_byte() < 16 => {
+ text_el =
+ text_el.set("class", format!("color{}", c.as_byte()).as_str());
+ }
+ c => {
+ let c = c.as_byte();
+ let (r, g, b) = XTERM_COLORS[c as usize];
+ text_el = text_el
+ .set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ };
+ row_group = row_group.add(text_el);
+ text.clear();
+ }
+ prev_x_fg = x;
+ cur_fg = grid[c].fg();
+ cur_attrs = grid[c].attrs();
+ }
+ match grid[c].ch() {
+ '"' => text.push_str("""),
+ '&' => text.push_str("&"),
+ '\'' => text.push_str("'"),
+ '<' => text.push_str("<"),
+ '>' => text.push_str(">"),
+ ' ' if is_start => {
+ prev_x_fg = x + 1;
+ }
+ c => text.push(c),
+ }
+ if grid[c].ch() != ' ' {
+ is_start = false;
+ }
+ }
+ if cur_bg != Color::Default {
+ let mut rect = Rectangle::new()
+ .set("x", prev_x_bg * 8)
+ .set("y", 17 * row_idx)
+ .set("width", (width - prev_x_bg) * 8 + 1)
+ .set("bgname", format!("{:?}", cur_bg))
+ .set("height", 18);
+ match cur_bg {
+ Color::Rgb(r, g, b) => {
+ rect = rect.set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ Color::Default => {
+ unreachable!();
+ }
+ c if c.as_byte() < 16 => {
+ rect = rect.set("class", format!("color{}", c.as_byte()).as_str());
+ }
+ c => {
+ let c = c.as_byte();
+ let (r, g, b) = XTERM_COLORS[c as usize];
+ rect = rect.set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ }
+ rows_group = rows_group.add(rect);
+ }
+ if !text.is_empty() {
+ let text_length = text.split_graphemes().len();
+ let mut text_el = Text::new()
+ .add(TextNode::new(&text))
+ .set("x", prev_x_fg * 8)
+ .set("textLength", text_length * 8)
+ .set("fgname", format!("{:?}", cur_fg));
+ if cur_attrs.intersects(Attr::BOLD) {
+ text_el = text_el.set("font-weight", "bold");
+ }
+ if cur_attrs.intersects(Attr::ITALICS) {
+ text_el = text_el.set("font-style", "italic");
+ }
+ if cur_attrs.intersects(Attr::UNDERLINE) {
+ text_el = text_el.set("text-decoration", "underline");
+ }
+ if cur_attrs.intersects(Attr::DIM) {
+ text_el = text_el.set("font-weight", "lighter");
+ }
+ if cur_attrs.intersects(Attr::HIDDEN) {
+ text_el = text_el.set("display", "none");
+ }
+ match cur_fg {
+ Color::Default if cur_attrs.intersects(Attr::REVERSE) => {
+ text_el = text_el.set("class", "background");
+ }
+ Color::Default => {
+ text_el = text_el.set("class", "foreground");
+ }
+ Color::Rgb(r, g, b) => {
+ text_el =
+ text_el.set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ c if c.as_byte() < 16 => {
+ text_el = text_el.set("class", format!("color{}", c.as_byte()).as_str());
+ }
+ c => {
+ let c = c.as_byte();
+ let (r, g, b) = XTERM_COLORS[c as usize];
+ text_el =
+ text_el.set("fill", format!("#{:02x}{:02x}{:02x}", r, g, b).as_str());
+ }
+ }
+ row_group = row_group.add(text_el);
+ text.clear();
+ }
+ definitions = definitions.add(row_group);
+ rows_group = rows_group.add(
+ Use::new()
+ .set("xlink:href", format!("#g{}", row_idx + 1))
+ .set("y", 17 * row_idx),
+ );
+ }
+ let document = Document::new()
+ .set("viewBox", (0, 0, width * 8, height * 17 + 2))
+ .set("width", width * 8)
+ .set("height", height * 17 + 2)
+ .add(
+ Definitions::new().add(
+ Style::new(CSS_STYLE)
+ .set("id", "generated-style")
+ .set("type", "text/css"),
+ ),
+ )
+ .add(
+ Document::new()
+ .set("id", "terminal")
+ .set("preserveAspectRatio", "xMidYMin slice")
+ .set("viewBox", (0, 0, width * 8, height * 17))
+ .set("width", width * 8)
+ .set("height", height * 17)
+ .add(
+ Rectangle::new()
+ .set("class", "background")
+ .set("height", "100%")
+ .set("width", "100%")
+ .set("x", 0)
+ .set("y", 0),
+ )
+ .add(definitions)
+ .add(rows_group),
+ )
+ .set("xmlns", "http://www.w3.org/2000/svg")
+ .set("baseProfile", "full")
+ .set("xmlns:xlink", "http://www.w3.org/1999/xlink")
+ .set("version", "1.1");
+
+ let mut s = Vec::new();
+ svg_crate::write(&mut s, &document).unwrap();
+ let mut res = Vec::new();
+ /*
+ * svg crate formats text nodes like this:
+ *
+ *
+ * actual content
+ *
+ *
+ * But we don't want any extra newlines before/after the tags:
+ *
+ * actual content
+ *
+ * So remove all new lines from SVG file.
+ */
+ for b in s {
+ if b == b'\n' {
+ continue;
+ }
+ res.push(b);
+ }
+ let mut filename = melib::datetime::timestamp_to_string(
+ melib::datetime::now(),
+ Some("meli Screenshot - %e %h %Y %H:%M:%S.svg"),
+ );
+ while std::path::Path::new(&filename).exists() {
+ filename.pop();
+ filename.pop();
+ filename.pop();
+ filename.pop();
+ filename.push_str("_.svg");
+ }
+ std::fs::File::create(&filename)
+ .unwrap()
+ .write_all(&res)
+ .unwrap();
+ context.replies.push_back(UIEvent::Notification(
+ Some("Screenshot saved".into()),
+ format!("Screenshot saved to {}", filename),
+ None,
+ ));
+ }
+ fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool {
+ if let UIEvent::Input(Key::F(6)) = event {
+ self.save_screenshot = true;
+ true
+ } else if let UIEvent::ExInput(Key::F(6)) = event {
+ self.save_screenshot = true;
+ true
+ } else if let UIEvent::EmbedInput((Key::F(6), _)) = event {
+ self.save_screenshot = true;
+ false
+ } else {
+ false
+ }
+ }
+ fn set_dirty(&mut self, _value: bool) {}
+
+ fn is_dirty(&self) -> bool {
+ self.save_screenshot
+ }
+
+ fn id(&self) -> ComponentId {
+ ComponentId::nil()
+ }
+ fn set_id(&mut self, _id: ComponentId) {}
+}
+
+const CSS_STYLE: &'static str = r#"#terminal {
+ font-family: 'DejaVu Sans Mono', monospace;
+ font-style: normal;
+ font-size: 14px;
+}
+
+text {
+ dominant-baseline: text-before-edge;
+ white-space: pre;
+}
+/* The colors defined below are the default 16 colors used for rendering text of the terminal. Adjust them as needed. xterm colors based on https://en.wikipedia.org/wiki/ANSI_escape_code#Colors */
+.foreground {fill: #e5e5e5;}
+.background {fill: #000000;}
+.color0 {fill: #000000;}
+.color1 {fill: #cd0000;}
+.color2 {fill: #00cd00;}
+.color3 {fill: #cdcd00;}
+.color4 {fill: #0000ee;}
+.color5 {fill: #cd00cd;}
+.color6 {fill: #00cdcd;}
+.color7 {fill: #e5e5e5;}
+.color8 {fill: #7f7f7f;}
+.color9 {fill: #ff0000;}
+.color10 {fill: #00ff00;}
+.color11 {fill: #ffff00;}
+.color12 {fill: #5c5cff;}
+.color13 {fill: #ff00ff;}
+.color14 {fill: #00ffff;}
+.color15 {fill: #ffffff;}"#;
+
+const XTERM_COLORS: &'static [(u8, u8, u8)] = &[
+ /*0*/ (0, 0, 0),
+ /*1*/ (128, 0, 0),
+ /*2*/ (0, 128, 0),
+ /*3*/ (128, 128, 0),
+ /*4*/ (0, 0, 128),
+ /*5*/ (128, 0, 128),
+ /*6*/ (0, 128, 128),
+ /*7*/ (192, 192, 192),
+ /*8*/ (128, 128, 128),
+ /*9*/ (255, 0, 0),
+ /*10*/ (0, 255, 0),
+ /*11*/ (255, 255, 0),
+ /*12*/ (0, 0, 255),
+ /*13*/ (255, 0, 255),
+ /*14*/ (0, 255, 255),
+ /*15*/ (255, 255, 255),
+ /*16*/ (0, 0, 0),
+ /*17*/ (0, 0, 95),
+ /*18*/ (0, 0, 135),
+ /*19*/ (0, 0, 175),
+ /*20*/ (0, 0, 215),
+ /*21*/ (0, 0, 255),
+ /*22*/ (0, 95, 0),
+ /*23*/ (0, 95, 95),
+ /*24*/ (0, 95, 135),
+ /*25*/ (0, 95, 175),
+ /*26*/ (0, 95, 215),
+ /*27*/ (0, 95, 255),
+ /*28*/ (0, 135, 0),
+ /*29*/ (0, 135, 95),
+ /*30*/ (0, 135, 135),
+ /*31*/ (0, 135, 175),
+ /*32*/ (0, 135, 215),
+ /*33*/ (0, 135, 255),
+ /*34*/ (0, 175, 0),
+ /*35*/ (0, 175, 95),
+ /*36*/ (0, 175, 135),
+ /*37*/ (0, 175, 175),
+ /*38*/ (0, 175, 215),
+ /*39*/ (0, 175, 255),
+ /*40*/ (0, 215, 0),
+ /*41*/ (0, 215, 95),
+ /*42*/ (0, 215, 135),
+ /*43*/ (0, 215, 175),
+ /*44*/ (0, 215, 215),
+ /*45*/ (0, 215, 255),
+ /*46*/ (0, 255, 0),
+ /*47*/ (0, 255, 95),
+ /*48*/ (0, 255, 135),
+ /*49*/ (0, 255, 175),
+ /*50*/ (0, 255, 215),
+ /*51*/ (0, 255, 255),
+ /*52*/ (95, 0, 0),
+ /*53*/ (95, 0, 95),
+ /*54*/ (95, 0, 135),
+ /*55*/ (95, 0, 175),
+ /*56*/ (95, 0, 215),
+ /*57*/ (95, 0, 255),
+ /*58*/ (95, 95, 0),
+ /*59*/ (95, 95, 95),
+ /*60*/ (95, 95, 135),
+ /*61*/ (95, 95, 175),
+ /*62*/ (95, 95, 215),
+ /*63*/ (95, 95, 255),
+ /*64*/ (95, 135, 0),
+ /*65*/ (95, 135, 95),
+ /*66*/ (95, 135, 135),
+ /*67*/ (95, 135, 175),
+ /*68*/ (95, 135, 215),
+ /*69*/ (95, 135, 255),
+ /*70*/ (95, 175, 0),
+ /*71*/ (95, 175, 95),
+ /*72*/ (95, 175, 135),
+ /*73*/ (95, 175, 175),
+ /*74*/ (95, 175, 215),
+ /*75*/ (95, 175, 255),
+ /*76*/ (95, 215, 0),
+ /*77*/ (95, 215, 95),
+ /*78*/ (95, 215, 135),
+ /*79*/ (95, 215, 175),
+ /*80*/ (95, 215, 215),
+ /*81*/ (95, 215, 255),
+ /*82*/ (95, 255, 0),
+ /*83*/ (95, 255, 95),
+ /*84*/ (95, 255, 135),
+ /*85*/ (95, 255, 175),
+ /*86*/ (95, 255, 215),
+ /*87*/ (95, 255, 255),
+ /*88*/ (135, 0, 0),
+ /*89*/ (135, 0, 95),
+ /*90*/ (135, 0, 135),
+ /*91*/ (135, 0, 175),
+ /*92*/ (135, 0, 215),
+ /*93*/ (135, 0, 255),
+ /*94*/ (135, 95, 0),
+ /*95*/ (135, 95, 95),
+ /*96*/ (135, 95, 135),
+ /*97*/ (135, 95, 175),
+ /*98*/ (135, 95, 215),
+ /*99*/ (135, 95, 255),
+ /*100*/ (135, 135, 0),
+ /*101*/ (135, 135, 95),
+ /*102*/ (135, 135, 135),
+ /*103*/ (135, 135, 175),
+ /*104*/ (135, 135, 215),
+ /*105*/ (135, 135, 255),
+ /*106*/ (135, 175, 0),
+ /*107*/ (135, 175, 95),
+ /*108*/ (135, 175, 135),
+ /*109*/ (135, 175, 175),
+ /*110*/ (135, 175, 215),
+ /*111*/ (135, 175, 255),
+ /*112*/ (135, 215, 0),
+ /*113*/ (135, 215, 95),
+ /*114*/ (135, 215, 135),
+ /*115*/ (135, 215, 175),
+ /*116*/ (135, 215, 215),
+ /*117*/ (135, 215, 255),
+ /*118*/ (135, 255, 0),
+ /*119*/ (135, 255, 95),
+ /*120*/ (135, 255, 135),
+ /*121*/ (135, 255, 175),
+ /*122*/ (135, 255, 215),
+ /*123*/ (135, 255, 255),
+ /*124*/ (175, 0, 0),
+ /*125*/ (175, 0, 95),
+ /*126*/ (175, 0, 135),
+ /*127*/ (175, 0, 175),
+ /*128*/ (175, 0, 215),
+ /*129*/ (175, 0, 255),
+ /*130*/ (175, 95, 0),
+ /*131*/ (175, 95, 95),
+ /*132*/ (175, 95, 135),
+ /*133*/ (175, 95, 175),
+ /*134*/ (175, 95, 215),
+ /*135*/ (175, 95, 255),
+ /*136*/ (175, 135, 0),
+ /*137*/ (175, 135, 95),
+ /*138*/ (175, 135, 135),
+ /*139*/ (175, 135, 175),
+ /*140*/ (175, 135, 215),
+ /*141*/ (175, 135, 255),
+ /*142*/ (175, 175, 0),
+ /*143*/ (175, 175, 95),
+ /*144*/ (175, 175, 135),
+ /*145*/ (175, 175, 175),
+ /*146*/ (175, 175, 215),
+ /*147*/ (175, 175, 255),
+ /*148*/ (175, 215, 0),
+ /*149*/ (175, 215, 95),
+ /*150*/ (175, 215, 135),
+ /*151*/ (175, 215, 175),
+ /*152*/ (175, 215, 215),
+ /*153*/ (175, 215, 255),
+ /*154*/ (175, 255, 0),
+ /*155*/ (175, 255, 95),
+ /*156*/ (175, 255, 135),
+ /*157*/ (175, 255, 175),
+ /*158*/ (175, 255, 215),
+ /*159*/ (175, 255, 255),
+ /*160*/ (215, 0, 0),
+ /*161*/ (215, 0, 95),
+ /*162*/ (215, 0, 135),
+ /*163*/ (215, 0, 175),
+ /*164*/ (215, 0, 215),
+ /*165*/ (215, 0, 255),
+ /*166*/ (215, 95, 0),
+ /*167*/ (215, 95, 95),
+ /*168*/ (215, 95, 135),
+ /*169*/ (215, 95, 175),
+ /*170*/ (215, 95, 215),
+ /*171*/ (215, 95, 255),
+ /*172*/ (215, 135, 0),
+ /*173*/ (215, 135, 95),
+ /*174*/ (215, 135, 135),
+ /*175*/ (215, 135, 175),
+ /*176*/ (215, 135, 215),
+ /*177*/ (215, 135, 255),
+ /*178*/ (215, 175, 0),
+ /*179*/ (215, 175, 95),
+ /*180*/ (215, 175, 135),
+ /*181*/ (215, 175, 175),
+ /*182*/ (215, 175, 215),
+ /*183*/ (215, 175, 255),
+ /*184*/ (215, 215, 0),
+ /*185*/ (215, 215, 95),
+ /*186*/ (215, 215, 135),
+ /*187*/ (215, 215, 175),
+ /*188*/ (215, 215, 215),
+ /*189*/ (215, 215, 255),
+ /*190*/ (215, 255, 0),
+ /*191*/ (215, 255, 95),
+ /*192*/ (215, 255, 135),
+ /*193*/ (215, 255, 175),
+ /*194*/ (215, 255, 215),
+ /*195*/ (215, 255, 255),
+ /*196*/ (255, 0, 0),
+ /*197*/ (255, 0, 95),
+ /*198*/ (255, 0, 135),
+ /*199*/ (255, 0, 175),
+ /*200*/ (255, 0, 215),
+ /*201*/ (255, 0, 255),
+ /*202*/ (255, 95, 0),
+ /*203*/ (255, 95, 95),
+ /*204*/ (255, 95, 135),
+ /*205*/ (255, 95, 175),
+ /*206*/ (255, 95, 215),
+ /*207*/ (255, 95, 255),
+ /*208*/ (255, 135, 0),
+ /*209*/ (255, 135, 95),
+ /*210*/ (255, 135, 135),
+ /*211*/ (255, 135, 175),
+ /*212*/ (255, 135, 215),
+ /*213*/ (255, 135, 255),
+ /*214*/ (255, 175, 0),
+ /*215*/ (255, 175, 95),
+ /*216*/ (255, 175, 135),
+ /*217*/ (255, 175, 175),
+ /*218*/ (255, 175, 215),
+ /*219*/ (255, 175, 255),
+ /*220*/ (255, 215, 0),
+ /*221*/ (255, 215, 95),
+ /*222*/ (255, 215, 135),
+ /*223*/ (255, 215, 175),
+ /*224*/ (255, 215, 215),
+ /*225*/ (255, 215, 255),
+ /*226*/ (255, 255, 0),
+ /*227*/ (255, 255, 95),
+ /*228*/ (255, 255, 135),
+ /*229*/ (255, 255, 175),
+ /*230*/ (255, 255, 215),
+ /*231*/ (255, 255, 255),
+ /*232*/ (8, 8, 8),
+ /*233*/ (18, 18, 18),
+ /*234*/ (28, 28, 28),
+ /*235*/ (38, 38, 38),
+ /*236*/ (48, 48, 48),
+ /*237*/ (58, 58, 58),
+ /*238*/ (68, 68, 68),
+ /*239*/ (78, 78, 78),
+ /*240*/ (88, 88, 88),
+ /*241*/ (98, 98, 98),
+ /*242*/ (108, 108, 108),
+ /*243*/ (118, 118, 118),
+ /*244*/ (128, 128, 128),
+ /*245*/ (138, 138, 138),
+ /*246*/ (148, 148, 148),
+ /*247*/ (158, 158, 158),
+ /*248*/ (168, 168, 168),
+ /*249*/ (178, 178, 178),
+ /*250*/ (188, 188, 188),
+ /*251*/ (198, 198, 198),
+ /*252*/ (208, 208, 208),
+ /*253*/ (218, 218, 218),
+ /*254*/ (228, 228, 228),
+ /*255*/ (238, 238, 238),
+];