skia 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,284 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skia
4
+ module Native
5
+ typedef :uint32, :sk_color_t
6
+ typedef :uint32, :sk_pmcolor_t
7
+ typedef :pointer, :sk_surface_t
8
+ typedef :pointer, :sk_canvas_t
9
+ typedef :pointer, :sk_paint_t
10
+ typedef :pointer, :sk_path_t
11
+ typedef :pointer, :sk_image_t
12
+ typedef :pointer, :sk_data_t
13
+ typedef :pointer, :sk_shader_t
14
+ typedef :pointer, :sk_typeface_t
15
+ typedef :pointer, :sk_font_t
16
+ typedef :pointer, :sk_mask_filter_t
17
+ typedef :pointer, :sk_color_filter_t
18
+ typedef :pointer, :sk_image_filter_t
19
+ typedef :pointer, :sk_path_effect_t
20
+ typedef :pointer, :sk_pixmap_t
21
+ typedef :pointer, :sk_document_t
22
+ typedef :pointer, :sk_picture_t
23
+ typedef :pointer, :sk_picture_recorder_t
24
+ typedef :pointer, :sk_drawable_t
25
+
26
+ enum :sk_colortype_t, [
27
+ :unknown, 0,
28
+ :alpha_8, 1,
29
+ :rgb_565, 2,
30
+ :argb_4444, 3,
31
+ :rgba_8888, 4,
32
+ :rgb_888x, 5,
33
+ :bgra_8888, 6,
34
+ :rgba_1010102, 7,
35
+ :rgb_101010x, 8,
36
+ :gray_8, 9,
37
+ :rgba_f16, 10,
38
+ :rgba_f32, 11
39
+ ]
40
+
41
+ enum :sk_alphatype_t, [
42
+ :unknown, 0,
43
+ :opaque, 1,
44
+ :premul, 2,
45
+ :unpremul, 3
46
+ ]
47
+
48
+ enum :sk_paint_style_t, [
49
+ :fill, 0,
50
+ :stroke, 1,
51
+ :stroke_and_fill, 2
52
+ ]
53
+
54
+ enum :sk_stroke_cap_t, [
55
+ :butt, 0,
56
+ :round, 1,
57
+ :square, 2
58
+ ]
59
+
60
+ enum :sk_stroke_join_t, [
61
+ :miter, 0,
62
+ :round, 1,
63
+ :bevel, 2
64
+ ]
65
+
66
+ enum :sk_blend_mode_t, [
67
+ :clear, 0,
68
+ :src, 1,
69
+ :dst, 2,
70
+ :src_over, 3,
71
+ :dst_over, 4,
72
+ :src_in, 5,
73
+ :dst_in, 6,
74
+ :src_out, 7,
75
+ :dst_out, 8,
76
+ :src_atop, 9,
77
+ :dst_atop, 10,
78
+ :xor, 11,
79
+ :plus, 12,
80
+ :modulate, 13,
81
+ :screen, 14,
82
+ :overlay, 15,
83
+ :darken, 16,
84
+ :lighten, 17,
85
+ :color_dodge, 18,
86
+ :color_burn, 19,
87
+ :hard_light, 20,
88
+ :soft_light, 21,
89
+ :difference, 22,
90
+ :exclusion, 23,
91
+ :multiply, 24,
92
+ :hue, 25,
93
+ :saturation, 26,
94
+ :color, 27,
95
+ :luminosity, 28
96
+ ]
97
+
98
+ enum :sk_path_filltype_t, [
99
+ :winding, 0,
100
+ :even_odd, 1,
101
+ :inverse_winding, 2,
102
+ :inverse_even_odd, 3
103
+ ]
104
+
105
+ enum :sk_path_direction_t, [
106
+ :cw, 0,
107
+ :ccw, 1
108
+ ]
109
+
110
+ enum :sk_clipop_t, [
111
+ :difference, 0,
112
+ :intersect, 1
113
+ ]
114
+
115
+ enum :sk_encoded_image_format_t, [
116
+ :bmp, 0,
117
+ :gif, 1,
118
+ :ico, 2,
119
+ :jpeg, 3,
120
+ :png, 4,
121
+ :wbmp, 5,
122
+ :webp, 6,
123
+ :pkm, 7,
124
+ :ktx, 8,
125
+ :astc, 9,
126
+ :dng, 10,
127
+ :heif, 11
128
+ ]
129
+
130
+ enum :sk_shader_tilemode_t, [
131
+ :clamp, 0,
132
+ :repeat, 1,
133
+ :mirror, 2,
134
+ :decal, 3
135
+ ]
136
+
137
+ enum :sk_font_style_slant_t, [
138
+ :upright, 0,
139
+ :italic, 1,
140
+ :oblique, 2
141
+ ]
142
+
143
+ enum :sk_text_encoding_t, [
144
+ :utf8, 0,
145
+ :utf16, 1,
146
+ :utf32, 2,
147
+ :glyph_id, 3
148
+ ]
149
+
150
+ class SKPoint < FFI::Struct
151
+ layout :x, :float,
152
+ :y, :float
153
+ end
154
+
155
+ class SKIPoint < FFI::Struct
156
+ layout :x, :int32,
157
+ :y, :int32
158
+ end
159
+
160
+ class SKRect < FFI::Struct
161
+ layout :left, :float,
162
+ :top, :float,
163
+ :right, :float,
164
+ :bottom, :float
165
+ end
166
+
167
+ class SKIRect < FFI::Struct
168
+ layout :left, :int32,
169
+ :top, :int32,
170
+ :right, :int32,
171
+ :bottom, :int32
172
+ end
173
+
174
+ class SKSize < FFI::Struct
175
+ layout :width, :float,
176
+ :height, :float
177
+ end
178
+
179
+ class SKISize < FFI::Struct
180
+ layout :width, :int32,
181
+ :height, :int32
182
+ end
183
+
184
+ class SKMatrix < FFI::Struct
185
+ layout :scaleX, :float,
186
+ :skewX, :float,
187
+ :transX, :float,
188
+ :skewY, :float,
189
+ :scaleY, :float,
190
+ :transY, :float,
191
+ :persp0, :float,
192
+ :persp1, :float,
193
+ :persp2, :float
194
+ end
195
+
196
+ # 4x4 matrix (row major order)
197
+ class SKMatrix44 < FFI::Struct
198
+ layout :m00, :float, :m01, :float, :m02, :float, :m03, :float,
199
+ :m10, :float, :m11, :float, :m12, :float, :m13, :float,
200
+ :m20, :float, :m21, :float, :m22, :float, :m23, :float,
201
+ :m30, :float, :m31, :float, :m32, :float, :m33, :float
202
+ end
203
+
204
+ class SKImageInfo < FFI::Struct
205
+ layout :colorspace, :pointer,
206
+ :width, :int32,
207
+ :height, :int32,
208
+ :colorType, :sk_colortype_t,
209
+ :alphaType, :sk_alphatype_t
210
+ end
211
+
212
+ class SKFontMetrics < FFI::Struct
213
+ layout :flags, :uint32,
214
+ :top, :float,
215
+ :ascent, :float,
216
+ :descent, :float,
217
+ :bottom, :float,
218
+ :leading, :float,
219
+ :avgCharWidth, :float,
220
+ :maxCharWidth, :float,
221
+ :xMin, :float,
222
+ :xMax, :float,
223
+ :xHeight, :float,
224
+ :capHeight, :float,
225
+ :underlineThickness, :float,
226
+ :underlinePosition, :float,
227
+ :strikeoutThickness, :float,
228
+ :strikeoutPosition, :float
229
+ end
230
+
231
+ # PNG Encoder
232
+ enum :sk_pngencoder_filterflags_t, [
233
+ :zero, 0x00,
234
+ :none, 0x08,
235
+ :sub, 0x10,
236
+ :up, 0x20,
237
+ :avg, 0x40,
238
+ :paeth, 0x80,
239
+ :all, 0xF8
240
+ ]
241
+
242
+ class SKPngEncoderOptions < FFI::Struct
243
+ layout :fFilterFlags, :sk_pngencoder_filterflags_t,
244
+ :fZLibLevel, :int,
245
+ :fComments, :pointer,
246
+ :fICCProfile, :pointer,
247
+ :fICCProfileDescription, :pointer
248
+ end
249
+
250
+ # JPEG Encoder
251
+ enum :sk_jpegencoder_downsample_t, [
252
+ :downsample_420, 0,
253
+ :downsample_422, 1,
254
+ :downsample_444, 2
255
+ ]
256
+
257
+ enum :sk_jpegencoder_alphaoption_t, [
258
+ :ignore, 0,
259
+ :blend_on_black, 1
260
+ ]
261
+
262
+ class SKJpegEncoderOptions < FFI::Struct
263
+ layout :fQuality, :int,
264
+ :fDownsample, :sk_jpegencoder_downsample_t,
265
+ :fAlphaOption, :sk_jpegencoder_alphaoption_t,
266
+ :xmpMetadata, :pointer,
267
+ :fICCProfile, :pointer,
268
+ :fICCProfileDescription, :pointer
269
+ end
270
+
271
+ # WebP Encoder
272
+ enum :sk_webpencoder_compression_t, [
273
+ :lossy, 0,
274
+ :lossless, 1
275
+ ]
276
+
277
+ class SKWebpEncoderOptions < FFI::Struct
278
+ layout :fCompression, :sk_webpencoder_compression_t,
279
+ :fQuality, :float,
280
+ :fICCProfile, :pointer,
281
+ :fICCProfileDescription, :pointer
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skia
4
+ module Native
5
+ extend FFI::Library
6
+
7
+ class << self
8
+ def find_library
9
+ lib_name, fallbacks = case RUBY_PLATFORM
10
+ when /darwin/
11
+ ['libSkiaSharp.dylib', ['libskia.dylib']]
12
+ when /linux/
13
+ ['libSkiaSharp.so', ['libskia.so']]
14
+ when /mingw|mswin/
15
+ ['libSkiaSharp.dll', ['skia.dll']]
16
+ else
17
+ raise "Unsupported platform: #{RUBY_PLATFORM}"
18
+ end
19
+
20
+ gem_root = File.expand_path('../..', __dir__)
21
+ search_paths = [
22
+ File.join(gem_root, lib_name),
23
+ File.join(Dir.pwd, lib_name),
24
+ ENV['SKIA_LIBRARY_PATH'],
25
+ lib_name
26
+ ].compact
27
+
28
+ found = search_paths.find { |p| File.exist?(p) }
29
+ return found if found
30
+
31
+ [lib_name] + fallbacks
32
+ end
33
+ end
34
+
35
+ ffi_lib_flags :now, :global
36
+
37
+ begin
38
+ lib_path = find_library
39
+ ffi_lib Array(lib_path).first
40
+ rescue LoadError => e
41
+ warn 'Failed to load Skia library. Please ensure libSkiaSharp is installed.'
42
+ warn 'Download from: https://www.nuget.org/packages/SkiaSharp.NativeAssets.macOS'
43
+ raise e
44
+ end
45
+
46
+ require_relative 'native/types'
47
+ require_relative 'native/functions'
48
+ require_relative 'native/callbacks'
49
+ end
50
+ end
data/lib/skia/paint.rb ADDED
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skia
4
+ class Paint < Base
5
+ def initialize(ptr = nil)
6
+ super(ptr || Native.sk_paint_new, :sk_paint_delete)
7
+ end
8
+
9
+ def antialias?
10
+ Native.sk_paint_is_antialias(@ptr)
11
+ end
12
+
13
+ def antialias=(value)
14
+ Native.sk_paint_set_antialias(@ptr, value)
15
+ end
16
+
17
+ def color
18
+ Color.new(Native.sk_paint_get_color(@ptr))
19
+ end
20
+
21
+ def color=(value)
22
+ color_value = value.is_a?(Color) ? value.to_i : value
23
+ Native.sk_paint_set_color(@ptr, color_value)
24
+ end
25
+
26
+ def style
27
+ Native.sk_paint_get_style(@ptr)
28
+ end
29
+
30
+ def style=(value)
31
+ Native.sk_paint_set_style(@ptr, value)
32
+ end
33
+
34
+ def stroke_width
35
+ Native.sk_paint_get_stroke_width(@ptr)
36
+ end
37
+
38
+ def stroke_width=(value)
39
+ Native.sk_paint_set_stroke_width(@ptr, value.to_f)
40
+ end
41
+
42
+ def stroke_cap
43
+ Native.sk_paint_get_stroke_cap(@ptr)
44
+ end
45
+
46
+ def stroke_cap=(value)
47
+ Native.sk_paint_set_stroke_cap(@ptr, value)
48
+ end
49
+
50
+ def stroke_join
51
+ Native.sk_paint_get_stroke_join(@ptr)
52
+ end
53
+
54
+ def stroke_join=(value)
55
+ Native.sk_paint_set_stroke_join(@ptr, value)
56
+ end
57
+
58
+ def stroke_miter
59
+ Native.sk_paint_get_stroke_miter(@ptr)
60
+ end
61
+
62
+ def stroke_miter=(value)
63
+ Native.sk_paint_set_stroke_miter(@ptr, value.to_f)
64
+ end
65
+
66
+ def blend_mode
67
+ Native.sk_paint_get_blendmode(@ptr)
68
+ end
69
+
70
+ def blend_mode=(value)
71
+ Native.sk_paint_set_blendmode(@ptr, value)
72
+ end
73
+
74
+ def shader
75
+ ptr = Native.sk_paint_get_shader(@ptr)
76
+ return nil if ptr.nil? || ptr.null?
77
+
78
+ Shader.wrap(ptr)
79
+ end
80
+
81
+ def shader=(value)
82
+ Native.sk_paint_set_shader(@ptr, value&.ptr)
83
+ end
84
+
85
+ def clone
86
+ self.class.new(Native.sk_paint_clone(@ptr))
87
+ end
88
+
89
+ def reset
90
+ Native.sk_paint_reset(@ptr)
91
+ self
92
+ end
93
+
94
+ def with(**options)
95
+ cloned = clone
96
+ options.each { |k, v| cloned.send(:"#{k}=", v) }
97
+ cloned
98
+ end
99
+ end
100
+ end
data/lib/skia/path.rb ADDED
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skia
4
+ class Path < Base
5
+ def initialize(ptr = nil)
6
+ super(ptr || Native.sk_path_new, :sk_path_delete)
7
+ end
8
+
9
+ def self.build(&block)
10
+ path = new
11
+ path.instance_eval(&block) if block
12
+ path
13
+ end
14
+
15
+ def move_to(x, y)
16
+ Native.sk_path_move_to(@ptr, x.to_f, y.to_f)
17
+ self
18
+ end
19
+
20
+ def line_to(x, y)
21
+ Native.sk_path_line_to(@ptr, x.to_f, y.to_f)
22
+ self
23
+ end
24
+
25
+ def quad_to(x1, y1, x2, y2)
26
+ Native.sk_path_quad_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f)
27
+ self
28
+ end
29
+
30
+ def conic_to(x1, y1, x2, y2, weight)
31
+ Native.sk_path_conic_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f, weight.to_f)
32
+ self
33
+ end
34
+
35
+ def cubic_to(x1, y1, x2, y2, x3, y3)
36
+ Native.sk_path_cubic_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f, x3.to_f, y3.to_f)
37
+ self
38
+ end
39
+
40
+ def arc_to(rx, ry, x_axis_rotate, x, y)
41
+ Native.sk_path_arc_to(@ptr, rx.to_f, ry.to_f, x_axis_rotate.to_f, x.to_f, y.to_f)
42
+ self
43
+ end
44
+
45
+ def arc_to_with_oval(oval, start_angle, sweep_angle, force_move_to = false)
46
+ rect_struct = oval.to_struct
47
+ Native.sk_path_arc_to_with_oval(@ptr, rect_struct, start_angle.to_f, sweep_angle.to_f, force_move_to)
48
+ self
49
+ end
50
+
51
+ def close
52
+ Native.sk_path_close(@ptr)
53
+ self
54
+ end
55
+
56
+ def add_rect(rect, direction = :cw)
57
+ rect_struct = rect.to_struct
58
+ Native.sk_path_add_rect(@ptr, rect_struct, direction)
59
+ self
60
+ end
61
+
62
+ def add_oval(rect, direction = :cw)
63
+ rect_struct = rect.to_struct
64
+ Native.sk_path_add_oval(@ptr, rect_struct, direction)
65
+ self
66
+ end
67
+
68
+ def add_circle(cx, cy, radius, direction = :cw)
69
+ Native.sk_path_add_circle(@ptr, cx.to_f, cy.to_f, radius.to_f, direction)
70
+ self
71
+ end
72
+
73
+ def add_arc(rect, start_angle, sweep_angle)
74
+ rect_struct = rect.to_struct
75
+ Native.sk_path_add_arc(@ptr, rect_struct, start_angle.to_f, sweep_angle.to_f)
76
+ self
77
+ end
78
+
79
+ def add_path(other, extend_path: false)
80
+ mode = extend_path ? 1 : 0
81
+ Native.sk_path_add_path(@ptr, other.ptr, mode, 0)
82
+ self
83
+ end
84
+
85
+ def add_path_offset(other, dx, dy, extend_path: false)
86
+ mode = extend_path ? 1 : 0
87
+ Native.sk_path_add_path_offset(@ptr, other.ptr, dx.to_f, dy.to_f, mode)
88
+ self
89
+ end
90
+
91
+ def add_path_matrix(other, matrix, extend_path: false)
92
+ mode = extend_path ? 1 : 0
93
+ matrix_struct = matrix.to_struct
94
+ Native.sk_path_add_path_matrix(@ptr, other.ptr, matrix_struct, mode)
95
+ self
96
+ end
97
+
98
+ def fill_type
99
+ Native.sk_path_get_filltype(@ptr)
100
+ end
101
+
102
+ def fill_type=(value)
103
+ Native.sk_path_set_filltype(@ptr, value)
104
+ end
105
+
106
+ def bounds
107
+ rect_struct = Native::SKRect.new
108
+ Native.sk_path_get_bounds(@ptr, rect_struct)
109
+ Rect.from_struct(rect_struct)
110
+ end
111
+
112
+ def empty?
113
+ Native.sk_path_count_verbs(@ptr) == 0
114
+ end
115
+
116
+ def contains?(x, y)
117
+ Native.sk_path_contains(@ptr, x.to_f, y.to_f)
118
+ end
119
+
120
+ def transform(matrix)
121
+ matrix_struct = matrix.to_struct
122
+ Native.sk_path_transform(@ptr, matrix_struct)
123
+ self
124
+ end
125
+
126
+ def clone
127
+ self.class.new(Native.sk_path_clone(@ptr))
128
+ end
129
+
130
+ def reset
131
+ Native.sk_path_reset(@ptr)
132
+ self
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skia
4
+ class Picture < Base
5
+ def initialize(ptr)
6
+ super(ptr, :sk_picture_unref)
7
+ end
8
+
9
+ def self.from_data(data)
10
+ data_obj = data.is_a?(Data) ? data : Data.new(data)
11
+ ptr = Native.sk_picture_deserialize_from_data(data_obj.ptr)
12
+ raise Error, "Failed to deserialize picture" if ptr.nil? || ptr.null?
13
+
14
+ new(ptr)
15
+ end
16
+
17
+ def self.record(bounds, &block)
18
+ recorder = PictureRecorder.new
19
+ recorder.begin_recording(bounds, &block)
20
+ end
21
+
22
+ def unique_id
23
+ Native.sk_picture_get_unique_id(@ptr)
24
+ end
25
+
26
+ def cull_rect
27
+ rect_struct = Native::SKRect.new
28
+ Native.sk_picture_get_cull_rect(@ptr, rect_struct)
29
+ Rect.from_struct(rect_struct)
30
+ end
31
+
32
+ def playback(canvas)
33
+ Native.sk_picture_playback(@ptr, canvas.ptr)
34
+ self
35
+ end
36
+
37
+ def serialize
38
+ data_ptr = Native.sk_picture_serialize_to_data(@ptr)
39
+ raise Error, "Failed to serialize picture" if data_ptr.nil? || data_ptr.null?
40
+
41
+ Data.new(data_ptr)
42
+ end
43
+
44
+ def approximate_op_count(nested: true)
45
+ Native.sk_picture_approximate_op_count(@ptr, nested)
46
+ end
47
+
48
+ def approximate_bytes_used
49
+ Native.sk_picture_approximate_bytes_used(@ptr)
50
+ end
51
+
52
+ def save(path)
53
+ data = serialize
54
+ File.binwrite(path, data.to_s)
55
+ self
56
+ end
57
+
58
+ def self.load(path)
59
+ data = Data.from_file(path)
60
+ from_data(data)
61
+ end
62
+ end
63
+
64
+ class PictureRecorder
65
+ def initialize
66
+ @ptr = Native.sk_picture_recorder_new
67
+ raise Error, "Failed to create picture recorder" if @ptr.nil? || @ptr.null?
68
+
69
+ @recording = false
70
+ end
71
+
72
+ def ptr
73
+ @ptr
74
+ end
75
+
76
+ def begin_recording(bounds)
77
+ bounds_struct = bounds.to_struct
78
+ canvas_ptr = Native.sk_picture_recorder_begin_recording(@ptr, bounds_struct)
79
+ raise Error, "Failed to begin recording" if canvas_ptr.nil? || canvas_ptr.null?
80
+
81
+ @recording = true
82
+ canvas = Canvas.new(canvas_ptr)
83
+
84
+ if block_given?
85
+ yield canvas
86
+ end_recording
87
+ else
88
+ canvas
89
+ end
90
+ end
91
+
92
+ def recording_canvas
93
+ return nil unless @recording
94
+
95
+ canvas_ptr = Native.sk_picture_get_recording_canvas(@ptr)
96
+ return nil if canvas_ptr.nil? || canvas_ptr.null?
97
+
98
+ Canvas.new(canvas_ptr)
99
+ end
100
+
101
+ def end_recording
102
+ return nil unless @recording
103
+
104
+ ptr = Native.sk_picture_recorder_end_recording(@ptr)
105
+ @recording = false
106
+ raise Error, "Failed to end recording" if ptr.nil? || ptr.null?
107
+
108
+ Picture.new(ptr)
109
+ end
110
+
111
+ def recording?
112
+ @recording
113
+ end
114
+
115
+ def delete
116
+ Native.sk_picture_recorder_delete(@ptr) if @ptr
117
+ @ptr = nil
118
+ end
119
+ end
120
+ end