pure_jpeg 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +6 -5
- data/lib/pure_jpeg/encoder.rb +12 -2
- data/lib/pure_jpeg/source/raw_source.rb +1 -2
- data/lib/pure_jpeg/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a0015f811a2250264bfa73727aa37af15fee1af10e4897243045f2f4f54ae07
|
|
4
|
+
data.tar.gz: 5085ab8c4bd1d9941c94e116b39ea7ca38f658fdf0e48523cae65fc913f765d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b507962b2ec9650e743b365b8ace5ddb2a9c1d04de126206ac6062c9da46001dc3e8a1f04df356187b3a2458f3383625d864fe12ee0b3c5e3df589755aa540aa
|
|
7
|
+
data.tar.gz: 7bf019ea4702bbd7379ad3a1d295acaadd47b185815461b810c08c33299248235b326e9d0cdcfbebe23646f32014487c55212517a9e8a246d4fd5d40891eb62f
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -198,12 +198,13 @@ Possible future improvements: AAN/fixed-point DCT (but it's a LOT of work), ICC
|
|
|
198
198
|
|
|
199
199
|
## Performance
|
|
200
200
|
|
|
201
|
-
On a 1024x1024 image (Ruby 4.0.1 on my
|
|
201
|
+
On a 1024x1024 image (Ruby 4.0.1 on my M5):
|
|
202
202
|
|
|
203
203
|
| Operation | Time |
|
|
204
204
|
|-----------|------|
|
|
205
|
-
| Encode (color, q85) | ~1.
|
|
206
|
-
| Decode (
|
|
205
|
+
| Encode (color, q85) | ~1.2s |
|
|
206
|
+
| Decode (baseline) | ~1.2s |
|
|
207
|
+
| Decode (progressive) | ~1.3s |
|
|
207
208
|
|
|
208
209
|
Both the encoder and decoder use a separable DCT with a precomputed cosine matrix and reuse all per-block buffers to minimize GC pressure. Pixel data is stored as packed integers internally to avoid per-pixel object allocation.
|
|
209
210
|
|
|
@@ -212,7 +213,7 @@ Both the encoder and decoder use a separable DCT with a precomputed cosine matri
|
|
|
212
213
|
```
|
|
213
214
|
bundle install
|
|
214
215
|
rake test # run the test suite
|
|
215
|
-
rake benchmark # benchmark encoding (3 runs
|
|
216
|
+
rake benchmark # benchmark encoding and decoding (3 runs each)
|
|
216
217
|
rake profile # CPU profile with StackProf (requires the stackprof gem)
|
|
217
218
|
```
|
|
218
219
|
|
|
@@ -222,7 +223,7 @@ rake profile # CPU profile with StackProf (requires the stackprof gem)
|
|
|
222
223
|
|
|
223
224
|
**I have read all of the code produced up to v0.2.0.** The algorithms are above my paygrade, but I'm OK with what has been produced, and I manually fixed a variety of stylistic things along the way. For example, CC seems to like wrapping entire functions in `if` statements rather than bailing on the opposite condition. *Later update: I have not read the ICC and optimized Huffman code yet, but it is heavily tested.*
|
|
224
225
|
|
|
225
|
-
**CC needed a lot of guidance.** Its initial JPEG algorithm was somewhat naive and output odd looking JPEGs akin to those of my
|
|
226
|
+
**CC needed a lot of guidance.** Its initial JPEG algorithm was somewhat naive and output odd looking JPEGs akin to those of my [Casio QV-10 digital camera](https://medium.com/people-gadgets/the-gadget-we-miss-the-casio-qv-10-digital-camera-c25ab786ce49) from the late 1990s. After some back and forth and image comparisons, we figured out it was doing the quantization entirely wrong (specifically not using the zigzag approach during quanitization but just going in raster order). I *like* this aesthetic, but fixed it up so that it works as a generally usable JPEG library, while adding ways to customize things so you can recreate the effect, if preferred (see `CREATIVE.md` for more on that).
|
|
226
227
|
|
|
227
228
|
**CC is lazy.** The initial implementation was VERY SLOW. It took 15 seconds to turn a 1024x1024 PNG into a JPEG, so we went down the profiling rabbit hole and found many optimizations to make it ~6x faster. CC is poor at considering the role of Ruby's GC when implementing low level algorithms and needs some prodding to make the correct optimizations. CC is also lazy to the point of recommending that you just use another language (e.g. Go or Rust) rather than do a pure Ruby version of something - despite it being possible with some extra work.
|
|
228
229
|
|
data/lib/pure_jpeg/encoder.rb
CHANGED
|
@@ -76,17 +76,27 @@ module PureJPEG
|
|
|
76
76
|
|
|
77
77
|
def build_lum_qtable
|
|
78
78
|
table = @luminance_table || Quantization.scale_table(Quantization::LUMINANCE_BASE, quality)
|
|
79
|
-
table =
|
|
79
|
+
table = apply_quantization_modifier(table, :luminance) if @quantization_modifier
|
|
80
80
|
table
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def build_chr_qtable
|
|
84
84
|
table = @chrominance_table || Quantization.scale_table(Quantization::CHROMINANCE_BASE, @chroma_quality)
|
|
85
|
-
table =
|
|
85
|
+
table = apply_quantization_modifier(table, :chrominance) if @quantization_modifier
|
|
86
86
|
table
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def apply_quantization_modifier(table, channel)
|
|
90
|
+
modified = @quantization_modifier.call(table, channel)
|
|
91
|
+
validate_qtable!(modified, "quantization_modifier result for #{channel}")
|
|
92
|
+
modified
|
|
93
|
+
end
|
|
94
|
+
|
|
89
95
|
def validate_qtable!(table, name)
|
|
96
|
+
unless table.respond_to?(:length) && table.respond_to?(:all?)
|
|
97
|
+
raise ArgumentError, "#{name} must be a 64-element array of integers between 1 and 255"
|
|
98
|
+
end
|
|
99
|
+
|
|
90
100
|
raise ArgumentError, "#{name} must have exactly 64 elements (got #{table.length})" unless table.length == 64
|
|
91
101
|
unless table.all? { |v| v.is_a?(Integer) && v >= 1 && v <= 255 }
|
|
92
102
|
raise ArgumentError, "#{name} elements must be integers between 1 and 255"
|
|
@@ -27,8 +27,7 @@ module PureJPEG
|
|
|
27
27
|
def initialize(width, height, &block)
|
|
28
28
|
@width = width
|
|
29
29
|
@height = height
|
|
30
|
-
|
|
31
|
-
@pixels = Array.new(width * height, black)
|
|
30
|
+
@pixels = Array.new(width * height) { Pixel.new(0, 0, 0) }
|
|
32
31
|
|
|
33
32
|
if block
|
|
34
33
|
height.times do |y|
|
data/lib/pure_jpeg/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pure_jpeg
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Cooper
|
|
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
87
|
version: '0'
|
|
88
88
|
requirements: []
|
|
89
|
-
rubygems_version:
|
|
89
|
+
rubygems_version: 4.0.3
|
|
90
90
|
specification_version: 4
|
|
91
91
|
summary: Pure Ruby JPEG encoder and decoder
|
|
92
92
|
test_files: []
|