oxedyne/fe2o3/fe2o3_graphics/src/lib.rs
5.7 KiB, 49 runs
created by r1870400018:13940, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! A 2D graphics library: paths, affine transforms, an anti-aliased rasteriser, pixmaps with |
| 2 | //! alpha compositing, blur and drop shadows, and PNG and JPEG codecs. |
| 3 | //! |
| 4 | //! Painting is not geometry, which is why this crate sits beside `fe2o3_geom` rather than inside |
| 5 | //! it. `fe2o3_geom` serves integer layout, where a rectangle is a cell of a terminal or a widget |
| 6 | //! in a pane. Here a coordinate is a float, a shape is a path of lines and Bezier curves, and the |
| 7 | //! output is a buffer of pixels. |
| 8 | //! |
| 9 | //! The only third-party dependency is `flate2`, for the DEFLATE stream a PNG carries; the CRC-32 a |
| 10 | //! PNG chunk carries is small enough to own outright. Nothing in JPEG is a general-purpose |
| 11 | //! compressor that could sensibly be borrowed, so [`jpeg`] owns the whole of it -- Huffman coding, |
| 12 | //! the discrete cosine transform, chroma resampling and the colour transform alike. |
| 13 | //! |
| 14 | //! # Codecs |
| 15 | //! |
| 16 | //! [`png`] and [`jpeg`] present the same pair of functions over the same [`pixmap::Pixmap`], so a |
| 17 | //! caller that reads pictures need not care which it was handed. JPEG adds two entry points a |
| 18 | //! photograph library wants and PNG has no use for: a size probe that stops at the frame header, and |
| 19 | //! a decode at an eighth scale that reads one coefficient a block and never runs a transform. |
| 20 | //! |
| 21 | //! # Animation |
| 22 | //! |
| 23 | //! [`png::Animation`] writes a sequence of pixmaps as one APNG. Only the rectangle in which a frame |
| 24 | //! differs from the one before it is stored, so a drawing that moves one figure across a still |
| 25 | //! background costs the figure rather than the background, and the file's default image is its first |
| 26 | //! frame, so a reader that knows nothing of animation shows that frame and reports no error. It is |
| 27 | //! not a video codec: there is no motion estimation and no lossy transform, which makes it right for |
| 28 | //! line drawing, flat colour and text and wrong for a photographic sequence. |
| 29 | //! |
| 30 | //! # Containers |
| 31 | //! |
| 32 | //! [`heif`] reads the other side of the same box structure: a HEIC file's items, which of them is |
| 33 | //! the photograph, the grid of tiles it is cut into, where each tile's bytes are, and the Exif |
| 34 | //! block the camera wrote. Reading the container decodes nothing -- what it hands back is a run of |
| 35 | //! bytes and the decoder configuration that describes them -- and it was written before any HEVC |
| 36 | //! decoder existed, because the two things a photograph library needs first, the size and the Exif, |
| 37 | //! are in the container and not in the coded picture. [`heif::decode`] now carries the rest of the |
| 38 | //! way, through [`hevc`] and the assembly of the grid, to a picture. |
| 39 | //! |
| 40 | //! # A container, without a codec |
| 41 | //! |
| 42 | //! [`mp4`] writes an MP4 -- ISO base media file format boxes, a sample table and the media -- around |
| 43 | //! a video track it can neither encode nor decode. That is an odd thing for a graphics crate to |
| 44 | //! hold and it is deliberate: an H.264 encoder is months of rate control, motion estimation and |
| 45 | //! entropy coding at a quality the encoder already in the caller's browser or silicon reaches |
| 46 | //! anyway, while a container is a few hundred lines of length-prefixed boxes with no compression in |
| 47 | //! it, and it is the part that describes the caller's own frames and their timing. So the caller |
| 48 | //! encodes and hands the samples and the decoder configuration over, and gets back a file. |
| 49 | //! |
| 50 | //! # The rasteriser |
| 51 | //! |
| 52 | //! [`raster`] accumulates the signed area each edge contributes to each pixel, then takes a prefix |
| 53 | //! sum along every row. This gives exact analytic anti-aliasing, with no supersampling, for a path |
| 54 | //! whose contours do not overlap, and either the non-zero winding rule or the even-odd rule where |
| 55 | //! they do. Non-zero is the default, and is what glyph outlines and filled boxes both want. |
| 56 | //! |
| 57 | //! # Stroking |
| 58 | //! |
| 59 | //! [`stroke`] adds no rasteriser code at all, because a stroke is only the fill of a different |
| 60 | //! shape: the region the pen sweeps as it travels the path. It builds that region as a [`path::Path`] |
| 61 | //! and hands it back to the filler. |
| 62 | //! |
| 63 | //! # Blurring |
| 64 | //! |
| 65 | //! [`blur`] adds none either. Three passes of a sliding box, along each axis, stand in for a |
| 66 | //! Gaussian to within a few percent, at a cost that is the same whatever the radius. A drop shadow |
| 67 | //! is then only a silhouette filled into a scratch pixmap, blurred, and composited back. The blur |
| 68 | //! runs on premultiplied alpha, without which the colour of the clear pixels a shape is blurred |
| 69 | //! against would bleed into it and fringe it with dirt. |
| 70 | //! |
| 71 | //! # SVG path data |
| 72 | //! |
| 73 | //! [`svg`] reads the `d` attribute of an SVG `<path>` -- and writes it back -- and only that. Path |
| 74 | //! data is a small closed grammar and the one part every drawing program agrees on, so it is where a |
| 75 | //! vector mark drawn elsewhere can be let in, or handed back out, without letting in a document |
| 76 | //! format. Elliptical arcs, which the path types have no segment for, become cubic béziers on the |
| 77 | //! way in. The paint a [`stroke::Stroke`] and an [`colour::Rgba`] model is rendered as a `<path>`'s |
| 78 | //! presentation attributes beside its geometry. |
| 79 | //! |
| 80 | //! # Colour and accessibility |
| 81 | //! |
| 82 | //! [`colour`] carries `Rgba` and its compositing, and beside it the WCAG relative luminance and |
| 83 | //! contrast ratio a design is checked for legibility against, and a simulation of the three |
| 84 | //! dichromacies for checking that a palette does not lean on a colour distinction a |
| 85 | //! colour-blind viewer cannot see. |
| 86 | //! |
| 87 | //! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\ |
| 88 | //! Anthropic Claude |
| 89 | #![forbid(unsafe_code)] |
| 90 | |
| 91 | pub mod avi; |
| 92 | pub mod blur; |
| 93 | pub mod colour; |
| 94 | pub mod h264; |
| 95 | pub mod heif; |
| 96 | pub mod hevc; |
| 97 | pub mod jpeg; |
| 98 | pub mod matroska; |
| 99 | pub mod mp4; |
| 100 | pub mod path; |
| 101 | pub mod pdf; |
| 102 | pub mod pdf_font; |
| 103 | pub mod pixmap; |
| 104 | pub mod png; |
| 105 | pub mod prelude; |
| 106 | pub mod qr; |
| 107 | pub mod raster; |
| 108 | pub mod stroke; |
| 109 | pub mod svg; |
| 110 | pub mod svg_doc; |
| 111 | pub mod transform; |
| 112 | pub mod yuv; |