oil 0.1.3 → 0.2.0
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 +5 -5
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -0
- data/Rakefile +1 -3
- data/ext/oil/extconf.rb +1 -1
- data/ext/oil/jpeg.c +68 -42
- data/ext/oil/oil.c +19 -2
- data/ext/oil/png.c +52 -31
- data/ext/oil/resample.c +719 -245
- data/ext/oil/resample.h +101 -28
- data/lib/oil.rb +2 -39
- data/test/test_png.rb +1 -2
- metadata +3 -5
- data/ext/oil/yscaler.c +0 -167
- data/ext/oil/yscaler.h +0 -33
data/ext/oil/resample.h
CHANGED
@@ -1,46 +1,119 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2014-2016 Timothy Elliott
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
* of this software and associated documentation files (the "Software"), to deal
|
5
|
+
* in the Software without restriction, including without limitation the rights
|
6
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
* copies of the Software, and to permit persons to whom the Software is
|
8
|
+
* furnished to do so, subject to the following conditions:
|
9
|
+
*
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
11
|
+
* all copies or substantial portions of the Software.
|
12
|
+
*
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
* THE SOFTWARE.
|
20
|
+
*/
|
21
|
+
|
1
22
|
#ifndef RESAMPLE_H
|
2
23
|
#define RESAMPLE_H
|
3
24
|
|
4
|
-
#
|
25
|
+
#include <stdint.h>
|
26
|
+
#include <stddef.h>
|
27
|
+
|
28
|
+
enum oil_colorspace {
|
29
|
+
OIL_CS_G = 0x0001,
|
30
|
+
OIL_CS_GA = 0x0002,
|
31
|
+
OIL_CS_RGB = 0x0003,
|
32
|
+
OIL_CS_RGBX = 0x0004,
|
33
|
+
OIL_CS_RGBA = 0x0104,
|
34
|
+
OIL_CS_CMYK = 0x0204,
|
35
|
+
};
|
36
|
+
#define CS_TO_CMP(x) (x&0xFF)
|
37
|
+
|
38
|
+
struct sl_rbuf {
|
39
|
+
uint32_t height; // number of scanlines that the ring buffer can hold
|
40
|
+
size_t length; // width in bytes of each scanline in the buffer
|
41
|
+
uint32_t count; // total no. of scanlines that have been fed in
|
42
|
+
uint16_t *buf; // buffer for the ring buffer
|
43
|
+
uint16_t **virt; // space to provide scanline pointers for scaling
|
44
|
+
};
|
5
45
|
|
6
46
|
/**
|
7
|
-
*
|
47
|
+
* Struct to hold state for y-scaling.
|
8
48
|
*/
|
9
|
-
|
10
|
-
|
49
|
+
struct yscaler {
|
50
|
+
struct sl_rbuf rb; // ring buffer holding scanlines.
|
51
|
+
uint32_t in_height; // input image height.
|
52
|
+
uint32_t out_height; // output image height.
|
53
|
+
uint32_t width;
|
54
|
+
enum oil_colorspace cs;
|
55
|
+
uint32_t target; // where the ring buffer should be on next scaling.
|
56
|
+
float ty; // sub-pixel offset for next scaling.
|
57
|
+
};
|
11
58
|
|
12
59
|
/**
|
13
|
-
*
|
14
|
-
*
|
60
|
+
* Initialize a yscaler struct. Calculates how large the scanline ring buffer
|
61
|
+
* will need to be and allocates it.
|
15
62
|
*/
|
16
|
-
|
63
|
+
int yscaler_init(struct yscaler *ys, uint32_t in_height, uint32_t out_height,
|
64
|
+
uint32_t width, enum oil_colorspace cs);
|
17
65
|
|
18
66
|
/**
|
19
|
-
*
|
20
|
-
* corresponding input position and put the sub-pixel remainder in rest.
|
67
|
+
* Free a yscaler struct, including the ring buffer.
|
21
68
|
*/
|
22
|
-
|
23
|
-
float *rest);
|
69
|
+
void yscaler_free(struct yscaler *ys);
|
24
70
|
|
25
71
|
/**
|
26
|
-
*
|
27
|
-
*
|
28
|
-
|
29
|
-
*
|
30
|
-
|
31
|
-
|
32
|
-
*
|
33
|
-
*
|
34
|
-
* array.
|
35
|
-
*
|
36
|
-
* The ty parameter indicates how far our mapped sampling position is from the
|
37
|
-
* center of the strip.
|
72
|
+
* Get a pointer to the next scanline to be filled in the ring buffer. Returns
|
73
|
+
* null if no more scanlines are needed to perform scaling.
|
74
|
+
*/
|
75
|
+
uint16_t *yscaler_next(struct yscaler *ys);
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Scale the buffered contents of the yscaler to produce the next scaled output
|
79
|
+
* scanline.
|
38
80
|
*
|
39
|
-
*
|
40
|
-
*
|
41
|
-
*
|
81
|
+
* Scaled scanline will be written to the out parameter.
|
82
|
+
* The width parameter is the nuber of samples in each scanline.
|
83
|
+
* The cmp parameter is the number of components per sample (3 for RGB).
|
84
|
+
* The pos parameter is the position of the output scanline.
|
85
|
+
*/
|
86
|
+
int yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t pos);
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Struct to hold state for x-scaling.
|
90
|
+
*/
|
91
|
+
struct xscaler {
|
92
|
+
uint16_t *psl_buf;
|
93
|
+
uint16_t *psl_pos0;
|
94
|
+
size_t psl_offset;
|
95
|
+
uint32_t width_in;
|
96
|
+
uint32_t width_out;
|
97
|
+
enum oil_colorspace cs;
|
98
|
+
};
|
99
|
+
|
100
|
+
struct preprocess_xscaler {
|
101
|
+
struct xscaler xs;
|
102
|
+
uint32_t width_in;
|
103
|
+
enum oil_colorspace cs_in;
|
104
|
+
uint32_t scale_factor;
|
105
|
+
};
|
106
|
+
|
107
|
+
int preprocess_xscaler_init(struct preprocess_xscaler *pxs, uint32_t width_in,
|
108
|
+
uint32_t width_out, enum oil_colorspace cs_in);
|
109
|
+
void preprocess_xscaler_scale(struct preprocess_xscaler *pxs, uint8_t *in,
|
110
|
+
uint16_t *out);
|
111
|
+
void preprocess_xscaler_free(struct preprocess_xscaler *pxs);
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Utility helpers.
|
42
115
|
*/
|
43
|
-
void
|
44
|
-
|
116
|
+
void fix_ratio(uint32_t src_width, uint32_t src_height, uint32_t *out_width,
|
117
|
+
uint32_t *out_height);
|
45
118
|
|
46
119
|
#endif
|
data/lib/oil.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Oil
|
2
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.2.0"
|
3
3
|
|
4
4
|
def self.sniff_signature(io)
|
5
5
|
a = io.getc
|
@@ -27,30 +27,6 @@ module Oil
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def self.fix_ratio(sw, sh, boxw, boxh)
|
31
|
-
x = boxw / sw.to_f
|
32
|
-
y = boxh / sh.to_f
|
33
|
-
|
34
|
-
destw = boxw
|
35
|
-
desth = boxh
|
36
|
-
|
37
|
-
if x < y
|
38
|
-
desth = (sh * x).round
|
39
|
-
else
|
40
|
-
destw = (sw * y).round
|
41
|
-
end
|
42
|
-
|
43
|
-
if desth < 1
|
44
|
-
desth = 1
|
45
|
-
end
|
46
|
-
|
47
|
-
if destw < 1
|
48
|
-
destw = 1
|
49
|
-
end
|
50
|
-
|
51
|
-
return destw, desth
|
52
|
-
end
|
53
|
-
|
54
30
|
def self.new_jpeg_reader(io, box_width, box_height)
|
55
31
|
o = JPEGReader.new(io, [:COM, :APP1, :APP2])
|
56
32
|
|
@@ -60,20 +36,7 @@ module Oil
|
|
60
36
|
end
|
61
37
|
|
62
38
|
# JPEG Pre-scaling is equivalent to a box filter at an integer scale factor.
|
63
|
-
|
64
|
-
# get proper bicubic scaling in the final image.
|
65
|
-
inv_scale = o.image_width / box_width
|
66
|
-
inv_scale /= 4
|
67
|
-
|
68
|
-
if inv_scale >= 8
|
69
|
-
o.scale_denom = 8
|
70
|
-
elsif inv_scale >= 4
|
71
|
-
o.scale_denom = 4
|
72
|
-
elsif inv_scale >= 2
|
73
|
-
o.scale_denom = 2
|
74
|
-
end
|
75
|
-
|
76
|
-
destw, desth = self.fix_ratio(o.output_width, o.output_height, box_width, box_height)
|
39
|
+
destw, desth = Oil.fix_ratio(o.output_width, o.output_height, box_width, box_height)
|
77
40
|
o.scale_width = destw
|
78
41
|
o.scale_height = desth
|
79
42
|
|
data/test/test_png.rb
CHANGED
@@ -42,7 +42,6 @@ class TestPNG < MiniTest::Test
|
|
42
42
|
def test_bogus_end_chunk
|
43
43
|
str = PNG_DATA.dup
|
44
44
|
str[-6] = "\x10"
|
45
|
-
io = StringIO.new(str)
|
46
45
|
o = Oil::PNGReader.new(png_io)
|
47
46
|
assert_equal 1, o.width
|
48
47
|
assert_equal 1, o.height
|
@@ -134,7 +133,7 @@ class TestPNG < MiniTest::Test
|
|
134
133
|
def test_each_shrinks_buffer
|
135
134
|
Oil::PNGReader.new(png_io).each { |d| d.slice!(0, 4) }
|
136
135
|
end
|
137
|
-
|
136
|
+
|
138
137
|
def test_each_enlarges_buffer
|
139
138
|
Oil::PNGReader.new(png_io).each { |d| d << "foobar" }
|
140
139
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Timothy Elliott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Resize JPEG and PNG images, aiming for fast performance and low memory
|
14
14
|
use.
|
@@ -28,8 +28,6 @@ files:
|
|
28
28
|
- ext/oil/png.c
|
29
29
|
- ext/oil/resample.c
|
30
30
|
- ext/oil/resample.h
|
31
|
-
- ext/oil/yscaler.c
|
32
|
-
- ext/oil/yscaler.h
|
33
31
|
- lib/oil.rb
|
34
32
|
- test/helper.rb
|
35
33
|
- test/test_jpeg.rb
|
@@ -54,7 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
52
|
version: '0'
|
55
53
|
requirements: []
|
56
54
|
rubyforge_project:
|
57
|
-
rubygems_version: 2.
|
55
|
+
rubygems_version: 2.7.6
|
58
56
|
signing_key:
|
59
57
|
specification_version: 4
|
60
58
|
summary: Resize JPEG and PNG images.
|
data/ext/oil/yscaler.c
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
#include "yscaler.h"
|
2
|
-
#include "resample.h"
|
3
|
-
#include <stdlib.h>
|
4
|
-
#include <stdint.h>
|
5
|
-
|
6
|
-
/**
|
7
|
-
* Initializes a strip of height scanlines.
|
8
|
-
*
|
9
|
-
* Scanlines are allocated with a size of len bytes.
|
10
|
-
*/
|
11
|
-
static void strip_init(struct strip *st, uint32_t height, size_t buflen)
|
12
|
-
{
|
13
|
-
uint32_t i;
|
14
|
-
|
15
|
-
st->height = height;
|
16
|
-
st->rr = 0;
|
17
|
-
st->sl = malloc(height * sizeof(uint8_t *));
|
18
|
-
st->virt = malloc(height * sizeof(uint8_t *));
|
19
|
-
for (i=0; i<height; i++) {
|
20
|
-
st->sl[i] = malloc(buflen);
|
21
|
-
st->virt[i] = st->sl[0];
|
22
|
-
}
|
23
|
-
}
|
24
|
-
|
25
|
-
/**
|
26
|
-
* Frees memory allocated at initialization.
|
27
|
-
*/
|
28
|
-
static void strip_free(struct strip *st)
|
29
|
-
{
|
30
|
-
uint32_t i;
|
31
|
-
|
32
|
-
for (i=0; i<st->height; i++) {
|
33
|
-
free(st->sl[i]);
|
34
|
-
}
|
35
|
-
free(st->sl);
|
36
|
-
free(st->virt);
|
37
|
-
}
|
38
|
-
|
39
|
-
/**
|
40
|
-
* Shifts the virtual scanline pointers downwards by one.
|
41
|
-
*
|
42
|
-
* The bottmomost virtual scanline pointer is left untouched since we may have
|
43
|
-
* reached the end of the source image and we may want to leave it pointing at
|
44
|
-
* the bottom.
|
45
|
-
*
|
46
|
-
* If we have not reached the bottom of the source image this call should be
|
47
|
-
* followed up by strip_bottom_shift() to complete the strip shift.
|
48
|
-
*/
|
49
|
-
static void strip_top_shift(struct strip *st)
|
50
|
-
{
|
51
|
-
uint32_t i;
|
52
|
-
for (i=1; i<st->height; i++) {
|
53
|
-
st->virt[i - 1] = st->virt[i];
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
/**
|
58
|
-
* Points the bottommost virtual scanline to the next allocated scanline,
|
59
|
-
* discarding the topmost scanline.
|
60
|
-
*
|
61
|
-
* The caller is expected to fill the bottom virtual scanline with image data
|
62
|
-
* after this call.
|
63
|
-
*/
|
64
|
-
static void strip_bottom_shift(struct strip *st)
|
65
|
-
{
|
66
|
-
st->rr = (st->rr + 1) % st->height;
|
67
|
-
st->virt[st->height - 1] = st->sl[st->rr];
|
68
|
-
}
|
69
|
-
|
70
|
-
/**
|
71
|
-
* Returns a pointer to the bottommost virtual scanline.
|
72
|
-
*/
|
73
|
-
static void *strip_bottom(struct strip *st)
|
74
|
-
{
|
75
|
-
return st->virt[st->height - 1];
|
76
|
-
}
|
77
|
-
|
78
|
-
static void yscaler_map_pos(struct yscaler *ys)
|
79
|
-
{
|
80
|
-
uint32_t target;
|
81
|
-
target = split_map(ys->in_height, ys->out_height, ys->out_pos, &ys->ty);
|
82
|
-
ys->in_target = target + ys->strip.height / 2 + 1;
|
83
|
-
}
|
84
|
-
|
85
|
-
void yscaler_init(struct yscaler *ys, uint32_t in_height, uint32_t out_height,
|
86
|
-
uint32_t buflen)
|
87
|
-
{
|
88
|
-
uint32_t taps;
|
89
|
-
|
90
|
-
ys->in_height = in_height;
|
91
|
-
ys->out_height = out_height;
|
92
|
-
ys->in_pos = 0;
|
93
|
-
ys->out_pos = 0;
|
94
|
-
|
95
|
-
taps = calc_taps(in_height, out_height);
|
96
|
-
strip_init(&ys->strip, taps, buflen);
|
97
|
-
yscaler_map_pos(ys);
|
98
|
-
}
|
99
|
-
|
100
|
-
void yscaler_free(struct yscaler *ys)
|
101
|
-
{
|
102
|
-
strip_free(&ys->strip);
|
103
|
-
}
|
104
|
-
|
105
|
-
unsigned char *yscaler_next(struct yscaler *ys)
|
106
|
-
{
|
107
|
-
struct strip *st;
|
108
|
-
|
109
|
-
st = &ys->strip;
|
110
|
-
|
111
|
-
/* We need the first scanline for top padding. */
|
112
|
-
if (ys->in_pos == 0) {
|
113
|
-
ys->in_pos++;
|
114
|
-
return strip_bottom(st);
|
115
|
-
}
|
116
|
-
|
117
|
-
while (ys->in_pos < ys->in_target) {
|
118
|
-
ys->in_pos++;
|
119
|
-
strip_top_shift(&ys->strip);
|
120
|
-
if (ys->in_pos <= ys->in_height) {
|
121
|
-
strip_bottom_shift(st);
|
122
|
-
return strip_bottom(st);
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
return 0;
|
127
|
-
}
|
128
|
-
|
129
|
-
void yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t width,
|
130
|
-
uint8_t cmp, uint8_t opts)
|
131
|
-
{
|
132
|
-
struct strip *st;
|
133
|
-
|
134
|
-
st = &ys->strip;
|
135
|
-
strip_scale((void **)st->virt, st->height, width, (void *)out, ys->ty,
|
136
|
-
cmp, opts);
|
137
|
-
ys->out_pos++;
|
138
|
-
yscaler_map_pos(ys);
|
139
|
-
}
|
140
|
-
|
141
|
-
void yscaler_prealloc_scale(uint32_t in_height, uint32_t out_height,
|
142
|
-
uint8_t **in, uint8_t *out, uint32_t pos, uint32_t width, uint8_t cmp,
|
143
|
-
uint8_t opts)
|
144
|
-
{
|
145
|
-
uint32_t i, taps;
|
146
|
-
int32_t smp_i, strip_pos;
|
147
|
-
uint8_t **virt;
|
148
|
-
float ty;
|
149
|
-
|
150
|
-
taps = calc_taps(in_height, out_height);
|
151
|
-
virt = malloc(taps * sizeof(uint8_t *));
|
152
|
-
smp_i = split_map(in_height, out_height, pos, &ty);
|
153
|
-
strip_pos = smp_i + 1 - taps / 2;
|
154
|
-
|
155
|
-
for (i=0; i<taps; i++) {
|
156
|
-
if (strip_pos < 0) {
|
157
|
-
virt[i] = in[0];
|
158
|
-
} else if ((uint32_t)strip_pos > in_height - 1) {
|
159
|
-
virt[i] = in[in_height - 1];
|
160
|
-
} else {
|
161
|
-
virt[i] = in[strip_pos];
|
162
|
-
}
|
163
|
-
strip_pos++;
|
164
|
-
}
|
165
|
-
|
166
|
-
strip_scale((void **)virt, taps, width, (void *)out, ty, cmp, opts);
|
167
|
-
}
|
data/ext/oil/yscaler.h
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#ifndef YSCALER_H
|
2
|
-
#define YSCALER_H
|
3
|
-
|
4
|
-
#include <stdint.h>
|
5
|
-
|
6
|
-
struct strip {
|
7
|
-
uint32_t height;
|
8
|
-
uint8_t **sl;
|
9
|
-
uint8_t **virt;
|
10
|
-
uint32_t rr;
|
11
|
-
};
|
12
|
-
|
13
|
-
struct yscaler {
|
14
|
-
uint32_t in_height;
|
15
|
-
uint32_t out_height;
|
16
|
-
struct strip strip;
|
17
|
-
uint32_t in_pos;
|
18
|
-
uint32_t out_pos;
|
19
|
-
uint32_t in_target;
|
20
|
-
float ty;
|
21
|
-
};
|
22
|
-
|
23
|
-
void yscaler_init(struct yscaler *ys, uint32_t in_height, uint32_t out_height,
|
24
|
-
uint32_t buflen);
|
25
|
-
void yscaler_free(struct yscaler *ys);
|
26
|
-
unsigned char *yscaler_next(struct yscaler *ys);
|
27
|
-
void yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t width,
|
28
|
-
uint8_t cmp, uint8_t opts);
|
29
|
-
void yscaler_prealloc_scale(uint32_t in_height, uint32_t out_height,
|
30
|
-
uint8_t **in, uint8_t *out, uint32_t pos, uint32_t width, uint8_t cmp,
|
31
|
-
uint8_t opts);
|
32
|
-
|
33
|
-
#endif
|