From a4fac2271b32d6926869acd857663fbff03edb06 Mon Sep 17 00:00:00 2001 From: taylorswift Date: Tue, 20 Feb 2024 23:53:09 +0000 Subject: [PATCH] update chunk type documentation --- Sources/PNG/Formats/PNG.Format.Pixel.swift | 267 ++++++ Sources/PNG/Formats/PNG.Format.swift | 551 +++++++++++ Sources/PNG/Formats/PNG.FormattingError.swift | 37 + Sources/PNG/{ => Formats}/PNG.Layout.swift | 0 Sources/PNG/Parsing/PNG.Background.Case.swift | 30 + Sources/PNG/Parsing/PNG.Background.swift | 84 +- Sources/PNG/Parsing/PNG.Chromaticity.swift | 58 +- Sources/PNG/Parsing/PNG.ColorProfile.swift | 29 +- Sources/PNG/Parsing/PNG.ColorRendering.swift | 38 +- Sources/PNG/Parsing/PNG.Format.swift | 905 ------------------ Sources/PNG/Parsing/PNG.FormattingError.swift | 53 - Sources/PNG/Parsing/PNG.Gamma.swift | 25 +- Sources/PNG/Parsing/PNG.Header.swift | 41 +- Sources/PNG/Parsing/PNG.Histogram.swift | 35 +- Sources/PNG/Parsing/PNG.Palette.swift | 35 +- Sources/PNG/Parsing/PNG.ParsingError.swift | 332 +++---- Sources/PNG/Parsing/PNG.Percentmille.swift | 59 +- .../PNG/Parsing/PNG.PhysicalDimensions.swift | 39 +- .../Parsing/PNG.SignificantBits.Case.swift | 55 ++ Sources/PNG/Parsing/PNG.SignificantBits.swift | 93 +- .../PNG.SuggestedPalette.Entries.swift | 16 + .../PNG/Parsing/PNG.SuggestedPalette.swift | 49 +- Sources/PNG/Parsing/PNG.Text.swift | 63 +- Sources/PNG/Parsing/PNG.TimeModified.swift | 73 +- .../PNG/Parsing/PNG.Transparency.Case.swift | 36 + Sources/PNG/Parsing/PNG.Transparency.swift | 90 +- 26 files changed, 1327 insertions(+), 1766 deletions(-) create mode 100644 Sources/PNG/Formats/PNG.Format.Pixel.swift create mode 100644 Sources/PNG/Formats/PNG.Format.swift create mode 100644 Sources/PNG/Formats/PNG.FormattingError.swift rename Sources/PNG/{ => Formats}/PNG.Layout.swift (100%) create mode 100644 Sources/PNG/Parsing/PNG.Background.Case.swift delete mode 100644 Sources/PNG/Parsing/PNG.Format.swift delete mode 100644 Sources/PNG/Parsing/PNG.FormattingError.swift create mode 100644 Sources/PNG/Parsing/PNG.SignificantBits.Case.swift create mode 100644 Sources/PNG/Parsing/PNG.SuggestedPalette.Entries.swift create mode 100644 Sources/PNG/Parsing/PNG.Transparency.Case.swift diff --git a/Sources/PNG/Formats/PNG.Format.Pixel.swift b/Sources/PNG/Formats/PNG.Format.Pixel.swift new file mode 100644 index 00000000..f4e86ae1 --- /dev/null +++ b/Sources/PNG/Formats/PNG.Format.Pixel.swift @@ -0,0 +1,267 @@ +extension PNG.Format +{ + /// A pixel format. + /// + /// A pixel format specifies the color model and bit depth used by an + /// image. They do not specify the ordering of the color samples within + /// the internal representation of a PNG image. For example, the color formats + /// ``Format/rgba8(palette:fill:)`` and ``Format/bgra8(palette:fill:)`` + /// both correspond to the pixel format ``Pixel/rgba8``. + /// + /// The pixel format associated with a color format can be accessed + /// through the ``Format/pixel`` instance property. + @frozen public + enum Pixel + { + /// Pixels are stored as 1-bit grayscale values. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `1`. Each sample is in the range `0 ... 1`. + case v1 + /// Pixels are stored as 2-bit grayscale values. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `2`. Each sample is in the range `0 ... 3`. + case v2 + /// Pixels are stored as 4-bit grayscale values. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `4`. Each sample is in the range `0 ... 15`. + case v4 + /// Pixels are stored as 8-bit grayscale values. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `8`. Each sample is in the range `0 ... 255`. + case v8 + /// Pixels are stored as 16-bit grayscale values. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `16`. Each sample is in the range `0 ... 65535`. + case v16 + + /// Pixels are stored as 8-bit RGB triplets. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `8`, for a total stride of `24` bits. + /// Each sample is in the range `0 ... 255`. + case rgb8 + /// Pixels are stored as 16-bit RGB triplets. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `16`, for a total stride of `48` bits. + /// Each sample is in the range `0 ... 65535`. + case rgb16 + + /// Pixels are stored as 1-bit indices. + /// + /// An image with this pixel format has a bit depth of `1`, and + /// a color depth of `8`. Each index is in the range `0 ... 1`, + /// and can reference an entry in a palette with at most `2` elements. + case indexed1 + /// Pixels are stored as 2-bit indices. + /// + /// An image with this pixel format has a bit depth of `2`, and + /// a color depth of `8`. Each index is in the range `0 ... 3`, + /// and can reference an entry in a palette with at most `4` elements. + case indexed2 + /// Pixels are stored as 4-bit indices. + /// + /// An image with this pixel format has a bit depth of `4`, and + /// a color depth of `8`. Each index is in the range `0 ... 15`, + /// and can reference an entry in a palette with at most `16` elements. + case indexed4 + /// Pixels are stored as 8-bit indices. + /// + /// An image with this pixel format has a bit depth and color depth + /// of `8`. Each index is in the range `0 ... 255`, and can reference + /// an entry in a palette with at most `256` elements. + case indexed8 + + /// Pixels are stored as 8-bit grayscale-alpha pairs. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `8`, for a total stride of `16` bits. Each sample + /// is in the range `0 ... 255`. + case va8 + /// Pixels are stored as 16-bit grayscale-alpha pairs. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `16`, for a total stride of `32` bits. Each sample + /// is in the range `0 ... 65535`. + case va16 + + /// Pixels are stored as 8-bit RGBA quadruplets. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `8`, for a total stride of `32` bits. + /// Each sample is in the range `0 ... 255`. + case rgba8 + /// Pixels are stored as 16-bit RGBA quadruplets. + /// + /// An image with this pixel format has a bit depth and a color + /// depth of `16`, for a total stride of `64` bits. + /// Each sample is in the range `0 ... 65535`. + case rgba16 + } +} +extension PNG.Format.Pixel +{ + /// Indicates whether an image with this pixel format contains more than one + /// non-alpha color component. + /// + /// This property is `true` for all RGB, RGBA, and indexed pixel formats, + /// and `false` otherwise. + @inlinable + public + var hasColor:Bool + { + switch self + { + case .v1, .v2, .v4, .v8, .v16, .va8, .va16: + return false + case .rgb8, .rgb16, .indexed1, .indexed2, .indexed4, .indexed8, .rgba8, .rgba16: + return true + } + } + /// Indicates whether an image with this pixel format contains an alpha + /// component. + /// + /// This property is `true` for all grayscale-alpha and RGBA pixel formats, + /// and `false` otherwise. Note that indexed pixel formats are not + /// considered transparent pixel formats, even though images using them + /// can contain per-pixel alpha information. + @inlinable + public + var hasAlpha:Bool + { + switch self + { + case .v1, .v2, .v4, .v8, .v16, .rgb8, .rgb16, + .indexed1, .indexed2, .indexed4, .indexed8: + return false + case .va8, .va16, .rgba8, .rgba16: + return true + } + } + + @inlinable + var volume:Int + { + self.depth * self.channels + } + + /// The number of channels encoded per-pixel in the internal representation + /// of an image with this pixel format. + /// + /// This number is *not* the number of components in the encoded image; + /// it indicates the dimensionality of the stored image data. Notably, + /// indexed images are defined as having one channel, even though each + /// scalar index represents a four-component color value. + /// + /// This property returns `1` for all grayscale and indexed pixel formats. + /// + /// This property returns `2` for all grayscale-alpha pixel formats. + /// + /// This property returns `3` for all RGB pixel formats. + /// + /// This property returns `4` for all RGBA pixel formats. + @inlinable + public + var channels:Int + { + switch self + { + case .v1, .v2, .v4, .v8, .v16, + .indexed1, .indexed2, .indexed4, .indexed8: return 1 + case .va8, .va16: return 2 + case .rgb8, .rgb16: return 3 + case .rgba8, .rgba16: return 4 + } + } + /// The bit depth of an image with this pixel format. + /// + /// This number is *not* the color depth the encoded image; + /// it indicates the bit depth of the stored image data. Notably, + /// indexed images always have a color depth of `8`, even though they may + /// have a bit depth less than `8`. + /// + /// This property returns `1` for the ``v1`` and ``indexed1`` pixel formats. + /// + /// This property returns `2` for the ``v2`` and ``indexed2`` pixel formats. + /// + /// This property returns `4` for the ``v4`` and ``indexed4`` pixel formats. + /// + /// This property returns `8` for the ``v8``, ``va8``, ``indexed8``, + /// ``rgb8``, and ``rgba8`` pixel formats. + /// + /// This property returns `16` for the ``v16``, ``va16``, + /// ``rgb16``, and ``rgba16`` pixel formats. + @inlinable + public + var depth:Int + { + switch self + { + case .v1, .indexed1: return 1 + case .v2, .indexed2: return 2 + case .v4, .indexed4: return 4 + case .v8, .rgb8, .indexed8, .va8, .rgba8: return 8 + case .v16, .rgb16, .va16, .rgba16: return 16 + } + } + + var code:(depth:UInt8, type:UInt8) + { + switch self + { + case .v1: return ( 1, 0) + case .v2: return ( 2, 0) + case .v4: return ( 4, 0) + case .v8: return ( 8, 0) + case .v16: return (16, 0) + + case .rgb8: return ( 8, 2) + case .rgb16: return (16, 2) + + case .indexed1: return ( 1, 3) + case .indexed2: return ( 2, 3) + case .indexed4: return ( 4, 3) + case .indexed8: return ( 8, 3) + + case .va8: return ( 8, 4) + case .va16: return (16, 4) + + case .rgba8: return ( 8, 6) + case .rgba16: return (16, 6) + } + } + + static + func recognize(code:(depth:UInt8, type:UInt8)) -> Self? + { + switch code + { + case ( 1, 0): return .v1 + case ( 2, 0): return .v2 + case ( 4, 0): return .v4 + case ( 8, 0): return .v8 + case (16, 0): return .v16 + + case ( 8, 2): return .rgb8 + case (16, 2): return .rgb16 + + case ( 1, 3): return .indexed1 + case ( 2, 3): return .indexed2 + case ( 4, 3): return .indexed4 + case ( 8, 3): return .indexed8 + + case ( 8, 4): return .va8 + case (16, 4): return .va16 + + case ( 8, 6): return .rgba8 + case (16, 6): return .rgba16 + + default: return nil + } + } +} diff --git a/Sources/PNG/Formats/PNG.Format.swift b/Sources/PNG/Formats/PNG.Format.swift new file mode 100644 index 00000000..095349fd --- /dev/null +++ b/Sources/PNG/Formats/PNG.Format.swift @@ -0,0 +1,551 @@ +extension PNG +{ + /// A color format. + /// + /// This color format enumeration combines two sets of PNG color formats. + /// It can represent the fifteen standard color formats from the core + /// [PNG specification](http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.IHDR), + /// as well as two iphone-optimized color formats from Apple’s PNG extensions. + /// + /// Some color formats contain a `palette`, an optional background `fill` color, + /// and an optional chroma `key`. For most use cases, the background `fill` + /// and chroma `key` can be set to `nil`. For the indexed color formats, + /// a non-empty `palette` is mandatory. For all other color formats, the `palette` + /// can be set to the empty array `[]`. + /// + /// Color format validation takes place when initializing a ``Layout`` instance, + /// which stores the color format in a ``Image`` image. + @frozen public + enum Format + { + /// A 1-bit grayscale color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/v1``. + /// - Parameter fill: + /// An optional background color. The sample is unscaled, and must + /// be in the range `0 ... 1`. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. The sample is + /// unscaled, and must be in the range `0 ... 1`. + case v1(fill:UInt8?, key:UInt8?) + /// A 2-bit grayscale color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/v2``. + /// - Parameter fill: + /// An optional background color. The sample is unscaled, and must + /// be in the range `0 ... 3`. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. The sample is + /// unscaled, and must be in the range `0 ... 3`. + case v2(fill:UInt8?, key:UInt8?) + + /// A 4-bit grayscale color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/v4``. + /// - Parameter fill: + /// An optional background color. The sample is unscaled, and must + /// be in the range `0 ... 15`. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. The sample is + /// unscaled, and must be in the range `0 ... 15`. + case v4(fill:UInt8?, key:UInt8?) + + /// An 8-bit grayscale color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/v8``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. + case v8(fill:UInt8?, key:UInt8?) + + /// A 16-bit grayscale color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/v16``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. + case v16(fill:UInt16?, key:UInt16?) + + /// An 8-bit BGR color format. + /// + /// This color format is an iphone-optimized format. + /// It has a ``pixel`` format of ``Pixel/rgb8``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. + case bgr8(palette:[(b:UInt8, g:UInt8, r:UInt8)], + fill:(b:UInt8, g:UInt8, r:UInt8 )?, + key:(b:UInt8, g:UInt8, r:UInt8 )?) + + /// An 8-bit RGB color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/rgb8``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. + case rgb8(palette:[(r:UInt8, g:UInt8, b:UInt8)], + fill:(r:UInt8, g:UInt8, b:UInt8 )?, + key:(r:UInt8, g:UInt8, b:UInt8)?) + + /// A 16-bit RGB color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/rgb16``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. Although the image color depth is `16`, the + /// palette atom type is ``Swift.UInt8``, not ``Swift.UInt16``. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + /// - Parameter key: + /// An optional chroma key. If present, pixels matching it + /// will be displayed as transparent, if possible. + case rgb16(palette:[(r:UInt8, g:UInt8, b:UInt8)], + fill:(r:UInt16, g:UInt16, b:UInt16)?, + key:(r:UInt16, g:UInt16, b:UInt16)?) + + /// A 1-bit indexed color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/indexed1``. + /// - Parameter palette: + /// The palette values referenced by an image with this color format. + /// This palette must be non-empty, and can have at most `2` entries. + /// - Parameter fill: + /// A palette index specifying an optional background color. This index + /// must be within the index range of the `palette` array. + /// + /// Most PNG viewers ignore this field. + case indexed1(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill:Int?) + + /// A 2-bit indexed color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/indexed2``. + /// - Parameter palette: + /// The palette values referenced by an image with this color format. + /// This palette must be non-empty, and can have at most `4` entries. + /// - Parameter fill: + /// A palette index specifying an optional background color. This index + /// must be within the index range of the `palette` array. + /// + /// Most PNG viewers ignore this field. + case indexed2(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill:Int?) + + /// A 4-bit indexed color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/indexed4``. + /// - Parameter palette: + /// The palette values referenced by an image with this color format. + /// This palette must be non-empty, and can have at most `16` entries. + /// - Parameter fill: + /// A palette index specifying an optional background color. This index + /// must be within the index range of the `palette` array. + /// + /// Most PNG viewers ignore this field. + case indexed4(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill:Int?) + + /// An 8-bit indexed color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/indexed8``. + /// - Parameter palette: + /// The palette values referenced by an image with this color format. + /// This palette must be non-empty, and can have at most `256` entries. + /// - Parameter fill: + /// A palette index specifying an optional background color. This index + /// must be within the index range of the `palette` array. + /// + /// Most PNG viewers ignore this field. + case indexed8(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill:Int?) + + /// An 8-bit grayscale-alpha color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/va8``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + case va8(fill:UInt8?) + + /// A 16-bit grayscale-alpha color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/va16``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + case va16(fill:UInt16?) + + /// An 8-bit BGRA color format. + /// + /// This color format is an iphone-optimized format. + /// It has a ``pixel`` format of ``Pixel/rgba8``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + case bgra8(palette:[(b:UInt8, g:UInt8, r:UInt8)], fill:(b:UInt8, g:UInt8, r:UInt8 )?) + + /// An 8-bit RGBA color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/rgba8``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + case rgba8(palette:[(r:UInt8, g:UInt8, b:UInt8)], fill:(r:UInt8, g:UInt8, b:UInt8 )?) + + /// A 16-bit RGBA color format. + /// + /// This color format has a ``pixel`` format of ``Pixel/rgba16``. + /// - Parameter palette: + /// An palette of suggested posterization values. Most PNG viewers + /// ignore this field. Although the image color depth is `16`, the + /// palette atom type is ``Swift.UInt8``, not ``Swift.UInt16``. + /// + /// This field is unrelated to, and should not be confused with a + /// ``SuggestedPalette``. + /// - Parameter fill: + /// An optional background color. Most PNG viewers ignore this field. + case rgba16(palette:[(r:UInt8, g:UInt8, b:UInt8)], fill:(r:UInt16, g:UInt16, b:UInt16)?) + } +} +extension PNG.Format +{ + // can’t use these in the enum cases because they are `internal` only + typealias RGB = (r:T, g:T, b:T) + typealias RGBA = (r:T, g:T, b:T, a:T) + + /// The pixel format used by an image with this color format. + @inlinable public + var pixel:Pixel + { + switch self + { + case .v1: return .v1 + case .v2: return .v2 + case .v4: return .v4 + case .v8: return .v8 + case .v16: return .v16 + case .bgr8: return .rgb8 + case .rgb8: return .rgb8 + case .rgb16: return .rgb16 + case .indexed1: return .indexed1 + case .indexed2: return .indexed2 + case .indexed4: return .indexed4 + case .indexed8: return .indexed8 + case .va8: return .va8 + case .va16: return .va16 + case .bgra8: return .rgba8 + case .rgba8: return .rgba8 + case .rgba16: return .rgba16 + } + } + + // enum case constructors can’t perform validation, so we need to check + // the range of the sample values with this function. + func validate() -> Self + { + let max:(sample:UInt16, count:Int, index:Int) + max.sample = .max >> (UInt16.bitWidth - self.pixel.depth) + max.count = 1 << min(self.pixel.depth, 8) + // palette cannot contain more entries than bit depth allows + switch self + { + case .bgr8 (palette: let palette, fill: _, key: _), + .bgra8 (palette: let palette, fill: _): + max.index = palette.count - 1 + case + .rgb8 (palette: let palette, fill: _, key: _), + .rgb16 (palette: let palette, fill: _, key: _), + .rgba8 (palette: let palette, fill: _), + .rgba16 (palette: let palette, fill: _): + max.index = palette.count - 1 + case .indexed1(palette: let palette, fill: _), + .indexed2(palette: let palette, fill: _), + .indexed4(palette: let palette, fill: _), + .indexed8(palette: let palette, fill: _): + guard !palette.isEmpty + else + { + PNG.ParsingError.invalidPaletteCount(0, max: max.count).fatal + } + max.index = palette.count - 1 + default: + max.index = -1 + } + + guard max.index < max.count + else + { + PNG.ParsingError.invalidPaletteCount(max.index + 1, max: max.count).fatal + } + + switch self + { + case .v1(fill: let fill?, key: _), + .v2(fill: let fill?, key: _), + .v4(fill: let fill?, key: _): + let fill:UInt16 = .init(fill) + guard fill <= max.sample + else + { + PNG.ParsingError.invalidBackgroundSample(fill, max: max.sample).fatal + } + case .indexed1(palette: _, fill: let i?), + .indexed2(palette: _, fill: let i?), + .indexed4(palette: _, fill: let i?), + .indexed8(palette: _, fill: let i?): + guard i <= max.index + else + { + PNG.ParsingError.invalidBackgroundIndex(i, max: max.index).fatal + } + default: + break + } + + switch self + { + case .v1(fill: _?, key: let key?), + .v2(fill: _?, key: let key?), + .v4(fill: _?, key: let key?): + let key:UInt16 = .init(key) + guard key <= max.sample + else + { + PNG.ParsingError.invalidTransparencySample(key, max: max.sample).fatal + } + default: + break + } + + return self + } + + // this function assumes all inputs have been validated for consistency, + // except for the presence of the palette argument itself. + static + func recognize(standard:PNG.Standard, pixel:PNG.Format.Pixel, + palette:PNG.Palette?, background:PNG.Background?, transparency:PNG.Transparency?) + -> Self? + { + let format:Self + switch pixel + { + case .v1, .v2, .v4, .v8, .v16: + guard palette == nil + else + { + PNG.ParsingError.unexpectedPalette(pixel: pixel).fatal + } + let f:UInt16?, + k:UInt16? + switch background?.case + { + case .v(let v)?: f = v + case nil: f = nil + default: + fatalError("expected background of case `v` for pixel format `\(pixel)`") + } + switch transparency?.case + { + case .v(let v)?: k = v + case nil: k = nil + default: + fatalError("expected transparency of case `v` for pixel format `\(pixel)`") + } + + switch pixel + { + case .v1: + format = .v1(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) + case .v2: + format = .v2(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) + case .v4: + format = .v4(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) + case .v8: + format = .v8(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) + case .v16: + format = .v16(fill: f, key: k) + default: + fatalError("unreachable") + } + + case .rgb8, .rgb16: + let palette:[RGB] = palette?.entries ?? [] + let f:RGB?, + k:RGB? + switch background?.case + { + case .rgb(let c)?: f = c + case nil: f = nil + default: + fatalError("expected background of case `rgb` for pixel format `\(pixel)`") + } + switch transparency?.case + { + case .rgb(let c)?: k = c + case nil: k = nil + default: + fatalError("expected transparency of case `rgb` for pixel format `\(pixel)`") + } + + switch (standard, pixel) + { + case (.common, .rgb8): + format = .rgb8(palette: palette, + fill: f.map{ (.init($0.r), .init($0.g), .init($0.b)) }, + key: k.map{ (.init($0.r), .init($0.g), .init($0.b)) }) + case (.ios, .rgb8): + format = .bgr8(palette: palette.map{ ($0.b, $0.g, $0.r) }, + fill: f.map{ (.init($0.b), .init($0.g), .init($0.r)) }, + key: k.map{ (.init($0.b), .init($0.g), .init($0.r)) }) + case (_, .rgb16): + format = .rgb16(palette: palette, fill: f, key: k) + default: + fatalError("unreachable") + } + + case .indexed1, .indexed2, .indexed4, .indexed8: + guard let solid:PNG.Palette = palette + else + { + return nil + } + let f:Int? + switch background?.case + { + case .palette(let i): f = i + case nil: f = nil + default: + fatalError("expected background of case `palette` for pixel format `\(pixel)`") + } + + let palette:[RGBA] + switch transparency?.case + { + case nil: + palette = solid.entries.map { ( $0.r, $0.g, $0.b, .max) } + case .palette(let alpha): + guard alpha.count <= solid.entries.count + else + { + PNG.ParsingError.invalidTransparencyCount(alpha.count, + max: solid.entries.count).fatal + } + + palette = zip(solid.entries, alpha).map{ ($0.0.r, $0.0.g, $0.0.b, $0.1) } + + solid.entries.dropFirst(alpha.count).map{ ( $0.r, $0.g, $0.b, .max) } + default: + fatalError("expected transparency of case `palette` for pixel format `\(pixel)`") + } + + switch pixel + { + case .indexed1: + format = .indexed1(palette: palette, fill: f) + case .indexed2: + format = .indexed2(palette: palette, fill: f) + case .indexed4: + format = .indexed4(palette: palette, fill: f) + case .indexed8: + format = .indexed8(palette: palette, fill: f) + default: + fatalError("unreachable") + } + + case .va8, .va16: + guard palette == nil + else + { + PNG.ParsingError.unexpectedPalette(pixel: pixel).fatal + } + guard transparency == nil + else + { + PNG.ParsingError.unexpectedTransparency(pixel: pixel).fatal + } + + let f:UInt16? + switch background?.case + { + case .v(let v)?: f = v + case nil: f = nil + default: + fatalError("expected background of case `v` for pixel format `\(pixel)`") + } + + switch pixel + { + case .va8: + format = .va8( fill: f.map(UInt8.init(_:))) + case .va16: + format = .va16(fill: f) + default: + fatalError("unreachable") + } + + case .rgba8, .rgba16: + guard transparency == nil + else + { + PNG.ParsingError.unexpectedTransparency(pixel: pixel).fatal + } + + let palette:[RGB] = palette?.entries ?? [] + let f:RGB? + switch background?.case + { + case .rgb(let c)?: f = c + case nil: f = nil + default: + fatalError("expected background of case `rgb` for pixel format `\(pixel)`") + } + + switch (standard, pixel) + { + case (.common, .rgba8): + format = .rgba8(palette: palette, + fill: f.map{ (.init($0.r), .init($0.g), .init($0.b)) }) + case (.ios, .rgba8): + format = .bgra8(palette: palette.map{ ($0.b, $0.g, $0.r) }, + fill: f.map{ (.init($0.b), .init($0.g), .init($0.r)) }) + case (_, .rgba16): + format = .rgba16(palette: palette, fill: f) + default: + fatalError("unreachable") + } + } + // do not call `.validate()` on `format` because this will be done when + // the `PNG.Layout` struct is initialized + return format + } +} diff --git a/Sources/PNG/Formats/PNG.FormattingError.swift b/Sources/PNG/Formats/PNG.FormattingError.swift new file mode 100644 index 00000000..152122a7 --- /dev/null +++ b/Sources/PNG/Formats/PNG.FormattingError.swift @@ -0,0 +1,37 @@ +extension PNG +{ + /// A formatting error. + public + enum FormattingError + { + /// The formatter failed to write to a destination bytestream. + case invalidDestination + } +} +extension PNG.FormattingError:PNG.Error +{ + /// The string `"formatting error"`. + public static + var namespace:String + { + "formatting error" + } + public + var message:String + { + switch self + { + case .invalidDestination: + return "failed to write to destination bytestream" + } + } + public + var details:String? + { + switch self + { + case .invalidDestination: + return nil + } + } +} diff --git a/Sources/PNG/PNG.Layout.swift b/Sources/PNG/Formats/PNG.Layout.swift similarity index 100% rename from Sources/PNG/PNG.Layout.swift rename to Sources/PNG/Formats/PNG.Layout.swift diff --git a/Sources/PNG/Parsing/PNG.Background.Case.swift b/Sources/PNG/Parsing/PNG.Background.Case.swift new file mode 100644 index 00000000..c86040d8 --- /dev/null +++ b/Sources/PNG/Parsing/PNG.Background.Case.swift @@ -0,0 +1,30 @@ +extension PNG.Background +{ + /// A background case. This is a separate type for validation purposes. + @frozen public + enum Case + { + /// A background descriptor for an indexed image. + /// - Parameter index: + /// The index of the palette entry to be used as a background color. + /// + /// This index must be within the index range of the image palette. + case palette(index:Int) + /// A background descriptor for an RGB, BGR, RGBA, or BGRA image. + /// - Parameter _: + /// A background color. + /// + /// Note that the background components are unscaled samples. If + /// the image color depth is less than `16`, only the least-significant + /// bits of each sample are inhabited. + case rgb((r:UInt16, g:UInt16, b:UInt16)) + /// A background descriptor for a grayscale or grayscale-alpha image. + /// - Parameter _: + /// A background color. + /// + /// Note that the background value is an unscaled sample. If + /// the image color depth is less than `16`, only the least-significant + /// bits are inhabited. + case v(UInt16) + } +} diff --git a/Sources/PNG/Parsing/PNG.Background.swift b/Sources/PNG/Parsing/PNG.Background.swift index 1d4af44b..66a4dfb9 100644 --- a/Sources/PNG/Parsing/PNG.Background.swift +++ b/Sources/PNG/Parsing/PNG.Background.swift @@ -1,67 +1,30 @@ extension PNG { - /// struct PNG.Background - /// A background descriptor. + /// A background descriptor. /// - /// This type models the information stored in a ``Chunk/bKGD`` chunk. - /// This information is used to populate the `fill` field in - /// an image color ``Format``. + /// This type models the information stored in a ``Chunk/bKGD`` chunk. + /// This information is used to populate the `fill` field in + /// an image color ``Format``. /// - /// The value of this descriptor is stored in the ``PNG.Background/case`` - /// property, after validation. - /// # [Parsing and serialization](background-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// The value of this descriptor is stored in the ``PNG.Background/case`` + /// property, after validation. public struct Background { - /// enum PNG.Background.Case - /// A background case. - public - enum Case - { - /// case PNG.Background.Case.palette(index:) - /// A background descriptor for an indexed image. - /// - Parameter index: - /// The index of the palette entry to be used as a background color. - /// - /// This index must be within the index range of the image palette. - case palette(index:Int) - /// case PNG.Background.Case.rgb(_:) - /// A background descriptor for an RGB, BGR, RGBA, or BGRA image. - /// - Parameter _: - /// A background color. - /// - /// Note that the background components are unscaled samples. If - /// the image color depth is less than `16`, only the least-significant - /// bits of each sample are inhabited. - case rgb((r:UInt16, g:UInt16, b:UInt16)) - /// case PNG.Background.Case.v(_:) - /// A background descriptor for a grayscale or grayscale-alpha image. - /// - Parameter _: - /// A background color. - /// - /// Note that the background value is an unscaled sample. If - /// the image color depth is less than `16`, only the least-significant - /// bits are inhabited. - case v(UInt16) - } - /// let PNG.Background.case : Case - /// The value of this background descriptor. + /// The value of this background descriptor. public let `case`:Case } } extension PNG.Background { - /// init PNG.Background.init(case:pixel:palette:) - /// Creates a background descriptor. + /// Creates a background descriptor. /// - /// This initializer validates the background information against the - /// given pixel format and image palette. Some `pixel` formats imply - /// that `palette` must be `nil`. This initializer does not check this - /// assumption, as it is expected to have been verified by - /// ``Palette.init(entries:pixel:)``. + /// This initializer validates the background information against the + /// given pixel format and image palette. Some `pixel` formats imply + /// that `palette` must be `nil`. This initializer does not check this + /// assumption, as it is expected to have been verified by + /// ``Palette.init(entries:pixel:)``. /// - Parameter case: /// A background descriptor value. /// @@ -137,15 +100,13 @@ extension PNG.Background self.case = `case` } - /// init PNG.Background.init(parsing:pixel:palette:) - /// throws - /// Creates a background descriptor by parsing the given chunk data, - /// interpreting and validating it according to the given `pixel` format and - /// image `palette`. + /// Creates a background descriptor by parsing the given chunk data, + /// interpreting and validating it according to the given `pixel` format and + /// image `palette`. /// - /// Some `pixel` formats imply that `palette` must be `nil`. This - /// initializer does not check this assumption, as it is expected to have - /// been verified by ``Palette.init(parsing:pixel:)``. + /// Some `pixel` formats imply that `palette` must be `nil`. This + /// initializer does not check this assumption, as it is expected to have + /// been verified by ``Palette.init(parsing:pixel:)``. /// - Parameter data: /// The contents of a ``Chunk/bKGD`` chunk to parse. /// - Parameter pixel: @@ -154,7 +115,6 @@ extension PNG.Background /// - Parameter palette: /// The image palette the chunk data is to be validated against, if /// applicable. - /// ## (background-parsing-and-serialization) public init(parsing data:[UInt8], pixel:PNG.Format.Pixel, palette:PNG.Palette?) throws { @@ -214,10 +174,8 @@ extension PNG.Background self.case = .palette(index: index) } } - /// var PNG.Background.serialized : [Swift.UInt8] { get } - /// Encodes this background descriptor as the contents of a - /// ``Chunk/bKGD`` chunk. - /// ## (background-parsing-and-serialization) + /// Encodes this background descriptor as the contents of a + /// ``Chunk/bKGD`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Chromaticity.swift b/Sources/PNG/Parsing/PNG.Chromaticity.swift index b32b46c9..653ddecf 100644 --- a/Sources/PNG/Parsing/PNG.Chromaticity.swift +++ b/Sources/PNG/Parsing/PNG.Chromaticity.swift @@ -1,41 +1,28 @@ extension PNG { - /// struct PNG.Chromaticity - /// A chromaticity descriptor. + /// A chromaticity descriptor. /// - /// This type models the information stored in a ``Chunk/cHRM`` chunk. - /// # [Parsing and serialization](chromaticity-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/cHRM`` chunk. public struct Chromaticity { - /// let PNG.Chromaticity.w : (x:Percentmille, y:Percentmille) - /// The white point of an image, expressed as a pair of fractions. - /// ## () - - /// let PNG.Chromaticity.r : (x:Percentmille, y:Percentmille) - /// The chromaticity of the red component of an image, - /// expressed as a pair of fractions. - /// ## () - - /// let PNG.Chromaticity.g : (x:Percentmille, y:Percentmille) - /// The chromaticity of the green component of an image, - /// expressed as a pair of fractions. - /// ## () - - /// let PNG.Chromaticity.b : (x:Percentmille, y:Percentmille) - /// The chromaticity of the blue component of an image, - /// expressed as a pair of fractions. - /// ## () + /// The white point of an image, expressed as a pair of fractions. public - let w:(x:Percentmille, y:Percentmille), - r:(x:Percentmille, y:Percentmille), - g:(x:Percentmille, y:Percentmille), - b:(x:Percentmille, y:Percentmille) + let w:(x:Percentmille, y:Percentmille) + /// The chromaticity of the red component of an image, + /// expressed as a pair of fractions. + public + let r:(x:Percentmille, y:Percentmille) + /// The chromaticity of the green component of an image, + /// expressed as a pair of fractions. + public + let g:(x:Percentmille, y:Percentmille) + /// The chromaticity of the blue component of an image, + /// expressed as a pair of fractions. + public + let b:(x:Percentmille, y:Percentmille) - /// init PNG.Chromaticity.init(w:r:g:b:) - /// Creates a chromaticity descriptor with the given values. + /// Creates a chromaticity descriptor with the given values. /// - Parameter w: /// The white point, expressed as a pair of fractions. /// - Parameter r: @@ -60,12 +47,9 @@ extension PNG } extension PNG.Chromaticity { - /// init PNG.Chromaticity.init(parsing:) - /// throws - /// Creates a chromaticity descriptor by parsing the given chunk data. + /// Creates a chromaticity descriptor by parsing the given chunk data. /// - Parameter data: /// The contents of a ``Chunk/cHRM`` chunk to parse. - /// ## (chromaticity-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -84,10 +68,8 @@ extension PNG.Chromaticity self.b.x = .init(data.load(bigEndian: UInt32.self, as: Int.self, at: 24)) self.b.y = .init(data.load(bigEndian: UInt32.self, as: Int.self, at: 28)) } - /// var PNG.Chromaticity.serialized : [Swift.UInt8] { get } - /// Encodes this chromaticity descriptor as the contents of a - /// ``Chunk/cHRM`` chunk. - /// ## (chromaticity-parsing-and-serialization) + /// Encodes this chromaticity descriptor as the contents of a + /// ``Chunk/cHRM`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.ColorProfile.swift b/Sources/PNG/Parsing/PNG.ColorProfile.swift index aeac258d..8575c46c 100644 --- a/Sources/PNG/Parsing/PNG.ColorProfile.swift +++ b/Sources/PNG/Parsing/PNG.ColorProfile.swift @@ -2,28 +2,21 @@ import LZ77 extension PNG { - /// struct PNG.ColorProfile - /// An embedded color profile. + /// An embedded color profile. /// - /// This type models the information stored in an ``Chunk/iCCP`` chunk. - /// # [Parsing and serialization](colorprofile-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in an ``Chunk/iCCP`` chunk. public struct ColorProfile { - /// let PNG.ColorProfile.name : Swift.String - /// The name of this profile. + /// The name of this profile. public let name:String - /// let PNG.ColorProfile.profile : [Swift.UInt8] - /// The uncompressed [ICC](http://www.color.org/index.xalter) color - /// profile data. + /// The uncompressed [ICC](http://www.color.org/index.xalter) color + /// profile data. public let profile:[UInt8] - /// init PNG.ColorProfile.init(name:profile:) - /// Creates a color profile. + /// Creates a color profile. /// - Parameter name: /// The profile name. /// @@ -51,12 +44,9 @@ extension PNG } extension PNG.ColorProfile { - /// init PNG.ColorProfile.init(parsing:) - /// throws - /// Creates a color profile by parsing the given chunk data. + /// Creates a color profile by parsing the given chunk data. /// - Parameter data: /// The contents of an ``Chunk/iCCP`` chunk to parse. - /// ## (colorprofile-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -93,10 +83,7 @@ extension PNG.ColorProfile self.profile = inflator.pull() } - /// var PNG.ColorProfile.serialized : [Swift.UInt8] { get } - /// Encodes this color profile as the contents of an - /// ``Chunk/iCCP`` chunk. - /// ## (colorprofile-parsing-and-serialization) + /// Encodes this color profile as the contents of an ``Chunk/iCCP`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.ColorRendering.swift b/Sources/PNG/Parsing/PNG.ColorRendering.swift index 30119fbf..13a5ba47 100644 --- a/Sources/PNG/Parsing/PNG.ColorRendering.swift +++ b/Sources/PNG/Parsing/PNG.ColorRendering.swift @@ -1,43 +1,28 @@ extension PNG { - /// enum PNG.ColorRendering - /// A color rendering mode. + /// A color rendering mode. /// - /// This type models the information stored in an ``Chunk/sRGB`` chunk. - /// It is not recommended for the same image to include both a `ColorRendering` - /// mode and a ``ColorProfile``. - /// # [Parsing and serialization](colorrendering-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in an ``Chunk/sRGB`` chunk. + /// It is not recommended for the same image to include both a `ColorRendering` + /// mode and a ``ColorProfile``. public enum ColorRendering { - /// case PNG.ColorRendering.perceptual - /// The perceptual rendering mode. - /// ## () + /// The perceptual rendering mode. case perceptual - /// case PNG.ColorRendering.relative - /// The relative colorimetric rendering mode. - /// ## () + /// The relative colorimetric rendering mode. case relative - /// case PNG.ColorRendering.saturation - /// The saturation rendering mode. - /// ## () + /// The saturation rendering mode. case saturation - /// case PNG.ColorRendering.absolute - /// The absolute colorimetric rendering mode. - /// ## () + /// The absolute colorimetric rendering mode. case absolute } } extension PNG.ColorRendering { - /// init PNG.ColorRendering.init(parsing:) - /// throws - /// Creates a color rendering mode by parsing the given chunk data. + /// Creates a color rendering mode by parsing the given chunk data. /// - Parameter data: /// The contents of an ``Chunk/sRGB`` chunk to parse. - /// ## (colorrendering-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -57,10 +42,7 @@ extension PNG.ColorRendering throw PNG.ParsingError.invalidColorRenderingCode(code) } } - /// var PNG.ColorRendering.serialized : [Swift.UInt8] { get } - /// Encodes this color rendering mode as the contents of an - /// ``Chunk/sRGB`` chunk. - /// ## (colorrendering-parsing-and-serialization) + /// Encodes this color rendering mode as the contents of an ``Chunk/sRGB`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Format.swift b/Sources/PNG/Parsing/PNG.Format.swift deleted file mode 100644 index 38d108d6..00000000 --- a/Sources/PNG/Parsing/PNG.Format.swift +++ /dev/null @@ -1,905 +0,0 @@ -extension PNG -{ - /// enum PNG.Format - /// A color format. - /// - /// This color format enumeration combines two sets of PNG color formats. - /// It can represent the fifteen standard color formats from the core - /// [PNG specification](http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.IHDR), - /// as well as two iphone-optimized color formats from Apple’s PNG extensions. - /// - /// Some color formats contain a `palette`, an optional background `fill` color, - /// and an optional chroma `key`. For most use cases, the background `fill` - /// and chroma `key` can be set to `nil`. For the indexed color formats, - /// a non-empty `palette` is mandatory. For all other color formats, the `palette` - /// can be set to the empty array `[]`. - /// - /// Color format validation takes place when initializing a ``Layout`` instance, - /// which stores the color format in a ``Image`` image. - /// # [Grayscale formats](grayscale-color-formats) - /// # [Grayscale-alpha formats](grayscale-alpha-color-formats) - /// # [Indexed formats](indexed-color-formats) - /// # [RGB formats](rgb-color-formats) - /// # [RGBA formats](rgba-color-formats) - /// # [iPhone-optimized color formats](ios-color-formats) - /// # [See also](color-formats) - /// ## (0:color-formats) - public - enum Format - { - /// enum PNG.Format.Pixel - /// A pixel format. - /// - /// A pixel format specifies the color model and bit depth used by an - /// image. They do not specify the ordering of the color samples within - /// the internal representation of a PNG image. For example, the color formats - /// ``Format/rgba8(palette:fill:)`` and ``Format/bgra8(palette:fill:)`` - /// both correspond to the pixel format ``Pixel/rgba8``. - /// - /// The pixel format associated with a color format can be accessed - /// through the ``Format/pixel`` instance property. - /// # [Pixel formats](pixel-formats) - /// # [See also](color-formats) - /// ## (0:color-formats) - public - enum Pixel - { - /// case PNG.Format.Pixel.v1 - /// Pixels are stored as 1-bit grayscale values. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `1`. Each sample is in the range `0 ... 1`. - /// ## (pixel-formats) - case v1 - /// case PNG.Format.Pixel.v2 - /// Pixels are stored as 2-bit grayscale values. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `2`. Each sample is in the range `0 ... 3`. - /// ## (pixel-formats) - case v2 - /// case PNG.Format.Pixel.v4 - /// Pixels are stored as 4-bit grayscale values. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `4`. Each sample is in the range `0 ... 15`. - /// ## (pixel-formats) - case v4 - /// case PNG.Format.Pixel.v8 - /// Pixels are stored as 8-bit grayscale values. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `8`. Each sample is in the range `0 ... 255`. - /// ## (pixel-formats) - case v8 - /// case PNG.Format.Pixel.v16 - /// Pixels are stored as 16-bit grayscale values. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `16`. Each sample is in the range `0 ... 65535`. - /// ## (pixel-formats) - case v16 - - /// case PNG.Format.Pixel.rgb8 - /// Pixels are stored as 8-bit RGB triplets. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `8`, for a total stride of `24` bits. - /// Each sample is in the range `0 ... 255`. - /// ## (pixel-formats) - case rgb8 - /// case PNG.Format.Pixel.rgb16 - /// Pixels are stored as 16-bit RGB triplets. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `16`, for a total stride of `48` bits. - /// Each sample is in the range `0 ... 65535`. - /// ## (pixel-formats) - case rgb16 - - /// case PNG.Format.Pixel.indexed1 - /// Pixels are stored as 1-bit indices. - /// - /// An image with this pixel format has a bit depth of `1`, and - /// a color depth of `8`. Each index is in the range `0 ... 1`, - /// and can reference an entry in a palette with at most `2` elements. - /// ## (pixel-formats) - case indexed1 - /// case PNG.Format.Pixel.indexed2 - /// Pixels are stored as 2-bit indices. - /// - /// An image with this pixel format has a bit depth of `2`, and - /// a color depth of `8`. Each index is in the range `0 ... 3`, - /// and can reference an entry in a palette with at most `4` elements. - /// ## (pixel-formats) - case indexed2 - /// case PNG.Format.Pixel.indexed4 - /// Pixels are stored as 4-bit indices. - /// - /// An image with this pixel format has a bit depth of `4`, and - /// a color depth of `8`. Each index is in the range `0 ... 15`, - /// and can reference an entry in a palette with at most `16` elements. - /// ## (pixel-formats) - case indexed4 - /// case PNG.Format.Pixel.indexed8 - /// Pixels are stored as 8-bit indices. - /// - /// An image with this pixel format has a bit depth and color depth - /// of `8`. Each index is in the range `0 ... 255`, and can reference - /// an entry in a palette with at most `256` elements. - /// ## (pixel-formats) - case indexed8 - - /// case PNG.Format.Pixel.va8 - /// Pixels are stored as 8-bit grayscale-alpha pairs. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `8`, for a total stride of `16` bits. Each sample - /// is in the range `0 ... 255`. - /// ## (pixel-formats) - case va8 - /// case PNG.Format.Pixel.va16 - /// Pixels are stored as 16-bit grayscale-alpha pairs. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `16`, for a total stride of `32` bits. Each sample - /// is in the range `0 ... 65535`. - /// ## (pixel-formats) - case va16 - - /// case PNG.Format.Pixel.rgba8 - /// Pixels are stored as 8-bit RGBA quadruplets. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `8`, for a total stride of `32` bits. - /// Each sample is in the range `0 ... 255`. - /// ## (pixel-formats) - case rgba8 - /// case PNG.Format.Pixel.rgba16 - /// Pixels are stored as 16-bit RGBA quadruplets. - /// - /// An image with this pixel format has a bit depth and a color - /// depth of `16`, for a total stride of `64` bits. - /// Each sample is in the range `0 ... 65535`. - /// ## (pixel-formats) - case rgba16 - } - - /// case PNG.Format.v1(fill:key:) - /// A 1-bit grayscale color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/v1``. - /// - Parameter fill: - /// An optional background color. The sample is unscaled, and must - /// be in the range `0 ... 1`. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. The sample is - /// unscaled, and must be in the range `0 ... 1`. - /// ## (grayscale-color-formats) - - /// case PNG.Format.v2(fill:key:) - /// A 2-bit grayscale color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/v2``. - /// - Parameter fill: - /// An optional background color. The sample is unscaled, and must - /// be in the range `0 ... 3`. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. The sample is - /// unscaled, and must be in the range `0 ... 3`. - /// ## (grayscale-color-formats) - - /// case PNG.Format.v4(fill:key:) - /// A 4-bit grayscale color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/v4``. - /// - Parameter fill: - /// An optional background color. The sample is unscaled, and must - /// be in the range `0 ... 15`. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. The sample is - /// unscaled, and must be in the range `0 ... 15`. - /// ## (grayscale-color-formats) - - /// case PNG.Format.v8(fill:key:) - /// An 8-bit grayscale color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/v8``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. - /// ## (grayscale-color-formats) - - /// case PNG.Format.v16(fill:key:) - /// A 16-bit grayscale color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/v16``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. - /// ## (grayscale-color-formats) - - /// case PNG.Format.bgr8(palette:fill:key:) - /// An 8-bit BGR color format. - /// - /// This color format is an iphone-optimized format. - /// It has a ``pixel`` format of ``Pixel/rgb8``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. - /// ## (ios-color-formats) - - /// case PNG.Format.rgb8(palette:fill:key:) - /// An 8-bit RGB color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/rgb8``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. - /// ## (rgb-color-formats) - - /// case PNG.Format.rgb16(palette:fill:key:) - /// A 16-bit RGB color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/rgb16``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. Although the image color depth is `16`, the - /// palette atom type is ``Swift.UInt8``, not ``Swift.UInt16``. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// - Parameter key: - /// An optional chroma key. If present, pixels matching it - /// will be displayed as transparent, if possible. - /// ## (rgb-color-formats) - - /// case PNG.Format.indexed1(palette:fill:) - /// A 1-bit indexed color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/indexed1``. - /// - Parameter palette: - /// The palette values referenced by an image with this color format. - /// This palette must be non-empty, and can have at most `2` entries. - /// - Parameter fill: - /// A palette index specifying an optional background color. This index - /// must be within the index range of the `palette` array. - /// - /// Most PNG viewers ignore this field. - /// ## (indexed-color-formats) - - /// case PNG.Format.indexed2(palette:fill:) - /// A 2-bit indexed color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/indexed2``. - /// - Parameter palette: - /// The palette values referenced by an image with this color format. - /// This palette must be non-empty, and can have at most `4` entries. - /// - Parameter fill: - /// A palette index specifying an optional background color. This index - /// must be within the index range of the `palette` array. - /// - /// Most PNG viewers ignore this field. - /// ## (indexed-color-formats) - - /// case PNG.Format.indexed4(palette:fill:) - /// A 4-bit indexed color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/indexed4``. - /// - Parameter palette: - /// The palette values referenced by an image with this color format. - /// This palette must be non-empty, and can have at most `16` entries. - /// - Parameter fill: - /// A palette index specifying an optional background color. This index - /// must be within the index range of the `palette` array. - /// - /// Most PNG viewers ignore this field. - /// ## (indexed-color-formats) - - /// case PNG.Format.indexed8(palette:fill:) - /// An 8-bit indexed color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/indexed8``. - /// - Parameter palette: - /// The palette values referenced by an image with this color format. - /// This palette must be non-empty, and can have at most `256` entries. - /// - Parameter fill: - /// A palette index specifying an optional background color. This index - /// must be within the index range of the `palette` array. - /// - /// Most PNG viewers ignore this field. - /// ## (indexed-color-formats) - - /// case PNG.Format.va8(fill:) - /// An 8-bit grayscale-alpha color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/va8``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// ## (grayscale-alpha-color-formats) - - /// case PNG.Format.va16(fill:) - /// A 16-bit grayscale-alpha color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/va16``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// ## (grayscale-alpha-color-formats) - - /// case PNG.Format.bgra8(palette:fill:) - /// An 8-bit BGRA color format. - /// - /// This color format is an iphone-optimized format. - /// It has a ``pixel`` format of ``Pixel/rgba8``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// ## (ios-color-formats) - - /// case PNG.Format.rgba8(palette:fill:) - /// An 8-bit RGBA color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/rgba8``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// ## (rgba-color-formats) - - /// case PNG.Format.rgba16(palette:fill:) - /// A 16-bit RGBA color format. - /// - /// This color format has a ``pixel`` format of ``Pixel/rgba16``. - /// - Parameter palette: - /// An palette of suggested posterization values. Most PNG viewers - /// ignore this field. Although the image color depth is `16`, the - /// palette atom type is ``Swift.UInt8``, not ``Swift.UInt16``. - /// - /// This field is unrelated to, and should not be confused with a - /// ``SuggestedPalette``. - /// - Parameter fill: - /// An optional background color. Most PNG viewers ignore this field. - /// ## (rgba-color-formats) - case v1 ( fill: UInt8?, key: UInt8? ) - case v2 ( fill: UInt8?, key: UInt8? ) - case v4 ( fill: UInt8?, key: UInt8? ) - case v8 ( fill: UInt8?, key: UInt8? ) - case v16 ( fill: UInt16?, key: UInt16? ) - - case bgr8 (palette:[(b:UInt8, g:UInt8, r:UInt8 )], fill:(b:UInt8, g:UInt8, r:UInt8 )?, key:(b:UInt8, g:UInt8, r:UInt8 )?) - - case rgb8 (palette:[(r:UInt8, g:UInt8, b:UInt8 )], fill:(r:UInt8, g:UInt8, b:UInt8 )?, key:(r:UInt8, g:UInt8, b:UInt8 )?) - case rgb16 (palette:[(r:UInt8, g:UInt8, b:UInt8 )], fill:(r:UInt16, g:UInt16, b:UInt16)?, key:(r:UInt16, g:UInt16, b:UInt16)?) - - case indexed1(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill: Int? ) - case indexed2(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill: Int? ) - case indexed4(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill: Int? ) - case indexed8(palette:[(r:UInt8, g:UInt8, b:UInt8, a:UInt8)], fill: Int? ) - - case va8 ( fill: UInt8? ) - case va16 ( fill: UInt16? ) - - case bgra8 (palette:[(b:UInt8, g:UInt8, r:UInt8 )], fill:(b:UInt8, g:UInt8, r:UInt8 )? ) - - case rgba8 (palette:[(r:UInt8, g:UInt8, b:UInt8 )], fill:(r:UInt8, g:UInt8, b:UInt8 )? ) - case rgba16 (palette:[(r:UInt8, g:UInt8, b:UInt8 )], fill:(r:UInt16, g:UInt16, b:UInt16)? ) - } -} -extension PNG.Format.Pixel -{ - /// var PNG.Format.Pixel.hasColor : Swift.Bool { get } - /// @ inlinable - /// Indicates whether an image with this pixel format contains more than one - /// non-alpha color component. - /// - /// This property is `true` for all RGB, RGBA, and indexed pixel formats, - /// and `false` otherwise. - @inlinable - public - var hasColor:Bool - { - switch self - { - case .v1, .v2, .v4, .v8, .v16, .va8, .va16: - return false - case .rgb8, .rgb16, .indexed1, .indexed2, .indexed4, .indexed8, .rgba8, .rgba16: - return true - } - } - /// var PNG.Format.Pixel.hasAlpha : Swift.Bool { get } - /// @ inlinable - /// Indicates whether an image with this pixel format contains an alpha - /// component. - /// - /// This property is `true` for all grayscale-alpha and RGBA pixel formats, - /// and `false` otherwise. Note that indexed pixel formats are not - /// considered transparent pixel formats, even though images using them - /// can contain per-pixel alpha information. - @inlinable - public - var hasAlpha:Bool - { - switch self - { - case .v1, .v2, .v4, .v8, .v16, .rgb8, .rgb16, - .indexed1, .indexed2, .indexed4, .indexed8: - return false - case .va8, .va16, .rgba8, .rgba16: - return true - } - } - - @inlinable - var volume:Int - { - self.depth * self.channels - } - - /// var PNG.Format.Pixel.channels : Swift.Int { get } - /// @ inlinable - /// The number of channels encoded per-pixel in the internal representation - /// of an image with this pixel format. - /// - /// This number is *not* the number of components in the encoded image; - /// it indicates the dimensionality of the stored image data. Notably, - /// indexed images are defined as having one channel, even though each - /// scalar index represents a four-component color value. - /// - /// This property returns `1` for all grayscale and indexed pixel formats. - /// - /// This property returns `2` for all grayscale-alpha pixel formats. - /// - /// This property returns `3` for all RGB pixel formats. - /// - /// This property returns `4` for all RGBA pixel formats. - @inlinable - public - var channels:Int - { - switch self - { - case .v1, .v2, .v4, .v8, .v16, - .indexed1, .indexed2, .indexed4, .indexed8: return 1 - case .va8, .va16: return 2 - case .rgb8, .rgb16: return 3 - case .rgba8, .rgba16: return 4 - } - } - /// var PNG.Format.Pixel.depth : Swift.Int { get } - /// @ inlinable - /// The bit depth of an image with this pixel format. - /// - /// This number is *not* the color depth the encoded image; - /// it indicates the bit depth of the stored image data. Notably, - /// indexed images always have a color depth of `8`, even though they may - /// have a bit depth less than `8`. - /// - /// This property returns `1` for the ``v1`` and ``indexed1`` pixel formats. - /// - /// This property returns `2` for the ``v2`` and ``indexed2`` pixel formats. - /// - /// This property returns `4` for the ``v4`` and ``indexed4`` pixel formats. - /// - /// This property returns `8` for the ``v8``, ``va8``, ``indexed8``, - /// ``rgb8``, and ``rgba8`` pixel formats. - /// - /// This property returns `16` for the ``v16``, ``va16``, - /// ``rgb16``, and ``rgba16`` pixel formats. - @inlinable - public - var depth:Int - { - switch self - { - case .v1, .indexed1: return 1 - case .v2, .indexed2: return 2 - case .v4, .indexed4: return 4 - case .v8, .rgb8, .indexed8, .va8, .rgba8: return 8 - case .v16, .rgb16, .va16, .rgba16: return 16 - } - } - - var code:(depth:UInt8, type:UInt8) - { - switch self - { - case .v1: return ( 1, 0) - case .v2: return ( 2, 0) - case .v4: return ( 4, 0) - case .v8: return ( 8, 0) - case .v16: return (16, 0) - - case .rgb8: return ( 8, 2) - case .rgb16: return (16, 2) - - case .indexed1: return ( 1, 3) - case .indexed2: return ( 2, 3) - case .indexed4: return ( 4, 3) - case .indexed8: return ( 8, 3) - - case .va8: return ( 8, 4) - case .va16: return (16, 4) - - case .rgba8: return ( 8, 6) - case .rgba16: return (16, 6) - } - } - - static - func recognize(code:(depth:UInt8, type:UInt8)) -> Self? - { - switch code - { - case ( 1, 0): return .v1 - case ( 2, 0): return .v2 - case ( 4, 0): return .v4 - case ( 8, 0): return .v8 - case (16, 0): return .v16 - - case ( 8, 2): return .rgb8 - case (16, 2): return .rgb16 - - case ( 1, 3): return .indexed1 - case ( 2, 3): return .indexed2 - case ( 4, 3): return .indexed4 - case ( 8, 3): return .indexed8 - - case ( 8, 4): return .va8 - case (16, 4): return .va16 - - case ( 8, 6): return .rgba8 - case (16, 6): return .rgba16 - - default: return nil - } - } -} -extension PNG.Format -{ - // can’t use these in the enum cases because they are `internal` only - typealias RGB = (r:T, g:T, b:T) - typealias RGBA = (r:T, g:T, b:T, a:T) - - /// var PNG.Format.pixel : Pixel { get } - /// @ inlinable - /// The pixel format used by an image with this color format. - @inlinable - public - var pixel:Pixel - { - switch self - { - case .v1: return .v1 - case .v2: return .v2 - case .v4: return .v4 - case .v8: return .v8 - case .v16: return .v16 - case .bgr8: return .rgb8 - case .rgb8: return .rgb8 - case .rgb16: return .rgb16 - case .indexed1: return .indexed1 - case .indexed2: return .indexed2 - case .indexed4: return .indexed4 - case .indexed8: return .indexed8 - case .va8: return .va8 - case .va16: return .va16 - case .bgra8: return .rgba8 - case .rgba8: return .rgba8 - case .rgba16: return .rgba16 - } - } - - // enum case constructors can’t perform validation, so we need to check - // the range of the sample values with this function. - func validate() -> Self - { - let max:(sample:UInt16, count:Int, index:Int) - max.sample = .max >> (UInt16.bitWidth - self.pixel.depth) - max.count = 1 << min(self.pixel.depth, 8) - // palette cannot contain more entries than bit depth allows - switch self - { - case .bgr8 (palette: let palette, fill: _, key: _), - .bgra8 (palette: let palette, fill: _): - max.index = palette.count - 1 - case - .rgb8 (palette: let palette, fill: _, key: _), - .rgb16 (palette: let palette, fill: _, key: _), - .rgba8 (palette: let palette, fill: _), - .rgba16 (palette: let palette, fill: _): - max.index = palette.count - 1 - case .indexed1(palette: let palette, fill: _), - .indexed2(palette: let palette, fill: _), - .indexed4(palette: let palette, fill: _), - .indexed8(palette: let palette, fill: _): - guard !palette.isEmpty - else - { - PNG.ParsingError.invalidPaletteCount(0, max: max.count).fatal - } - max.index = palette.count - 1 - default: - max.index = -1 - } - - guard max.index < max.count - else - { - PNG.ParsingError.invalidPaletteCount(max.index + 1, max: max.count).fatal - } - - switch self - { - case .v1(fill: let fill?, key: _), - .v2(fill: let fill?, key: _), - .v4(fill: let fill?, key: _): - let fill:UInt16 = .init(fill) - guard fill <= max.sample - else - { - PNG.ParsingError.invalidBackgroundSample(fill, max: max.sample).fatal - } - case .indexed1(palette: _, fill: let i?), - .indexed2(palette: _, fill: let i?), - .indexed4(palette: _, fill: let i?), - .indexed8(palette: _, fill: let i?): - guard i <= max.index - else - { - PNG.ParsingError.invalidBackgroundIndex(i, max: max.index).fatal - } - default: - break - } - - switch self - { - case .v1(fill: _?, key: let key?), - .v2(fill: _?, key: let key?), - .v4(fill: _?, key: let key?): - let key:UInt16 = .init(key) - guard key <= max.sample - else - { - PNG.ParsingError.invalidTransparencySample(key, max: max.sample).fatal - } - default: - break - } - - return self - } - - // this function assumes all inputs have been validated for consistency, - // except for the presence of the palette argument itself. - static - func recognize(standard:PNG.Standard, pixel:PNG.Format.Pixel, - palette:PNG.Palette?, background:PNG.Background?, transparency:PNG.Transparency?) - -> Self? - { - let format:Self - switch pixel - { - case .v1, .v2, .v4, .v8, .v16: - guard palette == nil - else - { - PNG.ParsingError.unexpectedPalette(pixel: pixel).fatal - } - let f:UInt16?, - k:UInt16? - switch background?.case - { - case .v(let v)?: f = v - case nil: f = nil - default: - fatalError("expected background of case `v` for pixel format `\(pixel)`") - } - switch transparency?.case - { - case .v(let v)?: k = v - case nil: k = nil - default: - fatalError("expected transparency of case `v` for pixel format `\(pixel)`") - } - - switch pixel - { - case .v1: - format = .v1(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) - case .v2: - format = .v2(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) - case .v4: - format = .v4(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) - case .v8: - format = .v8(fill: f.map(UInt8.init(_:)), key: k.map(UInt8.init(_:))) - case .v16: - format = .v16(fill: f, key: k) - default: - fatalError("unreachable") - } - - case .rgb8, .rgb16: - let palette:[RGB] = palette?.entries ?? [] - let f:RGB?, - k:RGB? - switch background?.case - { - case .rgb(let c)?: f = c - case nil: f = nil - default: - fatalError("expected background of case `rgb` for pixel format `\(pixel)`") - } - switch transparency?.case - { - case .rgb(let c)?: k = c - case nil: k = nil - default: - fatalError("expected transparency of case `rgb` for pixel format `\(pixel)`") - } - - switch (standard, pixel) - { - case (.common, .rgb8): - format = .rgb8(palette: palette, - fill: f.map{ (.init($0.r), .init($0.g), .init($0.b)) }, - key: k.map{ (.init($0.r), .init($0.g), .init($0.b)) }) - case (.ios, .rgb8): - format = .bgr8(palette: palette.map{ ($0.b, $0.g, $0.r) }, - fill: f.map{ (.init($0.b), .init($0.g), .init($0.r)) }, - key: k.map{ (.init($0.b), .init($0.g), .init($0.r)) }) - case (_, .rgb16): - format = .rgb16(palette: palette, fill: f, key: k) - default: - fatalError("unreachable") - } - - case .indexed1, .indexed2, .indexed4, .indexed8: - guard let solid:PNG.Palette = palette - else - { - return nil - } - let f:Int? - switch background?.case - { - case .palette(let i): f = i - case nil: f = nil - default: - fatalError("expected background of case `palette` for pixel format `\(pixel)`") - } - - let palette:[RGBA] - switch transparency?.case - { - case nil: - palette = solid.entries.map { ( $0.r, $0.g, $0.b, .max) } - case .palette(let alpha): - guard alpha.count <= solid.entries.count - else - { - PNG.ParsingError.invalidTransparencyCount(alpha.count, - max: solid.entries.count).fatal - } - - palette = zip(solid.entries, alpha).map{ ($0.0.r, $0.0.g, $0.0.b, $0.1) } + - solid.entries.dropFirst(alpha.count).map{ ( $0.r, $0.g, $0.b, .max) } - default: - fatalError("expected transparency of case `palette` for pixel format `\(pixel)`") - } - - switch pixel - { - case .indexed1: - format = .indexed1(palette: palette, fill: f) - case .indexed2: - format = .indexed2(palette: palette, fill: f) - case .indexed4: - format = .indexed4(palette: palette, fill: f) - case .indexed8: - format = .indexed8(palette: palette, fill: f) - default: - fatalError("unreachable") - } - - case .va8, .va16: - guard palette == nil - else - { - PNG.ParsingError.unexpectedPalette(pixel: pixel).fatal - } - guard transparency == nil - else - { - PNG.ParsingError.unexpectedTransparency(pixel: pixel).fatal - } - - let f:UInt16? - switch background?.case - { - case .v(let v)?: f = v - case nil: f = nil - default: - fatalError("expected background of case `v` for pixel format `\(pixel)`") - } - - switch pixel - { - case .va8: - format = .va8( fill: f.map(UInt8.init(_:))) - case .va16: - format = .va16(fill: f) - default: - fatalError("unreachable") - } - - case .rgba8, .rgba16: - guard transparency == nil - else - { - PNG.ParsingError.unexpectedTransparency(pixel: pixel).fatal - } - - let palette:[RGB] = palette?.entries ?? [] - let f:RGB? - switch background?.case - { - case .rgb(let c)?: f = c - case nil: f = nil - default: - fatalError("expected background of case `rgb` for pixel format `\(pixel)`") - } - - switch (standard, pixel) - { - case (.common, .rgba8): - format = .rgba8(palette: palette, - fill: f.map{ (.init($0.r), .init($0.g), .init($0.b)) }) - case (.ios, .rgba8): - format = .bgra8(palette: palette.map{ ($0.b, $0.g, $0.r) }, - fill: f.map{ (.init($0.b), .init($0.g), .init($0.r)) }) - case (_, .rgba16): - format = .rgba16(palette: palette, fill: f) - default: - fatalError("unreachable") - } - } - // do not call `.validate()` on `format` because this will be done when - // the `PNG.Layout` struct is initialized - return format - } -} diff --git a/Sources/PNG/Parsing/PNG.FormattingError.swift b/Sources/PNG/Parsing/PNG.FormattingError.swift deleted file mode 100644 index 9035f5f5..00000000 --- a/Sources/PNG/Parsing/PNG.FormattingError.swift +++ /dev/null @@ -1,53 +0,0 @@ -extension PNG -{ - /// enum PNG.FormattingError - /// : Error - /// A formatting error. - /// # [See also](error-handling) - /// ## (error-handling) - public - enum FormattingError - { - /// case PNG.FormattingError.invalidDestination - /// The formatter failed to write to a destination bytestream. - case invalidDestination - } -} -extension PNG.FormattingError:PNG.Error -{ - /// static var PNG.FormattingError.namespace : Swift.String { get } - /// ?: Error - /// The string `"formatting error"`. - public static - var namespace:String - { - "formatting error" - } - /// var PNG.FormattingError.message : Swift.String { get } - /// ?: Error - /// A human-readable summary of this error. - /// ## () - public - var message:String - { - switch self - { - case .invalidDestination: - return "failed to write to destination bytestream" - } - } - /// var PNG.FormattingError.details : Swift.String? { get } - /// ?: Error - /// An optional human-readable string providing additional details - /// about this error. - /// ## () - public - var details:String? - { - switch self - { - case .invalidDestination: - return nil - } - } -} diff --git a/Sources/PNG/Parsing/PNG.Gamma.swift b/Sources/PNG/Parsing/PNG.Gamma.swift index 9271a9b8..cc38c50e 100644 --- a/Sources/PNG/Parsing/PNG.Gamma.swift +++ b/Sources/PNG/Parsing/PNG.Gamma.swift @@ -1,21 +1,15 @@ extension PNG { - /// struct PNG.Gamma - /// A gamma descriptor. + /// A gamma descriptor. /// - /// This type models the information stored in a ``Chunk/gAMA`` chunk. - /// # [Parsing and serialization](gamma-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/gAMA`` chunk. public struct Gamma { - /// let PNG.Gamma.value : Percentmille - /// The gamma value of an image, expressed as a fraction. + /// The gamma value of an image, expressed as a fraction. public let value:Percentmille - /// init PNG.Gamma.init(value:) - /// Creates a gamma descriptor with the given value. + /// Creates a gamma descriptor with the given value. /// - Parameter value: /// A rational gamma value. public @@ -27,12 +21,9 @@ extension PNG } extension PNG.Gamma { - /// init PNG.Gamma.init(parsing:) - /// throws - /// Creates a gamma descriptor by parsing the given chunk data. + /// Creates a gamma descriptor by parsing the given chunk data. /// - Parameter data: /// The contents of a ``Chunk/gAMA`` chunk to parse. - /// ## (gamma-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -44,10 +35,8 @@ extension PNG.Gamma self.value = .init(data.load(bigEndian: UInt32.self, as: Int.self, at: 0)) } - /// var PNG.Gamma.serialized : [Swift.UInt8] { get } - /// Encodes this gamma descriptor as the contents of a - /// ``Chunk/gAMA`` chunk. - /// ## (gamma-parsing-and-serialization) + /// Encodes this gamma descriptor as the contents of a + /// ``Chunk/gAMA`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Header.swift b/Sources/PNG/Parsing/PNG.Header.swift index 58eb23f4..9f303672 100644 --- a/Sources/PNG/Parsing/PNG.Header.swift +++ b/Sources/PNG/Parsing/PNG.Header.swift @@ -1,31 +1,23 @@ extension PNG { - /// struct PNG.Header - /// An image header. + /// An image header. /// - /// This type models the information stored in a ``Chunk/IHDR`` chunk. - /// # [Parsing and serialization](header-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/IHDR`` chunk. public struct Header { - /// let PNG.Header.size : (x:Swift.Int, y:Swift.Int) - /// The size of an image, measured in pixels. + /// The size of an image, measured in pixels. public let size:(x:Int, y:Int), - /// let PNG.Header.pixel : Format.Pixel - /// The pixel format of an image. - pixel:PNG.Format.Pixel, - /// let PNG.Header.interlaced : Swift.Bool - /// Indicates whether an image uses interlacing. + /// The pixel format of an image. + pixel:Format.Pixel, + /// Indicates whether an image uses interlacing. interlaced:Bool - /// init PNG.Header.init(size:pixel:interlaced:standard:) - /// Creates an image header. + /// Creates an image header. /// - /// This initializer validates the image `size`, and validates the - /// `pixel` format against the given PNG `standard`. + /// This initializer validates the image `size`, and validates the + /// `pixel` format against the given PNG `standard`. /// - Parameter size: /// An image size, measured in pixels. /// @@ -43,7 +35,9 @@ extension PNG /// must be either ``Format.Pixel/rgb8`` or ``Format.Pixel/rgba8``. /// Otherwise, this initializer will suffer a precondition failure. public - init(size:(x:Int, y:Int), pixel:PNG.Format.Pixel, interlaced:Bool, + init(size:(x:Int, y:Int), + pixel:Format.Pixel, + interlaced:Bool, standard:PNG.Standard) { guard size.x > 0, size.y > 0 @@ -68,16 +62,13 @@ extension PNG } extension PNG.Header { - /// init PNG.Header.init(parsing:standard:) - /// throws - /// Creates an image header by parsing the given chunk data, interpreting it - /// according to the given PNG `standard`. + /// Creates an image header by parsing the given chunk data, interpreting it + /// according to the given PNG `standard`. /// - Parameter data: /// The contents of an ``Chunk/IHDR`` chunk to parse. /// - Parameter standard: /// Specifies if the header should be interpreted as a standard PNG header, /// or an iphone-optimized PNG header. - /// ## (header-parsing-and-serialization) public init(parsing data:[UInt8], standard:PNG.Standard) throws { @@ -137,9 +128,7 @@ extension PNG.Header } } - /// var PNG.Header.serialized : [Swift.UInt8] { get } - /// Encodes this image header as the contents of an ``Chunk/IHDR`` chunk. - /// ## (header-parsing-and-serialization) + /// Encodes this image header as the contents of an ``Chunk/IHDR`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Histogram.swift b/Sources/PNG/Parsing/PNG.Histogram.swift index c999fdc9..339930a7 100644 --- a/Sources/PNG/Parsing/PNG.Histogram.swift +++ b/Sources/PNG/Parsing/PNG.Histogram.swift @@ -1,31 +1,25 @@ extension PNG { - /// struct PNG.Histogram - /// A palette frequency histogram. + /// A palette frequency histogram. /// - /// This type models the information stored in a ``Chunk/hIST`` chunk. - /// # [Parsing and serialization](histogram-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/hIST`` chunk. public struct Histogram { - /// let PNG.Histogram.frequencies : [Swift.UInt16] - /// The frequency values of this histogram. + /// The frequency values of this histogram. /// - /// The *i*th frequency value corresponds to the *i*th entry in the - /// image palette. + /// The *i*th frequency value corresponds to the *i*th entry in the + /// image palette. public let frequencies:[UInt16] } } extension PNG.Histogram { - /// init PNG.Histogram.init(frequencies:palette:) - /// Creates a palette histogram. + /// Creates a palette histogram. /// - /// This initializer validates the background information against the - /// given image palette. + /// This initializer validates the background information against the + /// given image palette. /// - Parameter frequencies: /// The frequency of each palette entry in the image. The *i*th frequency /// value corresponds to the *i*th palette entry. This array must have the @@ -45,15 +39,12 @@ extension PNG.Histogram self.frequencies = frequencies } - /// init PNG.Histogram.init(parsing:palette:) - /// throws - /// Creates a palette histogram by parsing the given chunk data, - /// validating it according to the given image `palette`. + /// Creates a palette histogram by parsing the given chunk data, + /// validating it according to the given image `palette`. /// - Parameter data: /// The contents of a ``Chunk/hIST`` chunk to parse. /// - Parameter palette: /// The image palette the chunk data is to be validated against. - /// ## (histogram-parsing-and-serialization) public init(parsing data:[UInt8], palette:PNG.Palette) throws { @@ -68,10 +59,8 @@ extension PNG.Histogram data.load(bigEndian: UInt16.self, as: UInt16.self, at: $0 << 1) } } - /// var PNG.Histogram.serialized : [Swift.UInt8] { get } - /// Encodes this histogram as the contents of a - /// ``Chunk/hIST`` chunk. - /// ## (histogram-parsing-and-serialization) + /// Encodes this histogram as the contents of a + /// ``Chunk/hIST`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Palette.swift b/Sources/PNG/Parsing/PNG.Palette.swift index 31b479ba..29f47325 100644 --- a/Sources/PNG/Parsing/PNG.Palette.swift +++ b/Sources/PNG/Parsing/PNG.Palette.swift @@ -1,30 +1,24 @@ extension PNG { - /// struct PNG.Palette - /// An image palette. + /// An image palette. /// - /// This type models the information stored in a ``Chunk/PLTE`` chunk. - /// This information is used to populate the non-alpha components of the - /// `palette` field in an image color ``Format``, when appropriate. - /// # [Parsing and serialization](palette-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) - public + /// This type models the information stored in a ``Chunk/PLTE`` chunk. + /// This information is used to populate the non-alpha components of the + /// `palette` field in an image color ``Format``, when appropriate. + @frozen public struct Palette { - /// let PNG.Palette.entries : [(r:Swift.UInt8, g:Swift.UInt8, b:Swift.UInt8)] - /// The entries in this palette. + /// The entries in this palette. public let entries:[(r:UInt8, g:UInt8, b:UInt8)] } } extension PNG.Palette { - /// init PNG.Palette.init(entries:pixel:) - /// Creates an image palette. + /// Creates an image palette. /// - /// This initializer validates the palette information against the given - /// `pixel` format. + /// This initializer validates the palette information against the given + /// `pixel` format. /// - Parameter entries: /// An array of palette entries. This array must be non-empty, and can /// contain at most `256`, or `1 << pixel.```Format.Pixel/depth`` elements, @@ -50,15 +44,12 @@ extension PNG.Palette self.entries = entries } - /// init PNG.Palette.init(parsing:pixel:) - /// throws - /// Creates an image palette by parsing the given chunk data, interpreting - /// and validating it according to the given `pixel` format. + /// Creates an image palette by parsing the given chunk data, interpreting + /// and validating it according to the given `pixel` format. /// - Parameter data: /// The contents of a ``Chunk/PLTE`` chunk to parse. /// - Parameter pixel: /// The pixel format specifying how the chunk data is to be interpreted. - /// ## (palette-parsing-and-serialization) public init(parsing data:[UInt8], pixel:PNG.Format.Pixel) throws { @@ -88,9 +79,7 @@ extension PNG.Palette (base:Int) in (r: data[base], g: data[base + 1], b: data[base + 2]) } } - /// var PNG.Palette.serialized : [Swift.UInt8] { get } - /// Encodes this image palette as the contents of a ``Chunk/PLTE`` chunk. - /// ## (palette-parsing-and-serialization) + /// Encodes this image palette as the contents of a ``Chunk/PLTE`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.ParsingError.swift b/Sources/PNG/Parsing/PNG.ParsingError.swift index 4230d353..c7340c75 100644 --- a/Sources/PNG/Parsing/PNG.ParsingError.swift +++ b/Sources/PNG/Parsing/PNG.ParsingError.swift @@ -1,352 +1,264 @@ extension PNG { - /// enum PNG.ParsingError - /// : Error - /// A parsing error. - /// # [Header errors](IHDR-parsing-errors) - /// # [Palette errors](PLTE-parsing-errors) - /// # [Transparency errors](tRNS-parsing-errors) - /// # [Background errors](bKGD-parsing-errors) - /// # [Histogram errors](hIST-parsing-errors) - /// # [Gamma errors](gAMA-parsing-errors) - /// # [Chromaticity errors](cHRM-parsing-errors) - /// # [Color rendering errors](sRGB-parsing-errors) - /// # [Significant bits errors](sBIT-parsing-errors) - /// # [Color profile errors](iCCP-parsing-errors) - /// # [Physical dimensions errors](pHYs-parsing-errors) - /// # [Suggested palette errors](sPLT-parsing-errors) - /// # [Time modified errors](tIME-parsing-errors) - /// # [Text comment errors](text-chunk-parsing-errors) - /// # [See also](error-handling) - /// ## (error-handling) + /// A parsing error. public enum ParsingError { - /// case PNG.ParsingError.invalidHeaderChunkLength(_:) - /// An ``Chunk/IHDR`` chunk had the wrong length. + /// An ``Chunk/IHDR`` chunk had the wrong length. /// - /// Header chunks should be exactly `13` bytes long. + /// Header chunks should be exactly `13` bytes long. /// - Parameter _: /// The chunk length. - /// ## (IHDR-parsing-errors) + case invalidHeaderChunkLength(Int) - /// case PNG.ParsingError.invalidHeaderPixelFormatCode(_:) - /// An ``Chunk/IHDR`` chunk had an invalid pixel format code. + /// An ``Chunk/IHDR`` chunk had an invalid pixel format code. /// - Parameter _: /// The invalid pixel format code. - /// ## (IHDR-parsing-errors) + case invalidHeaderPixelFormatCode((UInt8, UInt8)) - /// case PNG.ParsingError.invalidHeaderPixelFormat(_:standard:) - /// An ``Chunk/IHDR`` chunk specified a pixel format that is disallowed - /// according to the PNG standard used by the image. + /// An ``Chunk/IHDR`` chunk specified a pixel format that is disallowed + /// according to the PNG standard used by the image. /// - /// This error gets thrown when an iphone-optimized image - /// (``Standard/ios``) has a pixel format that is not - /// ``Format.Pixel/rgb8`` or ``Format.Pixel/rgba8``. + /// This error gets thrown when an iphone-optimized image + /// (``Standard/ios``) has a pixel format that is not + /// ``Format.Pixel/rgb8`` or ``Format.Pixel/rgba8``. /// - Parameter _: /// The invalid pixel format. /// - Parameter standard: /// The PNG standard. This error is only relevant for iphone-optimized /// images, so library-generated instances of this error case always have /// this field set to ``Standard/ios``. - /// ## (IHDR-parsing-errors) + case invalidHeaderPixelFormat(PNG.Format.Pixel, standard:PNG.Standard) - /// case PNG.ParsingError.invalidHeaderCompressionMethodCode(_:) - /// An ``Chunk/IHDR`` chunk had an invalid compression method code. + /// An ``Chunk/IHDR`` chunk had an invalid compression method code. /// - /// The compression method code should always be `0`. + /// The compression method code should always be `0`. /// - Parameter _: /// The invalid compression method code. - /// ## (IHDR-parsing-errors) + case invalidHeaderCompressionMethodCode(UInt8) - /// case PNG.ParsingError.invalidHeaderFilterCode(_:) - /// An ``Chunk/IHDR`` chunk had an invalid filter code. + /// An ``Chunk/IHDR`` chunk had an invalid filter code. /// - /// The filter code should always be `0`. + /// The filter code should always be `0`. /// - Parameter _: /// The invalid filter code. - /// ## (IHDR-parsing-errors) + case invalidHeaderFilterCode(UInt8) - /// case PNG.ParsingError.invalidHeaderInterlacingCode(_:) - /// An ``Chunk/IHDR`` chunk had an invalid interlacing code. + /// An ``Chunk/IHDR`` chunk had an invalid interlacing code. /// - /// The interlacing code should be either `0` or `1`. + /// The interlacing code should be either `0` or `1`. /// - Parameter _: /// The invalid interlacing code. - /// ## (IHDR-parsing-errors) + case invalidHeaderInterlacingCode(UInt8) - /// case PNG.ParsingError.invalidHeaderSize(_:) - /// An ``Chunk/IHDR`` chunk specified an invalid image size. + /// An ``Chunk/IHDR`` chunk specified an invalid image size. /// - /// Both size dimensions must be strictly positive. + /// Both size dimensions must be strictly positive. /// - Parameter _: /// The invalid size. - /// ## (IHDR-parsing-errors) - case invalidHeaderChunkLength(Int) - case invalidHeaderPixelFormatCode((UInt8, UInt8)) - case invalidHeaderPixelFormat(PNG.Format.Pixel, standard:PNG.Standard) - case invalidHeaderCompressionMethodCode(UInt8) - case invalidHeaderFilterCode(UInt8) - case invalidHeaderInterlacingCode(UInt8) case invalidHeaderSize((x:Int, y:Int)) - /// case PNG.ParsingError.unexpectedPalette(pixel:) - /// The parser encountered a ``Chunk/PLTE`` chunk in an image - /// with a pixel format that forbids it. + + /// The parser encountered a ``Chunk/PLTE`` chunk in an image + /// with a pixel format that forbids it. /// - Parameter pixel: /// The image pixel format. - /// ## (PLTE-parsing-errors) + case unexpectedPalette(pixel:PNG.Format.Pixel) - /// case PNG.ParsingError.invalidPaletteChunkLength(_:) - /// A ``Chunk/PLTE`` chunk had a length that is not divisible by `3`. + /// A ``Chunk/PLTE`` chunk had a length that is not divisible by `3`. /// - Parameter _: /// The chunk length. - /// ## (PLTE-parsing-errors) + case invalidPaletteChunkLength(Int) - /// case PNG.ParsingError.invalidPaletteCount(_:max:) - /// A ``Chunk/PLTE`` chunk contained more entries than allowed. + /// A ``Chunk/PLTE`` chunk contained more entries than allowed. /// - Parameter _: /// The number of palette entries. /// - Parameter max: /// The maximum allowed number of palette entries, according to the /// image bit depth. - /// ## (PLTE-parsing-errors) - case unexpectedPalette(pixel:PNG.Format.Pixel) - case invalidPaletteChunkLength(Int) case invalidPaletteCount(Int, max:Int) - /// case PNG.ParsingError.unexpectedTransparency(pixel:) - /// The parser encountered a ``Chunk/tRNS`` chunk in an image - /// with a pixel format that forbids it. + /// The parser encountered a ``Chunk/tRNS`` chunk in an image + /// with a pixel format that forbids it. /// - Parameter pixel: /// The image pixel format. - /// ## (tRNS-parsing-errors) + case unexpectedTransparency(pixel:PNG.Format.Pixel) - /// case PNG.ParsingError.invalidTransparencyChunkLength(_:expected:) - /// A ``Chunk/tRNS`` chunk had the wrong length. + /// A ``Chunk/tRNS`` chunk had the wrong length. /// - Parameter _: /// The chunk length. /// - Parameter expected: /// The expected chunk length. - /// ## (tRNS-parsing-errors) + case invalidTransparencyChunkLength(Int, expected:Int) - /// case PNG.ParsingError.invalidTransparencySample(_:max:) - /// A ``Chunk/tRNS`` chunk contained an invalid chroma key sample. + /// A ``Chunk/tRNS`` chunk contained an invalid chroma key sample. /// - Parameter _: /// The value of the invalid chroma key sample. /// - Parameter max: /// The maximum allowed value for a chroma key sample, according to the /// image color depth. - /// ## (tRNS-parsing-errors) + case invalidTransparencySample(UInt16, max:UInt16) - /// case PNG.ParsingError.invalidTransparencyCount(_:max:) - /// A ``Chunk/tRNS`` chunk contained too many alpha samples. + /// A ``Chunk/tRNS`` chunk contained too many alpha samples. /// - Parameter _: /// The number of alpha samples present. /// - Parameter max: /// The maximum allowed number of alpha samples, which is equal to /// the number of entries in the image palette. - /// ## (tRNS-parsing-errors) - case unexpectedTransparency(pixel:PNG.Format.Pixel) - case invalidTransparencyChunkLength(Int, expected:Int) - case invalidTransparencySample(UInt16, max:UInt16) case invalidTransparencyCount(Int, max:Int) - /// case PNG.ParsingError.invalidBackgroundChunkLength(_:expected:) - /// A ``Chunk/bKGD`` chunk had the wrong length. + + /// A ``Chunk/bKGD`` chunk had the wrong length. /// - Parameter _: /// The chunk length. /// - Parameter expected: /// The expected chunk length. - /// ## (bKGD-parsing-errors) + case invalidBackgroundChunkLength(Int, expected:Int) - /// case PNG.ParsingError.invalidBackgroundSample(_:max:) - /// A ``Chunk/bKGD`` chunk contained an invalid background sample. + /// A ``Chunk/bKGD`` chunk contained an invalid background sample. /// - Parameter _: /// The value of the invalid background sample. /// - Parameter max: /// The maximum allowed value for a background sample, according to the /// image color depth. - /// ## (bKGD-parsing-errors) + case invalidBackgroundSample(UInt16, max:UInt16) - /// case PNG.ParsingError.invalidBackgroundIndex(_:max:) - /// A ``Chunk/bKGD`` chunk specified an out-of-range palette index. + /// A ``Chunk/bKGD`` chunk specified an out-of-range palette index. /// - Parameter _: /// The invalid index. /// - Parameter max: /// The maximum allowed index value, which is equal to one less than /// the number of entries in the image palette. - /// ## (bKGD-parsing-errors) - case invalidBackgroundChunkLength(Int, expected:Int) - case invalidBackgroundSample(UInt16, max:UInt16) case invalidBackgroundIndex(Int, max:Int) - /// case PNG.ParsingError.invalidHistogramChunkLength(_:expected:) - /// A ``Chunk/hIST`` chunk had the wrong length. + /// A ``Chunk/hIST`` chunk had the wrong length. /// - Parameter _: /// The chunk length. /// - Parameter expected: /// The expected chunk length. - /// ## (hIST-parsing-errors) case invalidHistogramChunkLength(Int, expected:Int) - /// case PNG.ParsingError.invalidGammaChunkLength(_:) - /// A ``Chunk/gAMA`` chunk had the wrong length. + /// A ``Chunk/gAMA`` chunk had the wrong length. /// - /// Gamma chunks should be exactly `4` bytes long. + /// Gamma chunks should be exactly `4` bytes long. /// - Parameter _: /// The chunk length. - /// ## (gAMA-parsing-errors) case invalidGammaChunkLength(Int) - /// case PNG.ParsingError.invalidChromaticityChunkLength(_:) - /// A ``Chunk/cHRM`` chunk had the wrong length. + /// A ``Chunk/cHRM`` chunk had the wrong length. /// - /// Chromaticity chunks should be exactly `32` bytes long. + /// Chromaticity chunks should be exactly `32` bytes long. /// - Parameter _: /// The chunk length. - /// ## (cHRM-parsing-errors) case invalidChromaticityChunkLength(Int) - /// case PNG.ParsingError.invalidColorRenderingChunkLength(_:) - /// An ``Chunk/sRGB`` chunk had the wrong length. + /// An ``Chunk/sRGB`` chunk had the wrong length. /// - /// Color rendering chunks should be exactly `1` byte long. + /// Color rendering chunks should be exactly `1` byte long. /// - Parameter _: /// The chunk length. - /// ## (sRGB-parsing-errors) + case invalidColorRenderingChunkLength(Int) - /// case PNG.ParsingError.invalidColorRenderingCode(_:) - /// An ``Chunk/sRGB`` chunk had an invalid color rendering code. + /// An ``Chunk/sRGB`` chunk had an invalid color rendering code. /// - /// The color rendering code should be one of `0`, `1`, `2`, or `3`. + /// The color rendering code should be one of `0`, `1`, `2`, or `3`. /// - Parameter _: /// The invalid color rendering code. - /// ## (sRGB-parsing-errors) - case invalidColorRenderingChunkLength(Int) case invalidColorRenderingCode(UInt8) - /// case PNG.ParsingError.invalidSignificantBitsChunkLength(_:expected:) - /// An ``Chunk/sBIT`` chunk had the wrong length. + /// An ``Chunk/sBIT`` chunk had the wrong length. /// - Parameter _: /// The chunk length. /// - Parameter expected: /// The expected chunk length. - /// ## (sBIT-parsing-errors) + case invalidSignificantBitsChunkLength(Int, expected:Int) - /// case PNG.ParsingError.invalidSignificantBitsPrecision(_:max:) - /// An ``Chunk/sBIT`` chunk specified an invalid precision value. + /// An ``Chunk/sBIT`` chunk specified an invalid precision value. /// - Parameter _: /// The invalid precision value. /// - Parameter max: /// The maximum allowed precision value, which is equal to the image /// color depth. - /// ## (sBIT-parsing-errors) - case invalidSignificantBitsChunkLength(Int, expected:Int) case invalidSignificantBitsPrecision(Int, max:Int) - /// case PNG.ParsingError.invalidColorProfileChunkLength(_:min:) - /// An ``Chunk/iCCP`` chunk had an invalid length. + /// An ``Chunk/iCCP`` chunk had an invalid length. /// - Parameter _: /// The chunk length. /// - Parameter min: /// The minimum expected chunk length. - /// ## (iCCP-parsing-errors) + case invalidColorProfileChunkLength(Int, min:Int) - /// case PNG.ParsingError.invalidColorProfileName(_:) - /// An ``Chunk/iCCP`` chunk had an invalid profile name. + /// An ``Chunk/iCCP`` chunk had an invalid profile name. /// - Parameter _: /// The invalid profile name, or `nil` if the parser could not find /// the null-terminator of the profile name string. - /// ## (iCCP-parsing-errors) + case invalidColorProfileName(String?) - /// case PNG.ParsingError.invalidColorProfileCompressionMethodCode(_:) - /// An ``Chunk/iCCP`` chunk had an invalid compression method code. + /// An ``Chunk/iCCP`` chunk had an invalid compression method code. /// - /// The compression method code should always be `0`. + /// The compression method code should always be `0`. /// - Parameter _: /// The invalid compression method code. - /// ## (iCCP-parsing-errors) - - /// case PNG.ParsingError.incompleteColorProfileCompressedDatastream - /// The compressed data stream in an ``Chunk/iCCP`` chunk was not - /// properly terminated. - /// ## (iCCP-parsing-errors) - case invalidColorProfileChunkLength(Int, min:Int) - case invalidColorProfileName(String?) case invalidColorProfileCompressionMethodCode(UInt8) + + /// The compressed data stream in an ``Chunk/iCCP`` chunk was not + /// properly terminated. case incompleteColorProfileCompressedDatastream - /// case PNG.ParsingError.invalidPhysicalDimensionsChunkLength(_:) - /// A ``Chunk/pHYs`` chunk had the wrong length. + /// A ``Chunk/pHYs`` chunk had the wrong length. /// - /// Physical dimensions chunks should be exactly `9` bytes long. + /// Physical dimensions chunks should be exactly `9` bytes long. /// - Parameter _: /// The chunk length. - /// ## (pHYs-parsing-errors) + case invalidPhysicalDimensionsChunkLength(Int) - /// case PNG.ParsingError.invalidPhysicalDimensionsDensityUnitCode(_:) - /// A ``Chunk/pHYs`` chunk had an invalid density unit code. + /// A ``Chunk/pHYs`` chunk had an invalid density unit code. /// - /// The density code should be either `0` or `1`. + /// The density code should be either `0` or `1`. /// - Parameter _: /// The invalid density unit code. - /// ## (pHYs-parsing-errors) - case invalidPhysicalDimensionsChunkLength(Int) case invalidPhysicalDimensionsDensityUnitCode(UInt8) - /// case PNG.ParsingError.invalidSuggestedPaletteChunkLength(_:min:) - /// An ``Chunk/sPLT`` chunk had an invalid length. + /// An ``Chunk/sPLT`` chunk had an invalid length. /// - Parameter _: /// The chunk length. /// - Parameter min: /// The minimum expected chunk length. - /// ## (sPLT-parsing-errors) + case invalidSuggestedPaletteChunkLength(Int, min:Int) - /// case PNG.ParsingError.invalidSuggestedPaletteName(_:) - /// An ``Chunk/sPLT`` chunk had an invalid palette name. + /// An ``Chunk/sPLT`` chunk had an invalid palette name. /// - Parameter _: /// The invalid palette name, or `nil` if the parser could not find /// the null-terminator of the palette name string. - /// ## (sPLT-parsing-errors) + case invalidSuggestedPaletteName(String?) - /// case PNG.ParsingError.invalidSuggestedPaletteDataLength(_:stride:) - /// The length of the palette data in an ``Chunk/sPLT`` chunk was - /// not divisible by its expected stride. + /// The length of the palette data in an ``Chunk/sPLT`` chunk was + /// not divisible by its expected stride. /// - Parameter _: /// The length of the palette data. /// - Parameter stride: /// The expected stride of the palette entries. - /// ## (sPLT-parsing-errors) + case invalidSuggestedPaletteDataLength(Int, stride:Int) - /// case PNG.ParsingError.invalidSuggestedPaletteDepthCode(_:) - /// An ``Chunk/sPLT`` chunk had an invalid depth code. + /// An ``Chunk/sPLT`` chunk had an invalid depth code. /// - /// The depth code should be either `8` or `16`. + /// The depth code should be either `8` or `16`. /// - Parameter _: /// The invalid depth code. - /// ## (sPLT-parsing-errors) - - /// case PNG.ParsingError.invalidSuggestedPaletteFrequency - /// The entries in an ``Chunk/sPLT`` chunk were not ordered by - /// descending frequency. - /// ## (sPLT-parsing-errors) - case invalidSuggestedPaletteChunkLength(Int, min:Int) - case invalidSuggestedPaletteName(String?) - case invalidSuggestedPaletteDataLength(Int, stride:Int) case invalidSuggestedPaletteDepthCode(UInt8) + + /// The entries in an ``Chunk/sPLT`` chunk were not ordered by + /// descending frequency. case invalidSuggestedPaletteFrequency - /// case PNG.ParsingError.invalidTimeModifiedChunkLength(_:) - /// A ``Chunk/tIME`` chunk had the wrong length. + /// A ``Chunk/tIME`` chunk had the wrong length. /// - /// Time modified chunks should be exactly `7` bytes long. + /// Time modified chunks should be exactly `7` bytes long. /// - Parameter _: /// The chunk length. - /// ## (tIME-parsing-errors) + case invalidTimeModifiedChunkLength(Int) - /// case PNG.ParsingError.invalidTimeModifiedTime(year:month:day:hour:minute:second:) - /// A ``Chunk/tIME`` chunk specified an invalid timestamp. + /// A ``Chunk/tIME`` chunk specified an invalid timestamp. /// - Parameter year: /// The specified year. /// - Parameter month: @@ -359,75 +271,57 @@ extension PNG /// The specified minute. /// - Parameter second: /// The specified second. - /// ## (tIME-parsing-errors) - case invalidTimeModifiedChunkLength(Int) case invalidTimeModifiedTime(year:Int, month:Int, day:Int, hour:Int, minute:Int, second:Int) - /// case PNG.ParsingError.invalidTextEnglishKeyword(_:) - /// A ``Chunk/tEXt``, ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk - /// had an invalid english keyword. + /// A ``Chunk/tEXt``, ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk + /// had an invalid english keyword. /// - Parameter _: /// The invalid english keyword, or `nil` if the parser could not find /// the null-terminator of the keyword string. - /// ## (text-chunk-parsing-errors) + case invalidTextEnglishKeyword(String?) - /// case PNG.ParsingError.invalidTextChunkLength(_:min:) - /// A ``Chunk/tEXt``, ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk - /// had an invalid length. + /// A ``Chunk/tEXt``, ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk + /// had an invalid length. /// - Parameter _: /// The chunk length. /// - Parameter min: /// The minimum expected chunk length. - /// ## (text-chunk-parsing-errors) + case invalidTextChunkLength(Int, min:Int) - /// case PNG.ParsingError.invalidTextCompressionCode(_:) - /// An ``Chunk/iTXt`` chunk had an invalid compression code. + /// An ``Chunk/iTXt`` chunk had an invalid compression code. /// - /// The compression code should be either `0` or `1`. + /// The compression code should be either `0` or `1`. /// - Parameter _: /// The invalid compression code. - /// ## (text-chunk-parsing-errors) + case invalidTextCompressionCode(UInt8) - /// case PNG.ParsingError.invalidTextCompressionMethodCode(_:) - /// A ``Chunk/zTXt`` or ``Chunk/iTXt`` chunk had an invalid - /// compression method code. + /// A ``Chunk/zTXt`` or ``Chunk/iTXt`` chunk had an invalid + /// compression method code. /// - /// The compression method code should always be `0`. + /// The compression method code should always be `0`. /// - Parameter _: /// The invalid compression method code. - /// ## (text-chunk-parsing-errors) + case invalidTextCompressionMethodCode(UInt8) - /// case PNG.ParsingError.invalidTextLanguageTag(_:) - /// An ``Chunk/iTXt`` chunk had an invalid language tag. + /// An ``Chunk/iTXt`` chunk had an invalid language tag. /// - Parameter _: /// The invalid language tag component, or `nil` if the parser could /// not find the null-terminator of the language tag string. /// The language tag component is not the entire language tag string. - /// ## (text-chunk-parsing-errors) - - /// case PNG.ParsingError.invalidTextLocalizedKeyword - /// The parser could not find the null-terminator of the localized - /// keyword string in an ``Chunk/iTXt`` chunk. - /// ## (text-chunk-parsing-errors) - - /// case PNG.ParsingError.incompleteTextCompressedDatastream - /// The compressed data stream in a ``Chunk/zTXt`` or ``Chunk/iTXt`` - /// chunk was not properly terminated. - /// ## (text-chunk-parsing-errors) - case invalidTextEnglishKeyword(String?) - case invalidTextChunkLength(Int, min:Int) - case invalidTextCompressionCode(UInt8) - case invalidTextCompressionMethodCode(UInt8) case invalidTextLanguageTag(String?) + + /// The parser could not find the null-terminator of the localized + /// keyword string in an ``Chunk/iTXt`` chunk. case invalidTextLocalizedKeyword + + /// The compressed data stream in a ``Chunk/zTXt`` or ``Chunk/iTXt`` + /// chunk was not properly terminated. case incompleteTextCompressedDatastream } } extension PNG.ParsingError:PNG.Error { - /// static var PNG.ParsingError.namespace : Swift.String { get } - /// ?: Error - /// The string `"parsing error"`. + /// The string `"parsing error"`. public static var namespace:String { @@ -499,10 +393,6 @@ extension PNG.ParsingError:PNG.Error return PNG.Text.self } } - /// var PNG.ParsingError.message : Swift.String { get } - /// ?: Error - /// A human-readable summary of this error. - /// ## () public var message:String { @@ -581,11 +471,7 @@ extension PNG.ParsingError:PNG.Error return "(\(self.scope)) \(text)" } - /// var PNG.ParsingError.details : Swift.String? { get } - /// ?: Error - /// An optional human-readable string providing additional details - /// about this error. - /// ## () + public var details:String? { diff --git a/Sources/PNG/Parsing/PNG.Percentmille.swift b/Sources/PNG/Parsing/PNG.Percentmille.swift index f68c4b6d..86e2e3a4 100644 --- a/Sources/PNG/Parsing/PNG.Percentmille.swift +++ b/Sources/PNG/Parsing/PNG.Percentmille.swift @@ -1,33 +1,24 @@ extension PNG { - /// struct PNG.Percentmille - /// : Swift.AdditiveArithmetic - /// : Swift.ExpressibleByIntegerLiteral - /// A rational percentmille value. - /// ## (currency-types) + /// A rational percentmille value. public struct Percentmille:AdditiveArithmetic, ExpressibleByIntegerLiteral { - /// var PNG.Percentmille.points : Swift.Int - /// The numerator of this percentmille value. + /// The numerator of this percentmille value. /// - /// The numerical value of this percentmille instance is this integer - /// divided by `100000`. + /// The numerical value of this percentmille instance is this integer + /// divided by `100000`. public var points:Int - /// static let PNG.Percentmille.zero : Self - /// ?: Swift.AdditiveArithmetic - /// A percentmille value of zero. + /// A percentmille value of zero. public static let zero:Self = 0 - /// init PNG.Percentmille.init(_:) - /// where T:Swift.BinaryInteger - /// Creates a percentmille value with the given numerator. + /// Creates a percentmille value with the given numerator. /// - /// The numerical value of this percentmille value will be the given - /// numerator divided by `100000`. + /// The numerical value of this percentmille value will be the given + /// numerator divided by `100000`. /// - Parameter points: /// The numerator. public @@ -36,14 +27,12 @@ extension PNG self.points = .init(points) } - /// init PNG.Percentmille.init(integerLiteral:) - /// ?: Swift.ExpressibleByIntegerLiteral - /// Creates a percentmille value using the given integer literal as - /// the numerator. + /// Creates a percentmille value using the given integer literal as + /// the numerator. /// - /// The provided integer literal is *not* the numerical value of the - /// created percentmille value. It will be interpreted as the numerator - /// of a rational value. + /// The provided integer literal is *not* the numerical value of the + /// created percentmille value. It will be interpreted as the numerator + /// of a rational value. /// - Parameter integerLiteral: /// The integer literal. public @@ -52,9 +41,7 @@ extension PNG self.init(integerLiteral) } - /// static func PNG.Percentmille.(+)(_:_:) - /// ?: Swift.AdditiveArithmetic - /// Adds two percentmille values and produces their sum. + /// Adds two percentmille values and produces their sum. /// - Parameter lhs: /// The first value to add. /// - Parameter rhs: @@ -66,10 +53,8 @@ extension PNG { .init(lhs.points + rhs.points) } - /// static func PNG.Percentmille.(+=)(_:_:) - /// ?: Swift.AdditiveArithmetic - /// Adds two percentmille values and stores the result in the - /// left-hand-side variable. + /// Adds two percentmille values and stores the result in the + /// left-hand-side variable. /// - Parameter lhs: /// The first value to add. /// - Parameter rhs: @@ -79,10 +64,8 @@ extension PNG { lhs.points += rhs.points } - /// static func PNG.Percentmille.(-)(_:_:) - /// ?: Swift.AdditiveArithmetic - /// Subtracts one percentmille value from another and produces their - /// difference. + /// Subtracts one percentmille value from another and produces their + /// difference. /// - Parameter lhs: /// A percentmille value. /// - Parameter rhs: @@ -94,10 +77,8 @@ extension PNG { .init(lhs.points - rhs.points) } - /// static func PNG.Percentmille.(-=)(_:_:) - /// ?: Swift.AdditiveArithmetic - /// Subtracts one percentmille value from another and stores the - /// result in the left-hand-side variable. + /// Subtracts one percentmille value from another and stores the + /// result in the left-hand-side variable. /// - Parameter lhs: /// A percentmille value. /// - Parameter rhs: diff --git a/Sources/PNG/Parsing/PNG.PhysicalDimensions.swift b/Sources/PNG/Parsing/PNG.PhysicalDimensions.swift index 2966e4e5..cbdfff7f 100644 --- a/Sources/PNG/Parsing/PNG.PhysicalDimensions.swift +++ b/Sources/PNG/Parsing/PNG.PhysicalDimensions.swift @@ -1,39 +1,30 @@ extension PNG { - /// struct PNG.PhysicalDimensions - /// A physical dimensions descriptor. + /// A physical dimensions descriptor. /// - /// This type models the information stored in a ``Chunk/pHYs`` chunk. - /// # [Parsing and serialization](physicaldimensions-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/pHYs`` chunk. public struct PhysicalDimensions { - /// enum PNG.PhysicalDimensions.Unit - /// A unit of measurement. + /// A unit of measurement. public enum Unit { - /// case PNG.PhysicalDimensions.Unit.meter - /// The meter. + /// The meter. /// - /// For conversion purposes, one inch is assumed to equal exactly - /// `254 / 10000` meters. + /// For conversion purposes, one inch is assumed to equal exactly + /// `254 / 10000` meters. case meter } - /// let PNG.PhysicalDimensions.density : (x:Swift.Int, y:Swift.Int, unit:Unit?) - /// The number of pixels in each dimension per the given `unit` of - /// measurement. + /// The number of pixels in each dimension per the given `unit` of measurement. /// - /// If `unit` is `nil`, the pixel density is unknown, - /// and the `x` and `y` values specify the pixel aspect ratio only. + /// If `unit` is `nil`, the pixel density is unknown, + /// and the `x` and `y` values specify the pixel aspect ratio only. public let density:(x:Int, y:Int, unit:Unit?) - /// init PNG.PhysicalDimensions.init(density:) - /// Creates a physical dimensions descriptor. + /// Creates a physical dimensions descriptor. /// - Parameter density: /// The number of pixels in each dimension per the given `unit` of /// measurement. @@ -49,12 +40,9 @@ extension PNG } extension PNG.PhysicalDimensions { - /// init PNG.PhysicalDimensions.init(parsing:) - /// throws - /// Creates a physical dimensions descriptor by parsing the given chunk data. + /// Creates a physical dimensions descriptor by parsing the given chunk data. /// - Parameter data: /// The contents of a ``Chunk/pHYs`` chunk to parse. - /// ## (physicaldimensions-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -75,10 +63,7 @@ extension PNG.PhysicalDimensions throw PNG.ParsingError.invalidPhysicalDimensionsDensityUnitCode(code) } } - /// var PNG.PhysicalDimensions.serialized : [Swift.UInt8] { get } - /// Encodes this physical dimensions descriptor as the contents of a - /// ``Chunk/pHYs`` chunk. - /// ## (physicaldimensions-parsing-and-serialization) + /// Encodes this physical dimensions descriptor as the contents of a ``Chunk/pHYs`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.SignificantBits.Case.swift b/Sources/PNG/Parsing/PNG.SignificantBits.Case.swift new file mode 100644 index 00000000..6640898f --- /dev/null +++ b/Sources/PNG/Parsing/PNG.SignificantBits.Case.swift @@ -0,0 +1,55 @@ +extension PNG.SignificantBits +{ + /// A color precision case. This is a separate type for validation purposes. + @frozen public + enum Case + { + /// A color precision descriptor for a grayscale image. + /// - Parameter _: + /// The number of significant bits in each grayscale sample. + /// + /// This value must be greater than zero, and can be no greater + /// than the color depth of the image color format. + case v(Int) + /// A color precision descriptor for a grayscale-alpha image. + /// - Parameter _: + /// The number of significant bits in each grayscale and alpha + /// sample, respectively. + /// + /// Both precision values must be greater than zero, and neither + /// can be greater than the color depth of the image color format. + case va((v:Int, a:Int)) + /// A color precision descriptor for an RGB, BGR, or indexed image. + /// - Parameter _: + /// The number of significant bits in each red, green, and blue + /// sample, respectively. If the image uses an indexed color format, + /// the precision values refer to the precision of the palette + /// entries, not the indices. The ``Chunk/sBIT`` chunk type is + /// not capable of specifying the precision of the alpha component + /// of the palette entries. If the image palette was augmented with + /// alpha samples from a ``Transparency`` descriptor, the precision + /// of those samples is left undefined. + /// + /// The meaning of a color precision descriptor is + /// poorly-defined for BGR images. It is strongly recommended that + /// iphone-optimized images use ``PNG/SignificantBits`` only if all + /// samples have the same precision. + /// + /// Each precision value must be greater than zero, and none of them + /// can be greater than the color depth of the image color format. + case rgb((r:Int, g:Int, b:Int)) + /// A color precision descriptor for an RGBA or BGRA image. + /// - Parameter _: + /// The number of significant bits in each red, green, blue, and alpha + /// sample, respectively. + /// + /// The meaning of a color precision descriptor is + /// poorly-defined for BGRA images. It is strongly recommended that + /// iphone-optimized images use ``PNG/SignificantBits`` only if all + /// samples have the same precision. + /// + /// Each precision value must be greater than zero, and none of them + /// can be greater than the color depth of the image color format. + case rgba((r:Int, g:Int, b:Int, a:Int)) + } +} diff --git a/Sources/PNG/Parsing/PNG.SignificantBits.swift b/Sources/PNG/Parsing/PNG.SignificantBits.swift index 5976088d..48adc301 100644 --- a/Sources/PNG/Parsing/PNG.SignificantBits.swift +++ b/Sources/PNG/Parsing/PNG.SignificantBits.swift @@ -1,88 +1,21 @@ extension PNG { - /// struct PNG.SignificantBits - /// A color precision descriptor. + /// A color precision descriptor. /// - /// This type models the information stored in an ``Chunk/sBIT`` chunk. - /// # [Parsing and serialization](significantbits-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) - public + /// This type models the information stored in an ``Chunk/sBIT`` chunk. + @frozen public struct SignificantBits { - /// enum PNG.SignificantBits.Case - /// A color precision case. - public - enum Case - { - /// case PNG.SignificantBits.Case.v(_:) - /// A color precision descriptor for a grayscale image. - /// - Parameter _: - /// The number of significant bits in each grayscale sample. - /// - /// This value must be greater than zero, and can be no greater - /// than the color depth of the image color format. - /// ## () - case v(Int) - /// case PNG.SignificantBits.Case.va(_:) - /// A color precision descriptor for a grayscale-alpha image. - /// - Parameter _: - /// The number of significant bits in each grayscale and alpha - /// sample, respectively. - /// - /// Both precision values must be greater than zero, and neither - /// can be greater than the color depth of the image color format. - /// ## () - case va((v:Int, a:Int)) - /// case PNG.SignificantBits.Case.rgb(_:) - /// A color precision descriptor for an RGB, BGR, or indexed image. - /// - Parameter _: - /// The number of significant bits in each red, green, and blue - /// sample, respectively. If the image uses an indexed color format, - /// the precision values refer to the precision of the palette - /// entries, not the indices. The ``Chunk/sBIT`` chunk type is - /// not capable of specifying the precision of the alpha component - /// of the palette entries. If the image palette was augmented with - /// alpha samples from a ``Transparency`` descriptor, the precision - /// of those samples is left undefined. - /// - /// The meaning of a color precision descriptor is - /// poorly-defined for BGR images. It is strongly recommended that - /// iphone-optimized images use ``PNG/SignificantBits`` only if all - /// samples have the same precision. - /// - /// Each precision value must be greater than zero, and none of them - /// can be greater than the color depth of the image color format. - /// ## () - case rgb((r:Int, g:Int, b:Int)) - /// case PNG.SignificantBits.Case.rgba(_:) - /// A color precision descriptor for an RGBA or BGRA image. - /// - Parameter _: - /// The number of significant bits in each red, green, blue, and alpha - /// sample, respectively. - /// - /// The meaning of a color precision descriptor is - /// poorly-defined for BGRA images. It is strongly recommended that - /// iphone-optimized images use ``PNG/SignificantBits`` only if all - /// samples have the same precision. - /// - /// Each precision value must be greater than zero, and none of them - /// can be greater than the color depth of the image color format. - /// ## () - case rgba((r:Int, g:Int, b:Int, a:Int)) - } - /// let PNG.SignificantBits.case : Case - /// The value of this color precision descriptor. + /// The value of this color precision descriptor. let `case`:Case } } extension PNG.SignificantBits { - /// init PNG.SignificantBits.init(case:pixel:) - /// Creates a color precision descriptor. + /// Creates a color precision descriptor. /// - /// This initializer validates the precision information against the - /// given pixel format. + /// This initializer validates the precision information against the + /// given pixel format. /// - Parameter case: /// A color precision case. Each precision value in the enumeration /// payload must be greater than zero, and none of them @@ -116,16 +49,13 @@ extension PNG.SignificantBits self.case = `case` } - /// init PNG.SignificantBits.init(parsing:pixel:) - /// throws - /// Creates a color precision descriptor by parsing the given chunk data, - /// interpreting and validating it according to the given `pixel` format. + /// Creates a color precision descriptor by parsing the given chunk data, + /// interpreting and validating it according to the given `pixel` format. /// - Parameter data: /// The contents of an ``Chunk/sBIT`` chunk to parse. /// - Parameter pixel: /// The pixel format specifying how the chunk data is to be interpreted /// and validated against. - /// ## (significantbits-parsing-and-serialization) public init(parsing data:[UInt8], pixel:PNG.Format.Pixel) throws { @@ -178,10 +108,7 @@ extension PNG.SignificantBits throw PNG.ParsingError.invalidSignificantBitsPrecision(v, max: max) } } - /// var PNG.SignificantBits.serialized : [Swift.UInt8] { get } - /// Encodes this color precision descriptor as the contents of an - /// ``Chunk/sBIT`` chunk. - /// ## (significantbits-parsing-and-serialization) + /// Encodes this color precision descriptor as the contents of an ``Chunk/sBIT`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.SuggestedPalette.Entries.swift b/Sources/PNG/Parsing/PNG.SuggestedPalette.Entries.swift new file mode 100644 index 00000000..a32037b2 --- /dev/null +++ b/Sources/PNG/Parsing/PNG.SuggestedPalette.Entries.swift @@ -0,0 +1,16 @@ +extension PNG.SuggestedPalette +{ + /// A variant array of palette colors and frequencies. + @frozen public + enum Entries + { + /// A suggested palette with an 8-bit color depth. + /// - Parameter _: + /// An array of 8-bit palette colors and frequencies. + case rgba8( [(color:(r:UInt8, g:UInt8, b:UInt8, a:UInt8), frequency:UInt16)]) + /// A suggested palette with a 16-bit color depth. + /// - Parameter _: + /// An array of 16-bit palette colors and frequencies. + case rgba16([(color:(r:UInt16, g:UInt16, b:UInt16, a:UInt16), frequency:UInt16)]) + } +} diff --git a/Sources/PNG/Parsing/PNG.SuggestedPalette.swift b/Sources/PNG/Parsing/PNG.SuggestedPalette.swift index b01e0a84..cb9253c6 100644 --- a/Sources/PNG/Parsing/PNG.SuggestedPalette.swift +++ b/Sources/PNG/Parsing/PNG.SuggestedPalette.swift @@ -1,46 +1,21 @@ extension PNG { - /// struct PNG.SuggestedPalette - /// A suggested image palette. + /// A suggested image palette. /// - /// This type models the information stored in an ``Chunk/sPLT`` chunk. - /// It should not be confused with the suggested palette stored in the - /// color ``Format`` of an RGB, BGR, RGBA, or BGRA image. - /// # [Parsing and serialization](suggestedpalette-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in an ``Chunk/sPLT`` chunk. + /// It should not be confused with the suggested palette stored in the + /// color ``Format`` of an RGB, BGR, RGBA, or BGRA image. public struct SuggestedPalette { - /// enum PNG.SuggestedPalette.Entries - /// A variant array of palette colors and frequencies. - public - enum Entries - { - /// case PNG.SuggestedPalette.Entries.rgba8(_:) - /// A suggested palette with an 8-bit color depth. - /// - Parameter _: - /// An array of 8-bit palette colors and frequencies. - /// ## () - case rgba8( [(color:(r:UInt8, g:UInt8, b:UInt8, a:UInt8), frequency:UInt16)]) - /// case PNG.SuggestedPalette.Entries.rgba16(_:) - /// A suggested palette with a 16-bit color depth. - /// - Parameter _: - /// An array of 16-bit palette colors and frequencies. - /// ## () - case rgba16([(color:(r:UInt16, g:UInt16, b:UInt16, a:UInt16), frequency:UInt16)]) - } - /// let PNG.SuggestedPalette.name : Swift.String - /// The name of this suggested palette. + /// The name of this suggested palette. public let name:String - /// let PNG.SuggestedPalette.entries : Entries - /// The colors in this suggested palette, and their frequencies. + /// The colors in this suggested palette, and their frequencies. public var entries:Entries - /// init PNG.SuggestedPalette.init(name:entries:) - /// Creates a suggested palette. + /// Creates a suggested palette. /// - Parameter name: /// The palette name. /// @@ -72,12 +47,9 @@ extension PNG } extension PNG.SuggestedPalette { - /// init PNG.SuggestedPalette.init(parsing:) - /// throws - /// Creates a suggested palette by parsing the given chunk data. + /// Creates a suggested palette by parsing the given chunk data. /// - Parameter data: /// The contents of an ``Chunk/sPLT`` chunk to parse. - /// ## (suggestedpalette-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -182,10 +154,7 @@ extension PNG.SuggestedPalette return true } - /// var PNG.SuggestedPalette.serialized : [Swift.UInt8] { get } - /// Encodes this suggested palette as the contents of an - /// ``Chunk/sPLT`` chunk. - /// ## (suggestedpalette-parsing-and-serialization) + /// Encodes this suggested palette as the contents of an ``Chunk/sPLT`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Text.swift b/Sources/PNG/Parsing/PNG.Text.swift index 05e0c146..69a67816 100644 --- a/Sources/PNG/Parsing/PNG.Text.swift +++ b/Sources/PNG/Parsing/PNG.Text.swift @@ -2,47 +2,37 @@ import LZ77 extension PNG { - /// struct PNG.Text - /// A text comment. + /// A text comment. /// - /// This type models the information stored in a ``Chunk/tEXt``, - /// ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk. - /// # [Parsing and serialization](text-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/tEXt``, + /// ``Chunk/zTXt``, or ``Chunk/iTXt`` chunk. public struct Text { - /// let PNG.Text.compressed : Swift.Bool - /// Indicates if the text is (or is to be) stored in compressed or - /// uncompressed form within a PNG file. + /// Indicates if the text is (or is to be) stored in compressed or + /// uncompressed form within a PNG file. /// - /// This flag is `true` if the original text chunk was a - /// ``Chunk/zTXt`` chunk, and `false` if it was a ``Chunk/tEXt`` - /// chunk. If the original chunk was an ``Chunk/iTXt`` chunk, - /// this flag can be either `true` or `false`. + /// This flag is `true` if the original text chunk was a + /// ``Chunk/zTXt`` chunk, and `false` if it was a ``Chunk/tEXt`` + /// chunk. If the original chunk was an ``Chunk/iTXt`` chunk, + /// this flag can be either `true` or `false`. public let compressed:Bool - /// let PNG.Text.keyword : (english:Swift.String, localized:Swift.String) - /// A keyword tag, in english, and possibly a non-english language. + /// A keyword tag, in english, and possibly a non-english language. /// - /// If the text is in english, the `localized` keyword is the empty - /// string `""`. + /// If the text is in english, the `localized` keyword is the empty string `""`. public let keyword:(english:String, localized:String), - /// let PNG.Text.language : [Swift.String] - /// An array representing an [rfc-1766](https://www.ietf.org/rfc/rfc1766.txt) - /// language tag, where each element is a language subtag. + /// An array representing an [rfc-1766](https://www.ietf.org/rfc/rfc1766.txt) + /// language tag, where each element is a language subtag. /// - /// If this array is empty, then the language is unspecified. + /// If this array is empty, then the language is unspecified. language:[String] - /// let PNG.Text.content : Swift.String - /// The text content. + /// The text content. public let content:String - /// init PNG.Text.init(compressed:keyword:language:content:) - /// Creates a text comment. + /// Creates a text comment. /// - Parameter compressed: /// Indicates if the text is to be stored in compressed or /// uncompressed form within a PNG file. @@ -103,10 +93,8 @@ extension PNG } extension PNG.Text { - /// init PNG.Text.init(parsing:unicode:) - /// throws - /// Creates a text comment by parsing the given chunk data, interpreting - /// it either as a unicode text chunk, or a latin-1 text chunk. + /// Creates a text comment by parsing the given chunk data, interpreting + /// it either as a unicode text chunk, or a latin-1 text chunk. /// - Parameter data: /// The contents of a ``Chunk/tEXt``, ``Chunk/zTXt``, or ``Chunk/iTXt`` /// chunk to parse. @@ -118,7 +106,6 @@ extension PNG.Text /// /// If this flag is set to `false`, the text is assumed to be in english, /// and the ``language`` tag will be set to `["en"]`. - /// ## (text-parsing-and-serialization) public init(parsing data:[UInt8], unicode:Bool = true) throws { @@ -312,16 +299,12 @@ extension PNG.Text return scalars.allSatisfy{ "a" ... "z" ~= $0 || "A" ... "Z" ~= $0 } } - /// var PNG.Text.serialized : [Swift.UInt8] { get } - /// Encodes this text comment as the contents of a - /// ``Chunk/iTXt`` chunk. + /// Encodes this text comment as the contents of a ``Chunk/iTXt`` chunk. /// - /// This property *always* emits a unicode ``Chunk/iTXt`` - /// chunk, regardless of the type of the original chunk, if it was parsed - /// from raw chunk data. It is the opinion of the library that the - /// latin-1 chunk types ``Chunk/tEXt`` and ``Chunk/zTXt`` are - /// deprecated. - /// ## (text-parsing-and-serialization) + /// This property *always* emits a unicode ``Chunk/iTXt`` + /// chunk, regardless of the type of the original chunk, if it was parsed + /// from raw chunk data. It is the opinion of the library that the + /// latin-1 chunk types ``Chunk/tEXt`` and ``Chunk/zTXt`` are deprecated. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.TimeModified.swift b/Sources/PNG/Parsing/PNG.TimeModified.swift index b052b88d..39f6c7f9 100644 --- a/Sources/PNG/Parsing/PNG.TimeModified.swift +++ b/Sources/PNG/Parsing/PNG.TimeModified.swift @@ -1,50 +1,37 @@ extension PNG { - /// struct PNG.TimeModified - /// An image modification time. + /// An image modification time. /// - /// This type models the information stored in a ``Chunk/tIME`` chunk. - /// This type is time-zone agnostic, and so all time values are assumed - /// to be in universal time (UTC). - /// # [Parsing and serialization](timemodified-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// This type models the information stored in a ``Chunk/tIME`` chunk. + /// This type is time-zone agnostic, and so all time values are assumed + /// to be in universal time (UTC). public struct TimeModified { - /// let PNG.TimeModified.year : Swift.Int - /// The complete [gregorian](https://en.wikipedia.org/wiki/Gregorian_calendar) - /// year. - /// ## () + /// The complete [gregorian](https://en.wikipedia.org/wiki/Gregorian_calendar) year. public - let year:Int, - /// let PNG.TimeModified.month : Swift.Int - /// The calendar month, expressed as a 1-indexed integer. - /// ## () - month:Int, - /// let PNG.TimeModified.day : Swift.Int - /// The calendar day, expressed as a 1-indexed integer. - /// ## () - day:Int, - /// let PNG.TimeModified.hour : Swift.Int - /// The hour, in 24-hour time, expressed as a 0-indexed integer. - /// ## () - hour:Int, - /// let PNG.TimeModified.minute : Swift.Int - /// The minute, expressed as a 0-indexed integer. - /// ## () - minute:Int, - /// let PNG.TimeModified.second : Swift.Int - /// The second, expressed as a 0-indexed integer. - /// ## () - second:Int + let year:Int + /// The calendar month, expressed as a 1-indexed integer. + public + let month:Int + /// The calendar day, expressed as a 1-indexed integer. + public + let day:Int + /// The hour, in 24-hour time, expressed as a 0-indexed integer. + public + let hour:Int + /// The minute, expressed as a 0-indexed integer. + public + let minute:Int + /// The second, expressed as a 0-indexed integer. + public + let second:Int - /// init PNG.TimeModified.init(year:month:day:hour:minute:second:) - /// Creates an image modification time. + /// Creates an image modification time. /// - /// The time is time-zone agnostic, and so all time parameters are - /// assumed to be in universal time (UTC). Passing out-of-range - /// time parameters will result in a precondition failure. + /// The time is time-zone agnostic, and so all time parameters are + /// assumed to be in universal time (UTC). Passing out-of-range + /// time parameters will result in a precondition failure. /// - Parameter year: /// The complete [gregorian](https://en.wikipedia.org/wiki/Gregorian_calendar) /// year. It must be in the range `0 ..< 1 << 16`. It can be @@ -96,12 +83,9 @@ extension PNG } extension PNG.TimeModified { - /// init PNG.TimeModified.init(parsing:) - /// throws - /// Creates an image modification time by parsing the given chunk data. + /// Creates an image modification time by parsing the given chunk data. /// - Parameter data: /// The contents of a ``Chunk/tIME`` chunk to parse. - /// ## (timemodified-parsing-and-serialization) public init(parsing data:[UInt8]) throws { @@ -135,10 +119,7 @@ extension PNG.TimeModified second: self.second) } } - /// var PNG.TimeModified.serialized : [Swift.UInt8] { get } - /// Encodes this image modification time as the contents of a - /// ``Chunk/tIME`` chunk. - /// ## (timemodified-parsing-and-serialization) + /// Encodes this image modification time as the contents of a ``Chunk/tIME`` chunk. public var serialized:[UInt8] { diff --git a/Sources/PNG/Parsing/PNG.Transparency.Case.swift b/Sources/PNG/Parsing/PNG.Transparency.Case.swift new file mode 100644 index 00000000..d45954f6 --- /dev/null +++ b/Sources/PNG/Parsing/PNG.Transparency.Case.swift @@ -0,0 +1,36 @@ +extension PNG.Transparency +{ + /// A transparency case. This is a separate type for validation purposes. + @frozen public + enum Case + { + /// A transparency descriptor for an indexed image. + /// - Parameter alpha: + /// An array of alpha samples, where each sample augments an + /// RGB triple in an image ``Palette``. This array can contain no + /// more elements than entries in the image palette, but it can + /// contain fewer. + /// + /// It is acceptable (though pointless) for the `alpha` array to be + /// empty. + case palette(alpha:[UInt8]) + /// A transparency descriptor for an RGB or BGR image. + /// - Parameter key: + /// A chroma key used to display transparency. Pixels + /// matching this key will be displayed as transparent, if possible. + /// + /// Note that the chroma key components are unscaled samples. If + /// the image color depth is less than `16`, only the least-significant + /// bits of each sample are inhabited. + case rgb(key:(r:UInt16, g:UInt16, b:UInt16)) + /// A transparency descriptor for a grayscale image. + /// - Parameter key: + /// A chroma key used to display transparency. Pixels + /// matching this key will be displayed as transparent, if possible. + /// + /// Note that the chroma key is an unscaled sample. If + /// the image color depth is less than `16`, only the least-significant + /// bits are inhabited. + case v(key:UInt16) + } +} diff --git a/Sources/PNG/Parsing/PNG.Transparency.swift b/Sources/PNG/Parsing/PNG.Transparency.swift index 03088218..9a5f3d76 100644 --- a/Sources/PNG/Parsing/PNG.Transparency.swift +++ b/Sources/PNG/Parsing/PNG.Transparency.swift @@ -1,74 +1,30 @@ extension PNG { - /// struct PNG.Transparency - /// A transparency descriptor. + /// A transparency descriptor. /// - /// This type models the information stored in a ``Chunk/tRNS`` chunk. - /// This information either used to populate the `key` field in - /// an image color ``Format``, or augment its `palette` field, when appropriate. + /// This type models the information stored in a ``Chunk/tRNS`` chunk. + /// This information either used to populate the `key` field in + /// an image color ``Format``, or augment its `palette` field, when appropriate. /// - /// The value of this descriptor is stored in the ``PNG.Transparency/case`` - /// property, after validation. - /// # [Parsing and serialization](transparency-parsing-and-serialization) - /// # [See also](parsed-chunk-types) - /// ## (parsed-chunk-types) + /// The value of this descriptor is stored in the ``PNG.Transparency/case`` + /// property, after validation. public struct Transparency { - /// enum PNG.Transparency.Case - /// A transparency case. - public - enum Case - { - /// case PNG.Transparency.Case.palette(alpha:) - /// A transparency descriptor for an indexed image. - /// - Parameter alpha: - /// An array of alpha samples, where each sample augments an - /// RGB triple in an image ``Palette``. This array can contain no - /// more elements than entries in the image palette, but it can - /// contain fewer. - /// - /// It is acceptable (though pointless) for the `alpha` array to be - /// empty. - case palette(alpha:[UInt8]) - /// case PNG.Transparency.Case.rgb(key:) - /// A transparency descriptor for an RGB or BGR image. - /// - Parameter key: - /// A chroma key used to display transparency. Pixels - /// matching this key will be displayed as transparent, if possible. - /// - /// Note that the chroma key components are unscaled samples. If - /// the image color depth is less than `16`, only the least-significant - /// bits of each sample are inhabited. - case rgb(key:(r:UInt16, g:UInt16, b:UInt16)) - /// case PNG.Transparency.Case.v(key:) - /// A transparency descriptor for a grayscale image. - /// - Parameter key: - /// A chroma key used to display transparency. Pixels - /// matching this key will be displayed as transparent, if possible. - /// - /// Note that the chroma key is an unscaled sample. If - /// the image color depth is less than `16`, only the least-significant - /// bits are inhabited. - case v(key:UInt16) - } - - /// let PNG.Transparency.case : Case - /// The value of this transparency descriptor. + /// The value of this transparency descriptor. public let `case`:Case } } extension PNG.Transparency { - /// init PNG.Transparency.init(case:pixel:palette:) - /// Creates a transparency descriptor. + /// Creates a transparency descriptor. /// - /// This initializer validates the transparency information against the - /// given pixel format and image palette. Some `pixel` formats imply - /// that `palette` must be `nil`. This initializer does not check this - /// assumption, as it is expected to have been verified by - /// ``Palette.init(entries:pixel:)``. + /// This initializer validates the transparency information against the + /// given pixel format and image palette. Some `pixel` formats imply + /// that `palette` must be `nil`. This initializer does not check this + /// assumption, as it is expected to have been verified by + /// ``Palette.init(entries:pixel:)``. /// - Parameter case: /// A transparency descriptor value. /// @@ -151,15 +107,13 @@ extension PNG.Transparency self.case = `case` } - /// init PNG.Transparency.init(parsing:pixel:palette:) - /// throws - /// Creates a transparency descriptor by parsing the given chunk data, - /// interpreting and validating it according to the given `pixel` format and - /// image `palette`. + /// Creates a transparency descriptor by parsing the given chunk data, + /// interpreting and validating it according to the given `pixel` format and + /// image `palette`. /// - /// Some `pixel` formats imply that `palette` must be `nil`. - /// This initializer does not check this assumption, as it is expected - /// to have been verified by ``Palette.init(parsing:pixel:)``. + /// Some `pixel` formats imply that `palette` must be `nil`. + /// This initializer does not check this assumption, as it is expected + /// to have been verified by ``Palette.init(parsing:pixel:)``. /// - Parameter data: /// The contents of a ``Chunk/tRNS`` chunk to parse. /// - Parameter pixel: @@ -168,7 +122,6 @@ extension PNG.Transparency /// - Parameter palette: /// The image palette the chunk data is to be validated against, if /// applicable. - /// ## (transparency-parsing-and-serialization) public init(parsing data:[UInt8], pixel:PNG.Format.Pixel, palette:PNG.Palette?) throws { @@ -225,10 +178,7 @@ extension PNG.Transparency throw PNG.ParsingError.unexpectedTransparency(pixel: pixel) } } - /// var PNG.Transparency.serialized : [Swift.UInt8] { get } - /// Encodes this transparency descriptor as the contents of a - /// ``Chunk/tRNS`` chunk. - /// ## (transparency-parsing-and-serialization) + /// Encodes this transparency descriptor as the contents of a ``Chunk/tRNS`` chunk. public var serialized:[UInt8] {