oil 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|