/src/serenity/Userland/Libraries/LibGfx/ImageFormats/TinyVGLoader.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, MacDue <macdue@dueutil.tech> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Forward.h> |
10 | | #include <AK/OwnPtr.h> |
11 | | #include <AK/Variant.h> |
12 | | #include <AK/Vector.h> |
13 | | #include <LibGfx/Color.h> |
14 | | #include <LibGfx/Forward.h> |
15 | | #include <LibGfx/ImageFormats/ImageDecoder.h> |
16 | | #include <LibGfx/PaintStyle.h> |
17 | | #include <LibGfx/Path.h> |
18 | | #include <LibGfx/VectorGraphic.h> |
19 | | |
20 | | namespace Gfx { |
21 | | |
22 | | // Current recommended SVG to TVG conversion (without installing tools) |
23 | | // (FIXME: Implement our own converter!) |
24 | | // 1. (Optional) Convert strokes to fills |
25 | | // * Only round joins/linecaps exist in TVG, so for other stroke kinds converting |
26 | | // them to fills (that still beziers etc, so are scalable) works better. |
27 | | // * This site can do that: https://iconly.io/tools/svg-convert-stroke-to-fill |
28 | | // 2. Scale your SVG's width/height to large size (e.g. 1024x?) |
29 | | // * Current converters deal poorly with small values in paths. |
30 | | // * This site can do that: https://www.iloveimg.com/resize-image/resize-svg |
31 | | // (or just edit the viewbox if it has one). |
32 | | // 3. Convert the SVG to a TVG |
33 | | // * This site can do that: https://svg-to-tvg-server.fly.dev/ |
34 | | |
35 | | // Decoder from the "Tiny Vector Graphics" format (v1.0). |
36 | | // https://tinyvg.tech/download/specification.pdf |
37 | | |
38 | | struct TinyVGHeader; |
39 | | |
40 | | class TinyVGDecodedImageData final : public VectorGraphic { |
41 | | public: |
42 | | using Style = Variant<Color, NonnullRefPtr<SVGGradientPaintStyle>>; |
43 | | |
44 | | struct DrawCommand { |
45 | | Path path; |
46 | | Optional<Style> fill {}; |
47 | | Optional<Style> stroke {}; |
48 | | float stroke_width { 0.0f }; |
49 | | }; |
50 | | |
51 | | virtual IntSize intrinsic_size() const override |
52 | 831 | { |
53 | 831 | return m_size; |
54 | 831 | } |
55 | | |
56 | | virtual void draw_transformed(Painter&, AffineTransform) const override; |
57 | | |
58 | | ReadonlySpan<DrawCommand> draw_commands() const |
59 | 414 | { |
60 | 414 | return m_draw_commands; |
61 | 414 | } |
62 | | |
63 | | static ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> decode(Stream& stream); |
64 | | static ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> decode(Stream& stream, TinyVGHeader const& header); |
65 | | |
66 | | private: |
67 | | TinyVGDecodedImageData(IntSize size, Vector<DrawCommand> draw_commands) |
68 | 417 | : m_size(size) |
69 | 417 | , m_draw_commands(move(draw_commands)) |
70 | 417 | { |
71 | 417 | } |
72 | | |
73 | | IntSize m_size; |
74 | | Vector<DrawCommand> m_draw_commands; |
75 | | }; |
76 | | |
77 | | struct TinyVGLoadingContext; |
78 | | |
79 | | class TinyVGImageDecoderPlugin final : public ImageDecoderPlugin { |
80 | | public: |
81 | | static bool sniff(ReadonlyBytes); |
82 | | static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes); |
83 | | |
84 | | virtual IntSize size() override; |
85 | | virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override; |
86 | | |
87 | 0 | virtual NaturalFrameFormat natural_frame_format() const override { return NaturalFrameFormat::Vector; } |
88 | | virtual ErrorOr<VectorImageFrameDescriptor> vector_frame(size_t index) override; |
89 | | |
90 | | virtual ~TinyVGImageDecoderPlugin() override; |
91 | | |
92 | | private: |
93 | | TinyVGImageDecoderPlugin(ReadonlyBytes); |
94 | | |
95 | | NonnullOwnPtr<TinyVGLoadingContext> m_context; |
96 | | }; |
97 | | |
98 | | } |