| // Copyright 2019 The Wuffs Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // ---------------- | |
| // Package compression provides common types for other compression packages. | |
| package compression | |
| import ( | |
| "io" | |
| ) | |
| // Reader is an io.ReadCloser with a Reset method. | |
| type Reader interface { | |
| io.ReadCloser | |
| // Reset resets this Reader to switch to a new underlying io.Reader. This | |
| // permits re-using a Reader instead of allocating a new one. | |
| // | |
| // It is the same as the standard library's zlib.Resetter's method. | |
| Reset(r io.Reader, dictionary []byte) error | |
| } | |
| // Writer is an io.WriteCloser with a Reset method. | |
| type Writer interface { | |
| io.WriteCloser | |
| // Reset resets this Writer to switch to a new underlying io.Writer. This | |
| // permits re-using a Writer instead of allocating a new one. | |
| Reset(w io.Writer, dictionary []byte, level Level) error | |
| } | |
| // Level configures the compression trade-off between speed and size. | |
| // | |
| // A lower (more negative) value means better speed (faster). A higher (more | |
| // positive) value means better size (smaller). | |
| type Level int32 | |
| const ( | |
| // LevelFastest means to maximize compression speed. | |
| LevelFastest Level = -2 << 10 | |
| // LevelFast means to prioritize compression speed. | |
| // | |
| // It might not be as fast as LevelFastest, if doing so would require | |
| // substantial additional compute resources (e.g. CPU or RAM) or give up | |
| // substantial compression size. | |
| LevelFast Level = -1 << 10 | |
| // LevelDefault means to use a reasonable default. | |
| LevelDefault Level = 0 | |
| // LevelSmall means to prioritize compression size. | |
| // | |
| // It might not be as small as LevelSmallest, if doing so would require | |
| // substantial additional compute resources (e.g. CPU or RAM) or give up | |
| // substantial compression speed. | |
| LevelSmall Level = +1 << 10 | |
| // LevelSmallest means to minimize compression size. | |
| LevelSmallest Level = +2 << 10 | |
| // gap is the difference between each named Level. | |
| gap = 1 << 10 | |
| ) | |
| // Interpolate translates from Level (a codec-independent concept) to a | |
| // codec-specific compression level numbering scheme. For exampe, a zlib | |
| // package might translate LevelFastest to 1 and LevelSmallest to 9 by calling | |
| // Interpolate(1, 2, 6, 9, 9). | |
| // | |
| // The mapping is via piecewise linear interpolation, given by five points in | |
| // (Level, int32) space: (LevelFastest, fastest), (LevelFast, fast), etc. | |
| func (l Level) Interpolate(fastest int32, fast int32, default_ int32, small int32, smallest int32) int32 { | |
| if l == 0 { | |
| return default_ | |
| } else if l <= LevelFastest { | |
| return fastest | |
| } else if l <= LevelFast { | |
| return interpolate(-l+LevelFast, fast, fastest) | |
| } else if l < 0 { | |
| return interpolate(-l, default_, fast) | |
| } else if l >= LevelSmallest { | |
| return smallest | |
| } else if l >= LevelSmall { | |
| return interpolate(+l-LevelSmall, small, smallest) | |
| } else if l > 0 { | |
| return interpolate(+l, default_, small) | |
| } | |
| panic("unreachable") | |
| } | |
| func interpolate(relative Level, ia int32, ib int32) int32 { | |
| x := int64(ib-ia) * int64(relative) / gap | |
| return ia + int32(x) | |
| } |