pikl 0.1.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.
@@ -0,0 +1,12 @@
1
+ #ifndef _LIB_PIKL_RESIZE_
2
+ #define _LIB_PIKL_RESIZE_
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <math.h>
8
+
9
+ #include "pikl.h"
10
+ #include "pikl_private.h"
11
+
12
+ #endif
@@ -0,0 +1,70 @@
1
+ #include "pikl_rotate.h"
2
+
3
+ //=================================================================================
4
+ // pkl_rotate
5
+ //=================================================================================
6
+ PKLExport int pkl_rotate(PKLImage pkl, PKL_ANGLE angle)
7
+ {
8
+ unsigned char *wrk;
9
+ int rsin, rcos;
10
+ int width, height;
11
+ int sx, sy, ex, ey;
12
+ int i, j, x, y;
13
+
14
+ switch(angle){
15
+ case PKL_ANGLE_000:
16
+ return(0);
17
+ case PKL_ANGLE_090:
18
+ rcos = 0;
19
+ rsin = -1;
20
+ width = pkl->height;
21
+ height = pkl->width;
22
+ sx = -(pkl->height-1);
23
+ sy = 0;
24
+ ex = 0;
25
+ ey = pkl->width-1;
26
+ break;
27
+ case PKL_ANGLE_180:
28
+ rcos = -1;
29
+ rsin = 0;
30
+ width = pkl->width;
31
+ height = pkl->height;
32
+ sx = -(pkl->width-1);
33
+ sy = -(pkl->height-1);
34
+ ex = 0;
35
+ ey = 0;
36
+ break;
37
+ case PKL_ANGLE_270:
38
+ rcos = 0;
39
+ rsin = 1;
40
+ width = pkl->height;
41
+ height = pkl->width;
42
+ sx = 0;
43
+ sy = -(pkl->width-1);
44
+ ex = pkl->height-1;
45
+ ey = 0;
46
+ break;
47
+ default:
48
+ return(1);
49
+ }
50
+
51
+ wrk = malloc(width * height * pkl->channel);
52
+ if(!wrk) return(1);
53
+
54
+ for(i=sy; i<=ey; i++){
55
+ for(j=sx; j<=ex; j++){
56
+ x = rcos * j - rsin * i;
57
+ y = rsin * j + rcos * i;
58
+ memcpy(&wrk[((i-sy)*width+j-sx)*pkl->channel], &pkl->image[(y*pkl->width+x)*pkl->channel], pkl->channel);
59
+ }
60
+ }
61
+
62
+ free(pkl->image);
63
+ pkl->image = wrk;
64
+ pkl->width = width;
65
+ pkl->height = height;
66
+
67
+ return(0);
68
+ }
69
+
70
+
@@ -0,0 +1,12 @@
1
+ #ifndef _LIB_PIKL_ROTATE_
2
+ #define _LIB_PIKL_ROTATE_
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <math.h>
8
+
9
+ #include "pikl.h"
10
+ #include "pikl_private.h"
11
+
12
+ #endif
@@ -0,0 +1,28 @@
1
+ #include "pikl_trim.h"
2
+
3
+ //=================================================================================
4
+ // pkl_trim
5
+ //=================================================================================
6
+ PKLExport int pkl_trim(PKLImage pkl, int sx, int sy, int width, int height)
7
+ {
8
+ unsigned char *wrk;
9
+ int p, y;
10
+
11
+ if( sx < 0 || sy < 0 || width <= 0 || height <= 0 ) return(1);
12
+ if( sx+width > pkl->width ) return(1);
13
+ if( sy+height > pkl->height ) return(1);
14
+
15
+ wrk = malloc(height * width * pkl->channel);
16
+ if(!wrk) return(1);
17
+
18
+ for(p=0,y=sy; y<sy+height; p++,y++){
19
+ memcpy(&wrk[p*width*pkl->channel], &pkl->image[(y*pkl->width+sx)*pkl->channel], width*pkl->channel);
20
+ }
21
+
22
+ free(pkl->image);
23
+ pkl->image = wrk;
24
+ pkl->height = height;
25
+ pkl->width = width;
26
+
27
+ return(0);
28
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef _LIB_PIKL_TRIM_
2
+ #define _LIB_PIKL_TRIM_
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ #include "pikl.h"
9
+ #include "pikl_private.h"
10
+
11
+ #endif
data/lib/pikl.rb ADDED
@@ -0,0 +1,14 @@
1
+ #--
2
+ # = Pikl - a simple image library.
3
+ # Author:: Ryota Maruko and Keiko Soejima
4
+ # Copyright:: (c) 2008 Ryota Maruko and Keiko Soejima
5
+ # License:: MIT License
6
+ #++
7
+ $:.unshift(File.dirname(__FILE__)) unless
8
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
9
+ module Pikl
10
+ require "pikl/const"
11
+ require "pikl/ext"
12
+ require "pikl/errors"
13
+ require "pikl/image"
14
+ end
data/lib/pikl/const.rb ADDED
@@ -0,0 +1,49 @@
1
+ module Pikl
2
+
3
+ JPEG = 1
4
+ JPG = JPEG
5
+ PNG = 2
6
+ BITMAP = 3
7
+ BMP = BITMAP
8
+
9
+ ANGLE000 = 0
10
+ ANGLE090 = 1
11
+ ANGLE180 = 2
12
+ ANGLE270 = 3
13
+
14
+ SAMPLE_NN = 1 #nearest neighbor
15
+ SAMPLE_BC = 2 #bicubic(4points)
16
+ SAMPLE_BC2 = 3 #bicubic(16points)
17
+ SAMPLE_PA = 4 #pixcel average(reduce only)
18
+ SAMPLE_LZ = 5 #lanczos
19
+
20
+ SAMPLES = {
21
+ :nearest_neighbor => SAMPLE_NN,
22
+ :bicubic => SAMPLE_BC,
23
+ :bicubic2 => SAMPLE_BC2,
24
+ :pixcel_averate => SAMPLE_PA,
25
+ :lanczoz => SAMPLE_LZ,
26
+ }
27
+
28
+ ROTATE_ANGLE = {
29
+ 0 => ANGLE000,
30
+ 90 => ANGLE090,
31
+ 180 => ANGLE180,
32
+ 270 => ANGLE270,
33
+ 360 => ANGLE000,
34
+ }
35
+
36
+
37
+ EXTENSIONS_FORMATS = {
38
+ "jpeg" => JPEG,
39
+ "jpg" => JPEG,
40
+ "png" => PNG,
41
+ "bmp" => BITMAP,
42
+ }
43
+
44
+ EXTENSIONS = EXTENSIONS_FORMATS.keys
45
+ FORMATS = EXTENSIONS_FORMATS.values.uniq
46
+
47
+ PIX_LIMIT = 6000
48
+
49
+ end
@@ -0,0 +1,7 @@
1
+ module Pikl
2
+
3
+ class ParameterException < Exception; end
4
+
5
+ class ImageProcessException < Exception; end
6
+
7
+ end
data/lib/pikl/ext.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Pikl
2
+ require "dl/import"
3
+ require "dl/struct"
4
+ require "rbconfig"
5
+
6
+ module Ext
7
+ extend DL::Importable
8
+ dlload "#{File.dirname(__FILE__)}/pikl.#{RbConfig::CONFIG['DLEXT']}"
9
+
10
+ typealias("KKImage", "void")
11
+ typealias("PKL_FORMAT", "int")
12
+ typealias("PKL_ANGLE", "int")
13
+ typealias("PKL_SAMPLE", "int")
14
+
15
+ extern "PKLImage *pkl_open(char*)"
16
+ extern "void pkl_close(PKLImage*)"
17
+ extern "int pkl_save(PKLImage*, const char *, PKL_FORMAT)"
18
+ extern "int pkl_compress(PKLImage*, int)"
19
+ extern "PKL_FORMAT pkl_format(PKLImage *)"
20
+ extern "int pkl_width(PKLImage *)"
21
+ extern "int pkl_height(PKLImage *)"
22
+ extern "int pkl_trim(PKLImage *, int, int, int, int)"
23
+ extern "int pkl_rotate(PKLImage *, PKL_ANGLE)"
24
+ extern "int pkl_resize(PKLImage*, int, int, PKL_SAMPLE)"
25
+ extern "int pkl_unsharp(PKLImage *, int, double)"
26
+ extern "int pkl_contrast(PKLImage *, int)"
27
+ extern "int pkl_level(PKLImage *, double, double, double)"
28
+ extern "int pkl_brightness(PKLImage*, int)"
29
+ extern "int pkl_hls(PKLImage*, double, double, double)"
30
+ extern "int pkl_gamma(PKLImage*, double)"
31
+ end
32
+ end
data/lib/pikl/image.rb ADDED
@@ -0,0 +1,219 @@
1
+ module Pikl
2
+
3
+ class Image
4
+
5
+ def self.open(inpath, &block)
6
+ image = Pikl::Image.new(inpath)
7
+ image.instance_variable_set(:@block,block)
8
+
9
+ return image unless block_given?
10
+
11
+ begin
12
+ block.call(image)
13
+ ensure
14
+ image.close if image
15
+ end
16
+
17
+ end
18
+
19
+ def initialize( inpath )
20
+ @pkl_image = Ext.pkl_open(File.expand_path(inpath))
21
+ end
22
+
23
+ def save(outpath, format = nil, compress = nil)
24
+ raise Pikl::ImageProcessException.new("image already closed.") unless @pkl_image
25
+ format ||= @format ||= split_extensions(outpath)
26
+ validate_format(format)
27
+ if compress
28
+ validate_compress(compress)
29
+ Ext.pkl_compress(@pkl_image, compress.to_i)
30
+ end
31
+ Ext.pkl_save(@pkl_image, File.expand_path(outpath), EXTENSIONS_FORMATS[format.to_s] || format.to_i)
32
+ self.close unless(@block)
33
+ end
34
+
35
+ def close()
36
+ Ext.pkl_close(@pkl_image) if @pkl_image
37
+ @pkl_image = nil
38
+ end
39
+
40
+ def width
41
+ Ext.pkl_width(@pkl_image) if(@pkl_image)
42
+ end
43
+
44
+ def height
45
+ Ext.pkl_height(@pkl_image) if(@pkl_image)
46
+ end
47
+
48
+ def format
49
+ Ext.pkl_format(@pkl_image) if(@pkl_image)
50
+ end
51
+
52
+ def trim(x, y, dist_x, dist_y)
53
+ validate_trim(x, y, dist_x, dist_y)
54
+ dist_x = trim_dist(x, self.width, dist_x)
55
+ dist_y = trim_dist(y, self.height, dist_y)
56
+
57
+ Ext.pkl_trim(@pkl_image, x, y, dist_x, dist_y)
58
+ end
59
+
60
+ def trim_dist(start, dist_from, dist_to)
61
+ if dist_to == :auto || dist_to > (dist_from - start)
62
+ dist_to = dist_from - start
63
+ elsif dist_to < 0
64
+ dist_to += (dist_from - start)
65
+ else
66
+ dist_to
67
+ end
68
+ end
69
+
70
+ def rotate(angle)
71
+ validate_rotate(angle)
72
+ Ext.pkl_rotate(@pkl_image, ROTATE_ANGLE[angle.to_i])
73
+ end
74
+
75
+ def resize(width, height, sample = :nearest_neighbor)
76
+ validate_auto(width,height)
77
+
78
+ case sample.class.name
79
+ when 'Symbol', 'String'
80
+ sample = SAMPLES[sample.to_sym]
81
+ end
82
+
83
+ width = self.width * height / self.height if(width == :auto)
84
+ height = self.height * width / self.width if(height == :auto)
85
+
86
+ validate_resize(width, height)
87
+
88
+ Ext.pkl_resize(@pkl_image, width, height, sample)
89
+ end
90
+
91
+ # threshold=0-255
92
+ # threshold=0の時は変化しません
93
+ # threshold=255の時は全ての色にアンシャープ処理が働きます
94
+ # edge=-10 .. 10
95
+ # edge=0の時は変化しません
96
+ # edge>0の時は値が大きいほど先鋭化されます
97
+ # edge<0の時は値が小さいほどぼやけます
98
+ #
99
+ # 想定結果が得られる範囲は-10 .. 10程度です。
100
+ # これを超える場合は、品質の保証はありません
101
+ # ※画質によりこの通りではありません。-10..10の範囲より小さくなる可能性があります。
102
+ def unshapmask(threshold, edge)
103
+ Ext.pkl_unsharp(@pkl_image, threshold.to_i, edge.to_f)
104
+ end
105
+
106
+ # コントラスト調整
107
+ # コントラストを強くするということは、白い部分をより白く、
108
+ # 黒い部分をより黒くするような変換を意味します。
109
+ # 逆にコントラストを弱くした場合、白い部分と黒い部分の差が無くなり、灰色っぽい画像になります。
110
+ # <rate>
111
+ # 範囲:-127 .. 127
112
+ # rate=0の時は変化しません
113
+ # * rateが0以上の時は周波数によるコントラスト強調がおこなわれます
114
+ # * rateが0未満の時は直線的に平坦化されます
115
+ def contrast(rate)
116
+ Ext.pkl_contrast(@pkl_image, rate.to_f)
117
+ end
118
+
119
+ # レベル補正
120
+ # ヒストグラムの平坦化をおこないます。各色の分布に偏りがある画像に有効な場合があります。
121
+ # coeff = 平坦化時の係数です。1が標準です。1より小さい場合は暗く、1より大きい場合は明るくなります(0.0..2.0)
122
+ # low = 全ピクセル数に対して、切り捨てる暗い色の総数の割合(0-100%)
123
+ # high = 全ピクセル数に対して、切り捨てる明るい色の総数の割合(0-100%)
124
+ def level(low, high, coeff)
125
+ Ext.pkl_level(@pkl_image, low.to_f, high.to_f, coeff.to_f)
126
+ end
127
+
128
+ # 明るさ調整
129
+ # この明るさ調整は各色からcolor値を加算する単純な処理です。
130
+ # colorに255を指定すれば、ただの白い画像になります
131
+ # colorに-255を指定すると、ただの黒い画像になります。
132
+ def brightness(color)
133
+ Ext.pkl_brightness(@pkl_image, color.to_i)
134
+ end
135
+
136
+ # 輝度(明るさ)・彩度(鮮やかさ)・色相(色合い)調整
137
+ # * 具体的にどういうことかを理解したい場合は、mspaintの「色の編集」を見ると良いでしょう。
138
+ # ym(輝度) -1 .. 1(0.1で10%up).0では変化なし
139
+ # sm(彩度) -1 .. 1(0.1で10%up).0では変化なし
140
+ # hd(色相) 360.0度回転(R=113.2/Ye=173.0/G=225.0/Cy=293.2/B=353.0/Mg=45.0).360の倍数では変化なし
141
+ def hls(ym, sm ,hd)
142
+ Ext.pkl_hls(@pkl_image, ym.to_f, sm.to_f, hd.to_f)
143
+ end
144
+
145
+ # ガンマ補正
146
+ # ガンマ補正をします。
147
+ # gmは補正係数です。
148
+ # gm=0以上の値が指定できます。
149
+ # 1.0より小さい時は暗く、1.0より大きい時は明るく調整されます。
150
+ # 1.0を指定した時は調整されません。
151
+ def gamma(gm)
152
+ Ext.pkl_gamma(@pkl_image, gm.to_f)
153
+ end
154
+
155
+ # regular expressions to try for identifying extensions
156
+ def split_extensions(path)
157
+ filename = path.split('/').last
158
+ (filename =~ %r|.+\.([a-z,A-Z]+)$|) ? $1 : nil
159
+ end
160
+
161
+ def validate_auto(width, height)
162
+ error("invalid :autoto in the both of width and height.") if(width == :auto && height == :auto)
163
+ end
164
+
165
+ # validate identifying extensions
166
+ def validate_format(ext)
167
+ error(ext) unless (ext || EXTENSIONS.include?(ext.to_s.downcase) || FORMATS.include?(ext.to_i))
168
+ end
169
+
170
+ def validate_trim(x, y, dist_x, dist_y)
171
+ validate_numeric(x, y)
172
+
173
+ validate_pix(dist_x, true)
174
+ validate_pix(dist_y, true)
175
+
176
+ error("left is outside the range. #{x}") if x > self.width.to_i
177
+ error("top is outside the range. #{y}") if y > self.height.to_i
178
+ end
179
+
180
+ def validate_rotate(angle)
181
+ validate_numeric(angle)
182
+ error("invalid angle. # => #{angle}") unless ROTATE_ANGLE.has_key?(angle)
183
+ end
184
+
185
+ def validate_resize(width, height)
186
+ validate_auto(width, height)
187
+ validate_pix(width)
188
+ validate_pix(height)
189
+ end
190
+
191
+ def validate_pix(value, allow_minus = false)
192
+ return if value == :auto
193
+ validate_numeric(value)
194
+ error("value is outside the range. #{value}") if value == 0
195
+ error("value is outside the range. #{value}") if !allow_minus && value < 0
196
+ error("value is outside the range. #{value}") if value > PIX_LIMIT
197
+ end
198
+
199
+ def validate_numeric(*args)
200
+ args = [args] unless args.is_a?(Array)
201
+ args.each do |v|
202
+ error("invalid parameter. # => #{v}") unless /^[-\d]+$/ =~ v.to_s
203
+ end
204
+ end
205
+
206
+ def validate_compress(v)
207
+ error("invalid compress parameter. # => #{v}") unless /^\d+$/ =~ v.to_s
208
+ error("invalid compress parameter. # => #{v}") unless v.to_i >= 0 && v.to_i <= 10
209
+ end
210
+
211
+ def error(message)
212
+ #self.close
213
+ raise Pikl::ParameterException.new(message)
214
+ end
215
+ end
216
+ end
217
+
218
+
219
+