datauris 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8b17d925dd560274e1e3a4f21e5caa118762e74c1d5b1e4e07777c9456b64f0f
4
+ data.tar.gz: 34c7263eea9cd31e1bfede00bb4002d303dc59d7870d3bad620a88a7345d292a
5
+ SHA512:
6
+ metadata.gz: 509299375bebbc22eee68c3c3a704030df51c1d555a57ee5ff83435b1b5d6a0cf9de75c49d1551f277e89db01280bb7f15dc2f2ddd42cfa9bf3ef7279cef0ce4
7
+ data.tar.gz: b0aba84982c23968350395e3aedf91e11bf7f31a20566e1262f715f9638fdcf05b91aa2e575f4189ca0d58318f8702de0d587efbd7262d7a0c466a3b8e1e33e9
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ ### 1.0.0
2
+ ### 0.0.1 / 2023-11-23
3
+
4
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,7 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/datauri.rb
6
+ lib/datauris.rb
7
+ lib/datauris/version.rb
data/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Data URI Helpers
2
+
3
+ datauris - helpers to parse (decode) and build (encode) data uris incl. (strict)base64-encoded/decoded images and more
4
+
5
+ * home :: [github.com/s6ruby/rubidity](https://github.com/s6ruby/rubidity)
6
+ * bugs :: [github.com/s6ruby/rubidity/issues](https://github.com/s6ruby/rubidity/issues)
7
+ * gem :: [rubygems.org/gems/datauris](https://rubygems.org/gems/datauris)
8
+ * rdoc :: [rubydoc.info/gems/datauris](http://rubydoc.info/gems/datauris)
9
+
10
+
11
+
12
+ ## What are Data URIs?!
13
+
14
+ Data URI Syntax via [Wikipedia](https://en.wikipedia.org/wiki/Data_URI_scheme):
15
+
16
+ > The syntax of data URIs is defined in [Request for Comments (RFC) 2397](https://datatracker.ietf.org/doc/html/rfc2397),
17
+ > published in August 1998, and follows the URI scheme syntax. A data URI consists of:
18
+ >
19
+ > data:[<mediatype>][;base64],<data>
20
+ >
21
+ > - The **scheme**, `data`. It is followed by a colon (`:`).
22
+ > - An optional **media type**. The media type part may include one or more parameters,
23
+ > in the format `attribute=value`, separated by semicolons (`;`).
24
+ > A common media type parameter is charset, specifying the character
25
+ > set of the media type, where the value is from the IANA list of character set names.
26
+ > If one is not specified, the media type of the data URI is assumed
27
+ > to be `text/plain;charset=US-ASCII`.
28
+ > - An optional **base64 extension** `base64`, separated from the preceding part by a semicolon.
29
+ > When present, this indicates that the data content of the URI is binary data, encoded in ASCII format using the Base64 scheme for binary-to-text encoding.
30
+ > The base64 extension is distinguished from any media type parameters
31
+ > by virtue of not having a `=value` component and
32
+ > by coming after any media type parameters.
33
+ > - The **data**, separated from the preceding part by a comma (`,`).
34
+ > The data is a sequence of zero or more octets represented as characters.
35
+ > The comma is required in a data URI, even when the data part has zero length.
36
+ > The characters permitted within the data part include ASCII upper
37
+ > and lowercase letters, digits, and many ASCII punctuation and special characters.
38
+ > Note that this may include characters, such as colon, semicolon,
39
+ > and comma which are delimiters in the URI components preceding the data part.
40
+ > Other octets must be percent-encoded. If the data is Base64-encoded,
41
+ > then the data part may contain only valid Base64 characters.
42
+ > Note that Base64-encoded data: URIs use the standard Base64 character set
43
+ > (with `+` and `/` as characters 62 and 63)
44
+ > rather than the so-called "URL-safe Base64" character set.
45
+
46
+
47
+
48
+ ## Usage
49
+
50
+ [Parse](#parse) • [Build](#build)
51
+
52
+ ### Parse
53
+
54
+
55
+ Let's try and parse the Wikipedia Data URI examples:
56
+
57
+ ``` ruby
58
+ uri = "data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh"
59
+ DataUri.valid?( uri )
60
+ #=> true
61
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
62
+ #=> "text/vnd-example+xyz;foo=bar", "<blob>"
63
+
64
+ uri = "data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678"
65
+ DataUri.valid?( uri )
66
+ #=> true
67
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
68
+ #=> "text/plain;charset=UTF-8;page=21", "the data:1234,5678"
69
+
70
+
71
+ uri = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/"
72
+ DataUri.valid?( uri )
73
+ #=> true
74
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
75
+ #=> "image/jpeg", "<blob>"
76
+ ```
77
+
78
+
79
+
80
+ Let's try the DataUri helpers on inscriptions (that encode the "on-chain" data
81
+ in Data URIs). A valid inscribe must use a valid data uri in the calldata.
82
+
83
+ The "useless" (null) minimum - no media-type, and zero-length data - is:
84
+
85
+ ``` ruby
86
+ uri = "data:,"
87
+
88
+ DataUri.valid?( uri )
89
+ #=> true
90
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
91
+ #=> "", ""
92
+ ```
93
+
94
+ Let's try the (genesis) inscribe no. 0:
95
+
96
+ ``` ruby
97
+ uri = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHV..."
98
+
99
+ DataUri.valid?( uri )
100
+ #=> true
101
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
102
+ #=> "image/jpeg", "<blob>"
103
+
104
+ ## let's save the jpeg image (blob)
105
+ write_blob( "0.jpeg", data )
106
+ ```
107
+
108
+ and voila!
109
+
110
+ ![](i/0.jpeg)
111
+
112
+
113
+ Let's try the inscribe no. 15:
114
+
115
+ ``` ruby
116
+ uri = "data:image/png;base64,/9j/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAAB..."
117
+
118
+ DataUri.valid?( uri )
119
+ #=> true
120
+ mediatype, data = DataUri.parse( uri ) ## returns 1) mediatype (+parameters), 2) data
121
+ #=> "image/png", "<blob>"
122
+
123
+ ## let's save the png image (blob)
124
+ write_blob( "15.png", data )
125
+ ```
126
+
127
+ and voila!
128
+
129
+ ![](i/15.png)
130
+
131
+
132
+
133
+
134
+ ### Build
135
+
136
+ Let's build Data URIs.
137
+
138
+ ```ruby
139
+ uri = DataUri.build( "" )
140
+ #=> "data:,"
141
+
142
+ uri = DataUri.build( "the data:1234,5678", "text/plain" )
143
+ #=> "data:text/plain,the%20data:1234,5678"
144
+
145
+ # let's try images
146
+ data = read_blob( "0.jpeg" )
147
+ uri = DataUri.build( data, "image/jpeg" )
148
+ #=> "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHV..."
149
+
150
+ data = read_blob( "15.png" )
151
+ uri = DataUri.build( data, "image/png" )
152
+ #=> "data:image/png;base64,/9j/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAAB..."
153
+ ```
154
+
155
+
156
+
157
+ That's it for now.
158
+
159
+
160
+
161
+
162
+ ## Bonus - More Blockchain (Crypto) Tools, Libraries & Scripts In Ruby
163
+
164
+ See [**/blockchain**](https://github.com/rubycocos/blockchain)
165
+ at the ruby code commons (rubycocos) org.
166
+
167
+
168
+ ## Questions? Comments?
169
+
170
+ Join us in the [Rubidity (community) discord (chat server)](https://discord.gg/3JRnDUap6y). Yes you can.
171
+ Your questions and commentary welcome.
172
+
173
+ Or post them over at the [Help & Support](https://github.com/geraldb/help) page. Thanks.
174
+
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'hoe'
2
+ require './lib/datauris/version.rb'
3
+
4
+
5
+ Hoe.spec 'datauris' do
6
+ self.version = DataUri::VERSION
7
+
8
+ self.summary = "datauris gem - DataUri helpers to parse (decode) and build (encode) data uris incl. (strict) base64-encoded/decoded images and more"
9
+ self.description = summary
10
+
11
+ self.urls = { home: 'https://github.com/s6ruby/rubidity' }
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'gerald.bauer@gmail.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.extra_deps = [
21
+ ]
22
+
23
+ self.licenses = ['Public Domain']
24
+
25
+ self.spec_extras = {
26
+ required_ruby_version: '>= 2.3'
27
+ }
28
+ end
data/lib/datauri.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ ## let's you use require 'datauri' singular too
3
+ require_relative 'datauri'
4
+
5
+
@@ -0,0 +1,19 @@
1
+
2
+ module DataUri
3
+ MAJOR = 1 ## todo: namespace inside version or something - why? why not??
4
+ MINOR = 0
5
+ PATCH = 0
6
+ VERSION = [MAJOR,MINOR,PATCH].join('.')
7
+
8
+ def self.version
9
+ VERSION
10
+ end
11
+
12
+ def self.banner
13
+ "datauris/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
14
+ end
15
+
16
+ def self.root
17
+ File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
18
+ end
19
+ end
data/lib/datauris.rb ADDED
@@ -0,0 +1,211 @@
1
+
2
+ require 'base64' ## pull in Base64.strict_encode64/decode64 (standard) module
3
+ require 'uri' ## pull in URI.decode_uri_component
4
+
5
+
6
+ ## our own code
7
+ require_relative 'datauris/version' # let version go first
8
+
9
+
10
+ module DataUri
11
+ REGEX_V0 = %r{
12
+ \Adata:
13
+ (?<mediatype>
14
+ (?<type> .+? / .+? )?
15
+ (?<parameters> (?: ; .+? = .+? )* )
16
+ )?
17
+ (?<base64extension>;base64)?
18
+ ,
19
+ (?<data>.*)\z
20
+ }x
21
+
22
+ ## allow type only - why? why not?
23
+ ## split subtype into [tree prefix] and subtype
24
+ ## check if type can include dash (-) - why? why not?
25
+ ##
26
+ ## note: \w => A word character
27
+ ## is a character a-z, A-Z, 0-9, including _ (underscore).
28
+ ##
29
+ ## official grammar:
30
+ ## mime-type = type "/" [tree "."] subtype ["+" suffix]* [";" parameter];
31
+ ##
32
+ ## Types
33
+ ## The "type" part defines the broad use of the media type.
34
+ ## As of November 1996, the registered types were:
35
+ ## application, audio, image, message, multipart, text and video.
36
+ # By December 2020, the registered types included the foregoing,
37
+ ## plus font, example, and model.
38
+ ##
39
+ ## An unofficial top-level type in common use is chemical
40
+
41
+ ## examples with numbers:
42
+ # application/vnd.software602.filler.form+xml
43
+ # application/x-shockwave-flash2-preview
44
+ # application/vnd.isac.fcs; version="1.0-3.1"
45
+
46
+ ## make parameters key/value more strict - why? why not?
47
+ ## e.g. MIME_PARAM_RE = /^;([-\w.+]+)=([^;,]+)/.freeze
48
+ ##
49
+ ## allow +(plus) or .(dot) in param key - possible?? why? why not?
50
+
51
+ REGEX = %r{
52
+ \A
53
+ data:
54
+ (?<mediatype>
55
+ (?:
56
+ (?<type> [\w-]+? )
57
+ /
58
+ (?<subtype> [\w.+-]+? )
59
+ )?
60
+ (?<parameters> (?: ;
61
+ [\w.+-]+?
62
+ =
63
+ .+?
64
+ )*
65
+ )
66
+ )?
67
+ (?<base64extension>;base64)?
68
+ ,
69
+ (?<data>.*)
70
+ \z
71
+ }x
72
+
73
+
74
+ def self._parse( str ) REGEX.match( str ); end
75
+
76
+ def self.parse( str )
77
+ m = _parse( str )
78
+
79
+ if m
80
+ ## 1) return mediatype (mimetype PLUS optional parameters)
81
+ ## 2) return data (base64 decoded or not)
82
+
83
+ mediatype = m[:mediatype]
84
+ data = if m[:base64extension] ## assume base64 encoded
85
+ Base64.strict_decode64(m[:data])
86
+ else
87
+ ## e.g. %20 => space(20)
88
+ ## etc.
89
+ ## todo/double check - use a different URI decoder - why? why not?
90
+ URI.decode_uri_component(m[:data])
91
+ end
92
+ [mediatype, data]
93
+ else
94
+ raise ArgumentError, "invalid datauri - cannot match regex; sorry"
95
+ end
96
+ end
97
+
98
+
99
+ def self.valid?( str )
100
+ m = _parse( str )
101
+ if m
102
+ if m[:base64extension] ## assume base64
103
+ begin
104
+ Base64.strict_decode64(m[:data])
105
+ true
106
+ rescue ArgumentError
107
+ false
108
+ end
109
+ else
110
+ true
111
+ end
112
+ else
113
+ false
114
+ end
115
+ end
116
+
117
+
118
+ ###
119
+ ## fix-fix-fix - use our own encode_uri instead of encode_uri_component
120
+ ## why? keep more chars unescaped
121
+ ## e.g. ??
122
+ ##
123
+ ## check about space ( ) - must be encoded - why? why not??
124
+ ## comma (,)
125
+ ## more from json - [] or {} or ""
126
+ ##
127
+ ## see <https://en.wikipedia.org/wiki/Percent-encoding>
128
+
129
+
130
+ ## RFC 3986 section 2.3 Unreserved Characters (January 2005)
131
+ ## A-Z => A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
132
+ ## a-z => a b c d e f g h i j k l m n o p q r s t u v w x y z
133
+ ## 0-9 => 0 1 2 3 4 5 6 7 8 9
134
+ ## - _ . ~
135
+ ## Other characters in a URI must be percent-encoded.
136
+
137
+ ## RFC 3986 section 2.2 Reserved Characters (January 2005)
138
+ ## ! # $ & ' ( ) * + , / : ; = ? @ [ ]
139
+ ##
140
+ ## what's missing in reserved?
141
+ ## space(20) and
142
+ ## double quoutes (") and
143
+ ## curly bracket ({}), and ??
144
+ ##
145
+ ## note: Reserved characters that have no reserved purpose in a particular context
146
+ ## may also be percent-encoded but
147
+ ## are not semantically different from those that are not.
148
+
149
+
150
+ ## add more reserved chars here - to keep verbatim (as literal) and NOT percent-encoded
151
+ ## why? why not?
152
+
153
+
154
+ NOT_SAFECHARS_RX = /([^a-zA-Z0-9\-_.~]+)/
155
+
156
+ def self.encode_uri( str )
157
+ encoding = str.encoding
158
+ str.b.gsub( NOT_SAFECHARS_RX ) do |m|
159
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
160
+ end.force_encoding(encoding)
161
+ end
162
+
163
+
164
+ ## base64 - force base64 encoding (instead of "automagic")
165
+ def self.build( data, type=nil, base64: nil )
166
+ uri = "data:"
167
+ uri += type if type ## note: allow optional / no type
168
+
169
+ ## puts " type: #{type.inspect}, base64: #{base64.inspect}"
170
+
171
+ ## add more (binary) media types here - why? why not?
172
+ ## note svg is text AND an image => image/svg+xml
173
+ if base64.nil?
174
+ base64 = if type
175
+ if type.start_with?( 'image/svg+xml' )
176
+ false
177
+ elsif type.start_with?( 'image/') ||
178
+ type.start_with?( 'application/octet-stream' )
179
+ true
180
+ else
181
+ false
182
+ end
183
+ else # no type (assume text)
184
+ false
185
+ end
186
+ end
187
+
188
+ if base64
189
+ uri += ";base64," + Base64.strict_encode64( data )
190
+ else
191
+ ## use encode_uri_component by default - why? why not?
192
+ ## space becomes %20
193
+ ## : becomes %3A
194
+ ## , becomes %2C and so on
195
+ uri += "," + encode_uri( data )
196
+ end
197
+ end
198
+
199
+
200
+
201
+ ## add alias convenience names - why? why not?
202
+ class << self
203
+ alias_method :is_valid?, :valid?
204
+ alias_method :decode, :parse
205
+ alias_method :encode, :build
206
+ end
207
+ end # module DataUri
208
+
209
+
210
+
211
+ puts DataUri.banner # say hello
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: datauris
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-11-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7'
33
+ - !ruby/object:Gem::Dependency
34
+ name: hoe
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4.0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '4.0'
47
+ description: datauris gem - DataUri helpers to parse (decode) and build (encode)
48
+ data uris incl. (strict) base64-encoded/decoded images and more
49
+ email: gerald.bauer@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - CHANGELOG.md
54
+ - Manifest.txt
55
+ - README.md
56
+ files:
57
+ - CHANGELOG.md
58
+ - Manifest.txt
59
+ - README.md
60
+ - Rakefile
61
+ - lib/datauri.rb
62
+ - lib/datauris.rb
63
+ - lib/datauris/version.rb
64
+ homepage: https://github.com/s6ruby/rubidity
65
+ licenses:
66
+ - Public Domain
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options:
70
+ - "--main"
71
+ - README.md
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '2.3'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.4.10
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: datauris gem - DataUri helpers to parse (decode) and build (encode) data
89
+ uris incl. (strict) base64-encoded/decoded images and more
90
+ test_files: []