Refactor matricizer, fix some linter complaints
* Matricizer.choose_dimensions was not actually being used. It has been
removed, and dimensions of the hash matrix are now determined
internally by the matricizer, rather than in its constructor.
* Linter was complaining about missing documentation and some other
minor styling things so those are fixed
* Linter had a few more stupid lints enabled ("too-many-statements"?
really? god forbid your code is too long, I'm not a computer science
student, come on guys)
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -438,7 +438,9 @@ disable=raw-checker-failed,
|
|||||||
use-implicit-booleaness-not-comparison-to-zero,
|
use-implicit-booleaness-not-comparison-to-zero,
|
||||||
too-many-locals,
|
too-many-locals,
|
||||||
too-few-public-methods,
|
too-few-public-methods,
|
||||||
line-too-long
|
too-many-statements,
|
||||||
|
line-too-long,
|
||||||
|
redefined-builtin,
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
# either give multiple identifier separated by comma (,) or put this option
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
|||||||
@@ -7,12 +7,10 @@ import textwrap
|
|||||||
|
|
||||||
from .color import colorize
|
from .color import colorize
|
||||||
from .matricizer import Matricizer, NibbleMatricizer, RandomartMatricizer
|
from .matricizer import Matricizer, NibbleMatricizer, RandomartMatricizer
|
||||||
from .palettes import Palette, DEFAULT_PALETTES, PALETTES
|
from .palettes import Palette, PALETTES
|
||||||
from .writer import ANSIWriter, SVGWriter, Writer
|
from .writer import ANSIWriter, SVGWriter, Writer
|
||||||
|
|
||||||
|
|
||||||
# TODO - WASM compile for embedding directly in HTML
|
|
||||||
# - this may not be an option, sadly. might have to just port it to JS
|
|
||||||
# TODO - option to add a caption based on the filename (for SVG)
|
# TODO - option to add a caption based on the filename (for SVG)
|
||||||
# TODO - load palettes from a file
|
# TODO - load palettes from a file
|
||||||
# TODO - PNG output
|
# TODO - PNG output
|
||||||
@@ -36,11 +34,13 @@ def cli_main() -> None:
|
|||||||
PALETTE_HELP = "\n".join(
|
PALETTE_HELP = "\n".join(
|
||||||
[
|
[
|
||||||
"PALETTE CHOICES",
|
"PALETTE CHOICES",
|
||||||
'\n'.join(textwrap.wrap(
|
"\n".join(
|
||||||
|
textwrap.wrap(
|
||||||
", ".join(PALETTE_CHOICES),
|
", ".join(PALETTE_CHOICES),
|
||||||
initial_indent=" ",
|
initial_indent=" ",
|
||||||
subsequent_indent=" ",
|
subsequent_indent=" ",
|
||||||
)),
|
)
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
HASH_CHOICES = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]
|
HASH_CHOICES = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]
|
||||||
@@ -59,7 +59,9 @@ def cli_main() -> None:
|
|||||||
OUTPUT_TYPE_HELP = "OUTPUT TYPE (-y, --output-type)\n" + "\n".join(
|
OUTPUT_TYPE_HELP = "OUTPUT TYPE (-y, --output-type)\n" + "\n".join(
|
||||||
[f" {choice} - {desc}" for choice, desc in OUTPUT_TYPE_CHOICES.items()]
|
[f" {choice} - {desc}" for choice, desc in OUTPUT_TYPE_CHOICES.items()]
|
||||||
)
|
)
|
||||||
EPILOGUE = "\n\n".join([MATRIX_HELP, PALETTE_HELP, INPUT_TYPE_HELP, OUTPUT_TYPE_HELP])
|
EPILOGUE = "\n\n".join(
|
||||||
|
[MATRIX_HELP, PALETTE_HELP, INPUT_TYPE_HELP, OUTPUT_TYPE_HELP]
|
||||||
|
)
|
||||||
|
|
||||||
progname: str = sys.argv[0]
|
progname: str = sys.argv[0]
|
||||||
if progname.endswith("__main__.py"):
|
if progname.endswith("__main__.py"):
|
||||||
@@ -175,13 +177,9 @@ def cli_main() -> None:
|
|||||||
matricizer: Matricizer
|
matricizer: Matricizer
|
||||||
match args.matrix:
|
match args.matrix:
|
||||||
case "nibble":
|
case "nibble":
|
||||||
w, h = NibbleMatricizer.DIMENSIONS[args.hash]
|
matricizer = NibbleMatricizer()
|
||||||
matricizer = NibbleMatricizer(w, h)
|
|
||||||
case "randomart":
|
case "randomart":
|
||||||
# 17x9 is what openssh uses
|
matricizer = RandomartMatricizer()
|
||||||
# TODO - allow configuring dimensions, maybe
|
|
||||||
w, h = RandomartMatricizer.DIMENSIONS[args.hash]
|
|
||||||
matricizer = RandomartMatricizer(w, h)
|
|
||||||
case _:
|
case _:
|
||||||
assert False, f"invalid args.matrix: {args.matrix}"
|
assert False, f"invalid args.matrix: {args.matrix}"
|
||||||
|
|
||||||
@@ -210,4 +208,3 @@ def cli_main() -> None:
|
|||||||
sys.stdout.write(output)
|
sys.stdout.write(output)
|
||||||
else:
|
else:
|
||||||
args.out.write_text(output)
|
args.out.write_text(output)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"All things that turn a hash into a matrix."
|
"All things that turn a hash into a matrix."
|
||||||
import abc
|
import abc
|
||||||
|
import re
|
||||||
from typing import Mapping, Sequence
|
from typing import Mapping, Sequence
|
||||||
|
|
||||||
from .palettes import Palette, DEFAULT_PALETTES, GRADIENT_PALETTES, MULTICOLOR_PALETTES
|
from .palettes import Palette, DEFAULT_PALETTES, GRADIENT_PALETTES, MULTICOLOR_PALETTES
|
||||||
@@ -8,6 +9,27 @@ from .palettes import Palette, DEFAULT_PALETTES, GRADIENT_PALETTES, MULTICOLOR_P
|
|||||||
Matrix = Sequence[Sequence[int]]
|
Matrix = Sequence[Sequence[int]]
|
||||||
|
|
||||||
|
|
||||||
|
def detect_hash_algorithm(hash_or_algo: str | bytes) -> str | None:
|
||||||
|
dimensions: Mapping[int, str] = {
|
||||||
|
32: "md5",
|
||||||
|
40: "sha1",
|
||||||
|
56: "sha224",
|
||||||
|
64: "sha256",
|
||||||
|
96: "sha384",
|
||||||
|
128: "sha512",
|
||||||
|
}
|
||||||
|
if isinstance(hash_or_algo, bytes):
|
||||||
|
return dimensions.get(len(hash_or_algo) * 2)
|
||||||
|
|
||||||
|
hoa = hash_or_algo.lower()
|
||||||
|
if re.match(r"^([0-9a-fA-F]{2})+$", hoa):
|
||||||
|
return dimensions.get(len(hoa))
|
||||||
|
elif hoa in list(dimensions.values()):
|
||||||
|
return hoa
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Matricizer(metaclass=abc.ABCMeta):
|
class Matricizer(metaclass=abc.ABCMeta):
|
||||||
"""
|
"""
|
||||||
The base Matricizer class.
|
The base Matricizer class.
|
||||||
@@ -16,16 +38,6 @@ class Matricizer(metaclass=abc.ABCMeta):
|
|||||||
(inclusive). The method by which this is done is up to the matricizer.
|
(inclusive). The method by which this is done is up to the matricizer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, w: int, h: int) -> None:
|
|
||||||
"""
|
|
||||||
Create a new matricizer for the given dimensions.
|
|
||||||
|
|
||||||
:param w: the width of the output matrix.
|
|
||||||
:param h: the height of hte output matrix.
|
|
||||||
"""
|
|
||||||
self.w = w
|
|
||||||
self.h = h
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def matricize(self, data: bytes) -> Matrix:
|
def matricize(self, data: bytes) -> Matrix:
|
||||||
"""
|
"""
|
||||||
@@ -35,16 +47,6 @@ class Matricizer(metaclass=abc.ABCMeta):
|
|||||||
:returns: the matrix converted from the hash data.
|
:returns: the matrix converted from the hash data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@abc.abstractmethod
|
|
||||||
def choose_dimensions(hash: str) -> tuple[int, int]:
|
|
||||||
"""
|
|
||||||
Choose the dimensions for this matrix based on the hash algorithm.
|
|
||||||
|
|
||||||
:param hash: the hash algorithm being used.
|
|
||||||
:returns: a width and height as a tuple.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def choose_palette(
|
def choose_palette(
|
||||||
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
||||||
) -> Palette:
|
) -> Palette:
|
||||||
@@ -84,32 +86,31 @@ class NibbleMatricizer(Matricizer):
|
|||||||
:returns: the matrix converted from the hash data.
|
:returns: the matrix converted from the hash data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
algo = detect_hash_algorithm(data)
|
||||||
|
w, h = self.DIMENSIONS[algo]
|
||||||
|
|
||||||
nibbles = []
|
nibbles = []
|
||||||
for b in data:
|
for b in data:
|
||||||
top = (b & 0xF0) >> 4
|
top = (b & 0xF0) >> 4
|
||||||
bottom = b & 0x0F
|
bottom = b & 0x0F
|
||||||
nibbles += [top, bottom]
|
nibbles += [top, bottom]
|
||||||
|
|
||||||
if len(nibbles) != self.w * self.h:
|
if len(nibbles) != w * h:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"input data length ({len(nibbles)}) must match matrix dimensions "
|
f"input data length ({len(nibbles)}) must match matrix dimensions "
|
||||||
f"({self.w}x{self.h} = {self.w * self.h})"
|
f"({w}x{h} = {w * h})"
|
||||||
)
|
)
|
||||||
|
|
||||||
cols = []
|
cols = []
|
||||||
row = []
|
row = []
|
||||||
for b in nibbles:
|
for b in nibbles:
|
||||||
row += [b]
|
row += [b]
|
||||||
if len(row) == self.w:
|
if len(row) == w:
|
||||||
cols += [row]
|
cols += [row]
|
||||||
row = []
|
row = []
|
||||||
|
|
||||||
return cols
|
return cols
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def choose_dimensions(hash: str) -> tuple[int, int]:
|
|
||||||
return NibbleMatricizer.DIMENSIONS[hash]
|
|
||||||
|
|
||||||
def choose_palette(
|
def choose_palette(
|
||||||
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
||||||
) -> Palette:
|
) -> Palette:
|
||||||
@@ -150,10 +151,12 @@ class RandomartMatricizer(Matricizer):
|
|||||||
:param data: the hash data to turn into a matrix.
|
:param data: the hash data to turn into a matrix.
|
||||||
:returns: the matrix converted from the hash data.
|
:returns: the matrix converted from the hash data.
|
||||||
"""
|
"""
|
||||||
|
algo = detect_hash_algorithm(data)
|
||||||
|
w, h = self.DIMENSIONS[algo]
|
||||||
|
|
||||||
rows = [[0] * self.w for _ in range(self.h)]
|
rows = [[0] * w for _ in range(h)]
|
||||||
c = self.w // 2
|
c = w // 2
|
||||||
r = self.h // 2
|
r = h // 2
|
||||||
for value in data:
|
for value in data:
|
||||||
for _ in range(4):
|
for _ in range(4):
|
||||||
if value & 0x1:
|
if value & 0x1:
|
||||||
@@ -164,18 +167,14 @@ class RandomartMatricizer(Matricizer):
|
|||||||
r += 1
|
r += 1
|
||||||
else:
|
else:
|
||||||
r -= 1
|
r -= 1
|
||||||
c = min(max(c, 0), self.w - 1)
|
c = min(max(c, 0), w - 1)
|
||||||
r = min(max(r, 0), self.h - 1)
|
r = min(max(r, 0), h - 1)
|
||||||
# max value is 0xf
|
# max value is 0xf
|
||||||
if rows[r][c] < 0xF:
|
if rows[r][c] < 0xF:
|
||||||
rows[r][c] += 1
|
rows[r][c] += 1
|
||||||
value >>= 2;
|
value >>= 2
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def choose_dimensions(hash: str) -> tuple[int, int]:
|
|
||||||
return RandomartMatricizer.DIMENSIONS[hash]
|
|
||||||
|
|
||||||
def choose_palette(
|
def choose_palette(
|
||||||
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
self, data: bytes, palettes: Mapping[str, Palette] | None = None
|
||||||
) -> Palette:
|
) -> Palette:
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
"Base color palette definitions."
|
"Base color palette definitions."
|
||||||
import abc
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from .color import Color, HSLColor
|
from .color import Color, HSLColor
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
"Colorhash writer classes"
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
from .color import Color, ColorMatrix
|
from .color import Color, ColorMatrix
|
||||||
@@ -13,30 +14,47 @@ class Writer(metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def write(self, matrix: ColorMatrix) -> str:
|
def write(self, matrix: ColorMatrix) -> str:
|
||||||
"Write the color matrix to a string."
|
"""
|
||||||
|
Write the color matrix to a string.
|
||||||
|
|
||||||
|
:param matrix: the color matrix to generate the SVG for.
|
||||||
|
:returns: the full generated SVG as a string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ANSIWriter(Writer):
|
class ANSIWriter(Writer):
|
||||||
|
"""
|
||||||
|
ANSI terminal writer. This will output a 24-bit true color string.
|
||||||
|
"""
|
||||||
def write(self, matrix: ColorMatrix) -> str:
|
def write(self, matrix: ColorMatrix) -> str:
|
||||||
ESC = "\x1b"
|
"""
|
||||||
RESET = f"{ESC}[0m"
|
Write the color matrix to an ANSI string.
|
||||||
C = "██"
|
|
||||||
|
:param matrix: the color matrix to generate the SVG for.
|
||||||
|
:returns: the full generated SVG as a string.
|
||||||
|
"""
|
||||||
|
esc = "\x1b"
|
||||||
|
reset = f"{esc}[0m"
|
||||||
|
c = "██"
|
||||||
|
|
||||||
def ansi_color(c: Color) -> str:
|
def ansi_color(c: Color) -> str:
|
||||||
c = c.to_rgb()
|
c = c.to_rgb()
|
||||||
return f"{ESC}[38;2;{round(c.r)};{round(c.g)};{round(c.b)}m"
|
return f"{esc}[38;2;{round(c.r)};{round(c.g)};{round(c.b)}m"
|
||||||
|
|
||||||
out = ""
|
out = ""
|
||||||
for row in matrix:
|
for row in matrix:
|
||||||
for col in row:
|
for col in row:
|
||||||
out += ansi_color(col)
|
out += ansi_color(col)
|
||||||
out += C
|
out += c
|
||||||
out += "\n"
|
out += "\n"
|
||||||
out += RESET
|
out += reset
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
class SVGWriter(Writer):
|
class SVGWriter(Writer):
|
||||||
|
"""
|
||||||
|
SVG string writer.
|
||||||
|
"""
|
||||||
def __init__(self, square_size: int) -> None:
|
def __init__(self, square_size: int) -> None:
|
||||||
"""
|
"""
|
||||||
Create a new SVG writer that uses the given square size.
|
Create a new SVG writer that uses the given square size.
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
<svg width="256" height="160" xmlns="http://www.w3.org/2000/svg">
|
<svg width="256" height="160" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect x="0" y="0" width="32" height="32" fill="hsl(60.00,100.00%,40.00%)" />
|
<rect x="0" y="0" width="32" height="32" fill="hsl(30.00,100.00%,6.67%)" />
|
||||||
<rect x="32" y="0" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="32" y="0" width="32" height="32" fill="hsl(30.00,100.00%,36.67%)" />
|
||||||
<rect x="64" y="0" width="32" height="32" fill="hsl(60.00,100.00%,6.67%)" />
|
<rect x="64" y="0" width="32" height="32" fill="hsl(30.00,100.00%,10.00%)" />
|
||||||
<rect x="96" y="0" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="96" y="0" width="32" height="32" fill="hsl(30.00,100.00%,0.00%)" />
|
||||||
<rect x="128" y="0" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="128" y="0" width="32" height="32" fill="hsl(30.00,100.00%,0.00%)" />
|
||||||
<rect x="160" y="0" width="32" height="32" fill="hsl(60.00,100.00%,13.33%)" />
|
<rect x="160" y="0" width="32" height="32" fill="hsl(30.00,100.00%,23.33%)" />
|
||||||
<rect x="192" y="0" width="32" height="32" fill="hsl(60.00,100.00%,40.00%)" />
|
<rect x="192" y="0" width="32" height="32" fill="hsl(30.00,100.00%,0.00%)" />
|
||||||
<rect x="224" y="0" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="224" y="0" width="32" height="32" fill="hsl(30.00,100.00%,26.67%)" />
|
||||||
<rect x="0" y="32" width="32" height="32" fill="hsl(60.00,100.00%,10.00%)" />
|
<rect x="0" y="32" width="32" height="32" fill="hsl(30.00,100.00%,16.67%)" />
|
||||||
<rect x="32" y="32" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="32" y="32" width="32" height="32" fill="hsl(30.00,100.00%,3.33%)" />
|
||||||
<rect x="64" y="32" width="32" height="32" fill="hsl(60.00,100.00%,16.67%)" />
|
<rect x="64" y="32" width="32" height="32" fill="hsl(30.00,100.00%,30.00%)" />
|
||||||
<rect x="96" y="32" width="32" height="32" fill="hsl(60.00,100.00%,6.67%)" />
|
<rect x="96" y="32" width="32" height="32" fill="hsl(30.00,100.00%,36.67%)" />
|
||||||
<rect x="128" y="32" width="32" height="32" fill="hsl(60.00,100.00%,3.33%)" />
|
<rect x="128" y="32" width="32" height="32" fill="hsl(30.00,100.00%,10.00%)" />
|
||||||
<rect x="160" y="32" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="160" y="32" width="32" height="32" fill="hsl(30.00,100.00%,36.67%)" />
|
||||||
<rect x="192" y="32" width="32" height="32" fill="hsl(60.00,100.00%,43.33%)" />
|
<rect x="192" y="32" width="32" height="32" fill="hsl(30.00,100.00%,33.33%)" />
|
||||||
<rect x="224" y="32" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="224" y="32" width="32" height="32" fill="hsl(30.00,100.00%,3.33%)" />
|
||||||
<rect x="0" y="64" width="32" height="32" fill="hsl(60.00,100.00%,23.33%)" />
|
<rect x="0" y="64" width="32" height="32" fill="hsl(30.00,100.00%,26.67%)" />
|
||||||
<rect x="32" y="64" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="32" y="64" width="32" height="32" fill="hsl(30.00,100.00%,20.00%)" />
|
||||||
<rect x="64" y="64" width="32" height="32" fill="hsl(60.00,100.00%,3.33%)" />
|
<rect x="64" y="64" width="32" height="32" fill="hsl(30.00,100.00%,43.33%)" />
|
||||||
<rect x="96" y="64" width="32" height="32" fill="hsl(60.00,100.00%,43.33%)" />
|
<rect x="96" y="64" width="32" height="32" fill="hsl(30.00,100.00%,6.67%)" />
|
||||||
<rect x="128" y="64" width="32" height="32" fill="hsl(60.00,100.00%,33.33%)" />
|
<rect x="128" y="64" width="32" height="32" fill="hsl(30.00,100.00%,3.33%)" />
|
||||||
<rect x="160" y="64" width="32" height="32" fill="hsl(60.00,100.00%,30.00%)" />
|
<rect x="160" y="64" width="32" height="32" fill="hsl(30.00,100.00%,13.33%)" />
|
||||||
<rect x="192" y="64" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="192" y="64" width="32" height="32" fill="hsl(30.00,100.00%,3.33%)" />
|
||||||
<rect x="224" y="64" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="224" y="64" width="32" height="32" fill="hsl(30.00,100.00%,50.00%)" />
|
||||||
<rect x="0" y="96" width="32" height="32" fill="hsl(60.00,100.00%,50.00%)" />
|
<rect x="0" y="96" width="32" height="32" fill="hsl(30.00,100.00%,10.00%)" />
|
||||||
<rect x="32" y="96" width="32" height="32" fill="hsl(60.00,100.00%,10.00%)" />
|
<rect x="32" y="96" width="32" height="32" fill="hsl(30.00,100.00%,23.33%)" />
|
||||||
<rect x="64" y="96" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="64" y="96" width="32" height="32" fill="hsl(30.00,100.00%,0.00%)" />
|
||||||
<rect x="96" y="96" width="32" height="32" fill="hsl(60.00,100.00%,40.00%)" />
|
<rect x="96" y="96" width="32" height="32" fill="hsl(30.00,100.00%,23.33%)" />
|
||||||
<rect x="128" y="96" width="32" height="32" fill="hsl(60.00,100.00%,40.00%)" />
|
<rect x="128" y="96" width="32" height="32" fill="hsl(30.00,100.00%,43.33%)" />
|
||||||
<rect x="160" y="96" width="32" height="32" fill="hsl(60.00,100.00%,3.33%)" />
|
<rect x="160" y="96" width="32" height="32" fill="hsl(30.00,100.00%,13.33%)" />
|
||||||
<rect x="192" y="96" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="192" y="96" width="32" height="32" fill="hsl(30.00,100.00%,16.67%)" />
|
||||||
<rect x="224" y="96" width="32" height="32" fill="hsl(60.00,100.00%,30.00%)" />
|
<rect x="224" y="96" width="32" height="32" fill="hsl(30.00,100.00%,6.67%)" />
|
||||||
<rect x="0" y="128" width="32" height="32" fill="hsl(60.00,100.00%,36.67%)" />
|
<rect x="0" y="128" width="32" height="32" fill="hsl(30.00,100.00%,3.33%)" />
|
||||||
<rect x="32" y="128" width="32" height="32" fill="hsl(60.00,100.00%,16.67%)" />
|
<rect x="32" y="128" width="32" height="32" fill="hsl(30.00,100.00%,50.00%)" />
|
||||||
<rect x="64" y="128" width="32" height="32" fill="hsl(60.00,100.00%,26.67%)" />
|
<rect x="64" y="128" width="32" height="32" fill="hsl(30.00,100.00%,16.67%)" />
|
||||||
<rect x="96" y="128" width="32" height="32" fill="hsl(60.00,100.00%,20.00%)" />
|
<rect x="96" y="128" width="32" height="32" fill="hsl(30.00,100.00%,30.00%)" />
|
||||||
<rect x="128" y="128" width="32" height="32" fill="hsl(60.00,100.00%,16.67%)" />
|
<rect x="128" y="128" width="32" height="32" fill="hsl(30.00,100.00%,10.00%)" />
|
||||||
<rect x="160" y="128" width="32" height="32" fill="hsl(60.00,100.00%,50.00%)" />
|
<rect x="160" y="128" width="32" height="32" fill="hsl(30.00,100.00%,16.67%)" />
|
||||||
<rect x="192" y="128" width="32" height="32" fill="hsl(60.00,100.00%,43.33%)" />
|
<rect x="192" y="128" width="32" height="32" fill="hsl(30.00,100.00%,13.33%)" />
|
||||||
<rect x="224" y="128" width="32" height="32" fill="hsl(60.00,100.00%,0.00%)" />
|
<rect x="224" y="128" width="32" height="32" fill="hsl(30.00,100.00%,36.67%)" />
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Reference in New Issue
Block a user