jekyll-pig 0.0.3 → 0.0.5

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jekyll-pig.rb +294 -295
  3. metadata +5 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd6c955e443343e3d518c3b174cb1f7dc665f810c8420f5dec7c8dfccf345f2d
4
- data.tar.gz: 3d3c91f6ca57ecbd9acee9dd68554f7eb8ce04500008c9fb09c827f9f2cd88c4
3
+ metadata.gz: bc22ff1902fb72ae001ac574bb84687afabcb815c54169d470b96dad48315ad7
4
+ data.tar.gz: d91b9e706a8a81841ec856a64870c6a5831030327e444d390bb27e92217c169d
5
5
  SHA512:
6
- metadata.gz: d2ab7eb1ef1d385abb3f274659435f844e0db139822da055e429e449fea15b64145c5f3082be02fb13a9b1bad2c27ef7665a965173f0e839ed2c6e7fed40bd18
7
- data.tar.gz: 5b3cb6c3c98675efe89e9f31a65b59765f66768ac4ffa51318b90ad93d5d179f45710ddf890063da9c90d798164f80274593ec6dc686fcf1a742e1742baa5de0
6
+ metadata.gz: e63a1cee3e5aa25416246030f113ac8271bb3e5872038ea7317c1873029cfe4d3c66b96d753d4dee6c7b22914399a3a876a10520b619fa70bb15e1f9926719e5
7
+ data.tar.gz: 38ee6decfa0bff283ee334362ea1bf2552874abeec76339b963b819b12e9bc873238a48e5a853c6fae9b6159ed1d8f07af29e1743322f6dc578197cdc8aa39d7
data/lib/jekyll-pig.rb CHANGED
@@ -1,295 +1,294 @@
1
-
2
- require 'fileutils'
3
- require 'json'
4
- require 'mini_magick'
5
-
6
- module JekyllPig
7
-
8
- class SourceGallery
9
- def initialize(path, name)
10
- @path = path
11
- @name = name
12
- end
13
- def to_s
14
- "gallery #{@name} at #{@path}"
15
- end
16
- def path
17
- @path
18
- end
19
- def name
20
- @name
21
- end
22
- end
23
-
24
- class JekyllPig < Jekyll::Generator
25
-
26
- @@image_cache = {}
27
-
28
- @@pig_min_js = '!function(t){"use strict";var i,e,s=(e=!(i=[]),{add:function(t){i.length||window.addEventListener("resize",n),i.push(t)},disable:function(){window.removeEventListener("resize",n)},reEnable:function(){window.addEventListener("resize",n)}});function n(){e||(e=!0,window.requestAnimationFrame?window.requestAnimationFrame(o):setTimeout(o,66))}function o(){i.forEach(function(t){t()}),e=!1}function a(t,i){return this.inRAF=!1,this.isTransitioning=!1,this.minAspectRatioRequiresTransition=!1,this.minAspectRatio=null,this.latestYOffset=0,this.lastWindowWidth=window.innerWidth,this.scrollDirection="down",this.visibleImages=[],this.settings={containerId:"pig",scroller:window,classPrefix:"pig",figureTagName:"figure",spaceBetweenImages:8,transitionSpeed:500,primaryImageBufferHeight:1e3,secondaryImageBufferHeight:300,thumbnailSize:20,urlForSize:function(t,i){return"/img/"+i+"/"+t},onClickHandler:function(t){},getMinAspectRatio:function(t){return t<=640?2:t<=1280?4:t<=1920?5:6},getImageSize:function(t){return t<=640?100:t<=1920?250:500}},function(t,i){for(var e in i)i.hasOwnProperty(e)&&(t[e]=i[e])}(this.settings,i||{}),this.container=document.getElementById(this.settings.containerId),this.container||console.error("Could not find element with ID "+this.settings.containerId),this.scroller=this.settings.scroller,this.images=this._parseImageData(t),function(t,i,e){var s="#"+t+" { position: relative;}."+i+"-figure { background-color: #D5D5D5; overflow: hidden; left: 0; position: absolute; top: 0; margin: 0;}."+i+"-figure img { left: 0; position: absolute; top: 0; height: 100%; width: 100%; opacity: 0; transition: "+e/1e3+"s ease opacity; -webkit-transition: "+e/1e3+"s ease opacity;}."+i+"-figure img."+i+"-thumbnail { -webkit-filter: blur(30px); filter: blur(30px); left: auto; position: relative; width: auto;}."+i+"-figure img."+i+"-loaded { opacity: 1;}",n=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",o.styleSheet?o.styleSheet.cssText=s:o.appendChild(document.createTextNode(s)),n.appendChild(o)}(this.settings.containerId,this.settings.classPrefix,this.settings.transitionSpeed),this}function r(t,i,e){return this.existsOnPage=!1,this.aspectRatio=t.aspectRatio,this.filename=t.filename,this.index=i,this.pig=e,this.classNames={figure:e.settings.classPrefix+"-figure",thumbnail:e.settings.classPrefix+"-thumbnail",loaded:e.settings.classPrefix+"-loaded"},this}a.prototype._getTransitionTimeout=function(){return 1.5*this.settings.transitionSpeed},a.prototype._getTransitionString=function(){return this.isTransitioning?this.settings.transitionSpeed/1e3+"s transform ease":"none"},a.prototype._recomputeMinAspectRatio=function(){var t=this.minAspectRatio;this.minAspectRatio=this.settings.getMinAspectRatio(this.lastWindowWidth),null!==t&&t!==this.minAspectRatio?this.minAspectRatioRequiresTransition=!0:this.minAspectRatioRequiresTransition=!1},a.prototype._parseImageData=function(t){var s=[];return t.forEach(function(t,i){var e=new r(t,i,this);s.push(e)}.bind(this)),s},a.prototype._computeLayout=function(){var s=parseInt(this.container.clientWidth),n=[],o=0,a=0,r=0;this._recomputeMinAspectRatio(),!this.isTransitioning&&this.minAspectRatioRequiresTransition&&(this.isTransitioning=!0,setTimeout(function(){this.isTransitioning=!1},this._getTransitionTimeout()));var h=this._getTransitionString();[].forEach.call(this.images,function(t,i){if(r+=parseFloat(t.aspectRatio),n.push(t),r>=this.minAspectRatio||i+1===this.images.length){r=Math.max(r,this.minAspectRatio);var e=(s-this.settings.spaceBetweenImages*(n.length-1))/r;n.forEach(function(t){var i=e*t.aspectRatio;t.style={width:parseInt(i),height:parseInt(e),translateX:o,translateY:a,transition:h},o+=i+this.settings.spaceBetweenImages}.bind(this)),n=[],r=0,a+=parseInt(e)+this.settings.spaceBetweenImages,o=0}}.bind(this)),this.totalHeight=a-this.settings.spaceBetweenImages},a.prototype._doLayout=function(){this.container.style.height=this.totalHeight+"px";var t="up"===this.scrollDirection?this.settings.primaryImageBufferHeight:this.settings.secondaryImageBufferHeight,i="down"===this.scrollDirection?this.settings.secondaryImageBufferHeight:this.settings.primaryImageBufferHeight,e=function(t){for(var i=0;isNaN(t.offsetTop)||(i+=t.offsetTop),t=t.offsetParent;);return i}(this.container),s=this.scroller===window?window.innerHeight:this.scroller.offsetHeight,n=this.latestYOffset-e-t,o=this.latestYOffset-e+s+i;this.images.forEach(function(t){t.style.translateY+t.style.height<n||t.style.translateY>o?t.hide():t.load()}.bind(this))},a.prototype._getOnScroll=function(){var i=this;return function(){var t=i.scroller===window?window.pageYOffset:i.scroller.scrollTop;i.previousYOffset=i.latestYOffset||t,i.latestYOffset=t,i.scrollDirection=i.latestYOffset>i.previousYOffset?"down":"up",i.inRAF||(i.inRAF=!0,window.requestAnimationFrame(function(){i._doLayout(),i.inRAF=!1}))}},a.prototype.enable=function(){return this.onScroll=this._getOnScroll(),this.scroller.addEventListener("scroll",this.onScroll),this.onScroll(),this._computeLayout(),this._doLayout(),s.add(function(){this.lastWindowWidth=this.scroller===window?window.innerWidth:this.scroller.offsetWidth,this._computeLayout(),this._doLayout()}.bind(this)),this},a.prototype.disable=function(){return this.scroller.removeEventListener("scroll",this.onScroll),s.disable(),this},r.prototype.load=function(){this.existsOnPage=!0,this._updateStyles(),this.pig.container.appendChild(this.getElement()),setTimeout(function(){this.existsOnPage&&(this.thumbnail||(this.thumbnail=new Image,this.thumbnail.src=this.pig.settings.urlForSize(this.filename,this.pig.settings.thumbnailSize),this.thumbnail.className=this.classNames.thumbnail,this.thumbnail.onload=function(){this.thumbnail&&(this.thumbnail.className+=" "+this.classNames.loaded)}.bind(this),this.getElement().appendChild(this.thumbnail)),this.fullImage||(this.fullImage=new Image,this.fullImage.src=this.pig.settings.urlForSize(this.filename,this.pig.settings.getImageSize(this.pig.lastWindowWidth)),this.fullImage.onload=function(){this.fullImage&&(this.fullImage.className+=" "+this.classNames.loaded)}.bind(this),this.getElement().appendChild(this.fullImage)))}.bind(this),100)},r.prototype.hide=function(){this.getElement()&&(this.thumbnail&&(this.thumbnail.src="",this.getElement().removeChild(this.thumbnail),delete this.thumbnail),this.fullImage&&(this.fullImage.src="",this.getElement().removeChild(this.fullImage),delete this.fullImage)),this.existsOnPage&&this.pig.container.removeChild(this.getElement()),this.existsOnPage=!1},r.prototype.getElement=function(){return this.element||(this.element=document.createElement(this.pig.settings.figureTagName),this.element.className=this.classNames.figure,this.element.addEventListener("click",function(){this.pig.settings.onClickHandler(this.filename)}.bind(this)),this._updateStyles()),this.element},r.prototype._updateStyles=function(){this.getElement().style.transition=this.style.transition,this.getElement().style.width=this.style.width+"px",this.getElement().style.height=this.style.height+"px",this.getElement().style.transform="translate3d("+this.style.translateX+"px,"+this.style.translateY+"px, 0)"},"function"==typeof define&&define.amd?define([],function(){return a}):"undefined"!=typeof module&&module.exports?module.exports=a:t.Pig=a}("undefined"!=typeof window?window:this);'
29
-
30
- def full_size_html(gallery_name, name, date, prev_url, next_url)
31
- "---\n" \
32
- "layout: post\n" \
33
- "title: #{name}\n" \
34
- "date: #{date.strftime("%Y-%m-%d %H:%M:%S")}\n" \
35
- "permalink: /assets/html/#{gallery_name}/#{name}.html\n" \
36
- "exclude: true\n" \
37
- "---\n" \
38
- "<div><a href=\"#{prev_url}\" style=\"display:inline;\">prev</a><a href=\"#{next_url}\" style=\"display:inline; float:right\">next</a></div>\n" \
39
- "<img src=\"{{site.baseurl}}/assets/img/#{gallery_name}/1024/#{name}\"/>\n"
40
- end
41
-
42
- def gallery_html(id, image_data)
43
- "<div id='#{id}_pig'></div>\n" \
44
- "<script src='{{site.baseurl}}/assets/js/pig.min.js'></script>\n" \
45
- "<script>\n" \
46
- "var #{id}_pig = new Pig(\n" \
47
- " #{image_data.to_json()},\n" \
48
- " {\n" \
49
- " containerId: '#{id}_pig',\n" \
50
- " classPrefix: '#{id}_pig',\n" \
51
- " urlForSize: function(filename, size) {\n" \
52
- " return '{{site.baseurl}}/assets/img/#{id}/' + size + '/' + filename;\n" \
53
- " },\n" \
54
- " onClickHandler: function(filename) {\n" \
55
- " window.location.href = '{{site.baseurl}}/assets/html/#{id}/' + filename + '.html';\n" \
56
- " }\n" \
57
- " }\n" \
58
- ").enable();\n" \
59
- "</script>"
60
- end
61
-
62
- def image_html_url(gallery_name, image_name)
63
- "/assets/html/#{gallery_name}/#{image_name}.html"
64
- end
65
-
66
- #read the image data from the _includes folder
67
- def get_image_data(gallery_name)
68
- image_data = []
69
- #read image_data if existing
70
- if File.exists?(File.join(@data_path, "#{gallery_name}.json"))
71
- File.open(File.join(@data_path, "#{gallery_name}.json"), 'r') { |file|
72
- #get array of image data (drop 'var imageData = ' and ';')
73
- image_data = JSON.parse(file.read)
74
- }
75
- end
76
- image_data
77
- end
78
-
79
- #get a list of image file names from a given path
80
- def get_images(path)
81
- patterns = ['*.jpg', '*.jpeg', '*.png'].map { |ext| File.join(path, ext) }
82
- Dir.glob(patterns).map { |filepath| File.basename(filepath) }
83
- end
84
-
85
- def get_image(gallery_path, image_name)
86
- image = @@image_cache[File.join(gallery_path, image_name)]
87
- if image == nil
88
- image = MiniMagick::Image.open(File.join(gallery_path, image_name))
89
- @@image_cache[File.join(gallery_path, image_name)] = image
90
- end
91
- image
92
- end
93
-
94
- def get_image_date(gallery_path, image_name)
95
- image_date = nil
96
- begin
97
- image = get_image(gallery_path, image_name)
98
- exif_date = image.exif['DateTimeOriginal']
99
- if exif_date == nil
100
- #no exif date, try to get from file name
101
- image_date = Time.strptime(image_name, "%Y-%m-%d")
102
- else
103
- #try to get the image date from exif
104
- image_date = Time.strptime(exif_date, "%Y:%m:%d %H:%M:%S")
105
- end
106
- rescue
107
- #get the date from file if possible
108
- image_date = File.mtime(File.join(gallery_path, image_name))
109
- end
110
- image_date
111
- end
112
-
113
- def get_previous_url(image_data, gallery_name, image_name)
114
- index = image_data.index { |data| data['filename'] == image_name }
115
- index = index - 1
116
- if index < 0
117
- index = image_data.length - 1
118
- end
119
- image_html_url(gallery_name, image_data[index]['filename'])
120
- end
121
-
122
- def get_next_url(image_data, gallery_name, image_name)
123
- index = image_data.index { |data| data['filename'] == image_name }
124
- index = index + 1
125
- if index >= image_data.length
126
- index = 0
127
- end
128
- image_html_url(gallery_name, image_data[index]['filename'])
129
- end
130
-
131
- #create thumbnails and fullsize image assets
132
- def process_images(image_data, gallery_id, gallery_path, images)
133
- #create thumbs
134
- sizes = [1024, 500, 250, 100, 20]
135
- sizes.each { |size|
136
- #output path for current size
137
- size_out_path = File.join(@img_path, gallery_id, size.to_s)
138
- FileUtils.mkdir_p size_out_path unless File.exists? size_out_path
139
-
140
- #images that have already been processed for the current size
141
- done_images = get_images(size_out_path)
142
- #all images in the gallery with the ones already done taken away
143
- todo_images = images - done_images
144
-
145
- #function to get the source path to use for creating the given size thumbnail
146
- #i.e. use the 500px sized images to make the 250px versions
147
- source_for_size = -> (size) {
148
- index = sizes.index(size)
149
- source = gallery_path
150
- if index != nil && index != 0
151
- source = File.join(@img_path, gallery_id, sizes[index - 1].to_s)
152
- end
153
- source
154
- }
155
-
156
- #do the processing in a batch
157
- mog = MiniMagick::Tool::Mogrify.new
158
- mog.resize("x#{size}")
159
- mog.sampling_factor('4:2:0')
160
- mog.colorspace('RGB')
161
- mog.interlace('Plane')
162
- mog.strip()
163
- mog.quality('75')
164
- mog.path(size_out_path)
165
- source_path = source_for_size.call(size)
166
- todo_images.each { |todo| mog << File.join(source_path, todo) }
167
- mog.call
168
- }
169
- end
170
-
171
- #create full size html page for a given image
172
- def process_image(image_data, gallery_id, gallery_path, image_name)
173
- full_size_html_path = File.join(@html_path, gallery_id, image_name + ".html")
174
- #create full size html if it doesn't exist
175
- if not File.exists? full_size_html_path
176
- #get image date
177
- image_date = get_image_date(gallery_path, image_name)
178
- #create full size html text
179
- full_size_html = full_size_html(gallery_id, image_name, image_date,
180
- get_previous_url(image_data, gallery_id, image_name),
181
- get_next_url(image_data, gallery_id, image_name))
182
- File.open(full_size_html_path, 'w') { |file|
183
- file.write(full_size_html)
184
- }
185
- end
186
- end
187
-
188
- def get_paths
189
- @assets_path = File.join(@site.source, "assets")
190
- @js_path = File.join(@assets_path, "js")
191
- @data_path = File.join(@site.source, "_data")
192
- @img_path = File.join(@assets_path, "img")
193
- @html_path = File.join(@assets_path, "html")
194
- @includes_path = File.join(@site.source, "_includes")
195
- end
196
-
197
- def get_galleries
198
- galleries = []
199
- config_galleries = Jekyll.configuration({})['galleries']
200
- if config_galleries != nil
201
- config_galleries.each do |gallery|
202
- full_path = File.join(@site.source, gallery['path'])
203
- if File.directory?(full_path)
204
- galleries << SourceGallery.new(full_path, gallery['name'])
205
- end
206
- end
207
- else
208
- default_gallery_path = File.join(@site.source, 'gallery')
209
- if File.directory?(default_gallery_path)
210
- galleries << SourceGallery.new(default_gallery_path, 'gallery')
211
- end
212
- end
213
- galleries
214
- end
215
-
216
- def make_output_paths
217
- FileUtils.mkdir_p @assets_path unless File.exists? @assets_path
218
- FileUtils.mkdir_p @js_path unless File.exists? @js_path
219
- FileUtils.mkdir_p @img_path unless File.exists? @img_path
220
- FileUtils.mkdir_p @html_path unless File.exists? @html_path
221
- FileUtils.mkdir_p @includes_path unless File.exists? @includes_path
222
- FileUtils.mkdir_p @data_path unless File.exists? @data_path
223
- end
224
-
225
- def augment_image_data(gallery, image_data, images)
226
- images.each do |image_name|
227
- #append data to image_data array if it's not already there
228
- if not image_data.any? { |data| data['filename'] == image_name }
229
- #get image date
230
- image_date = get_image_date(gallery.path, image_name)
231
- image = get_image(gallery.path, image_name)
232
- image_data <<
233
- {
234
- 'datetime' => image_date.to_s,
235
- 'filename' => image_name,
236
- 'aspectRatio' => image.width.to_f / image.height
237
- }
238
- end
239
- end
240
- end
241
-
242
- def generate(site)
243
- @site = site
244
- get_paths()
245
- make_output_paths()
246
- galleries = get_galleries()
247
- galleries.each do |gallery|
248
-
249
- #make gallery specific html and image output paths
250
- html_output_path = File.join(@html_path, gallery.name)
251
- FileUtils.mkdir_p html_output_path unless File.exists? html_output_path
252
- img_output_path = File.join(@img_path, gallery.name)
253
- FileUtils.mkdir_p img_output_path unless File.exists? img_output_path
254
-
255
- #write pig.min.js to js path
256
- if not File.exists? File.join(@js_path, 'pig.min.js')
257
- File.open(File.join(@js_path, 'pig.min.js'), 'w') { |file| file.write(@@pig_min_js) }
258
- end
259
-
260
- #get image data from _data
261
- image_data = get_image_data(gallery.name)
262
- old_image_data = image_data.clone
263
-
264
- #get images from gallery
265
- images = get_images(gallery.path)
266
-
267
- #add any additional images to image_data
268
- augment_image_data(gallery, image_data, images)
269
-
270
- #sort image data
271
- image_data = image_data.sort_by { |data| data['datetime'] }
272
-
273
- #create thumbs
274
- process_images(image_data, gallery.name, gallery.path, images)
275
-
276
- images.each do |image_name|
277
- #create html assets for each image
278
- process_image(image_data, gallery.name, gallery.path, image_name)
279
- end
280
-
281
- if image_data != old_image_data
282
- #write image_data
283
- File.open(File.join(@data_path, "#{gallery.name}.json"), 'w') { |file|
284
- file.write(image_data.to_json)
285
- }
286
-
287
- #save this gallery's includable content
288
- File.open(File.join(@includes_path, "#{gallery.name}.html"), 'w') { |file|
289
- file.write(gallery_html(gallery.name, image_data))
290
- }
291
- end
292
- end
293
- end
294
- end
295
- end
1
+
2
+ require 'fileutils'
3
+ require 'json'
4
+ require 'mini_magick'
5
+
6
+ module JekyllPig
7
+
8
+ class SourceGallery
9
+ def initialize(path, name)
10
+ @path = path
11
+ @name = name
12
+ end
13
+ def to_s
14
+ "gallery #{@name} at #{@path}"
15
+ end
16
+ def path
17
+ @path
18
+ end
19
+ def name
20
+ @name
21
+ end
22
+ end
23
+
24
+ class JekyllPig < Jekyll::Generator
25
+
26
+ @@image_cache = {}
27
+
28
+ @@pig_min_js = '!function(t){"use strict";var i,e,s=(e=!(i=[]),{add:function(t){i.length||window.addEventListener("resize",n),i.push(t)},disable:function(){window.removeEventListener("resize",n)},reEnable:function(){window.addEventListener("resize",n)}});function n(){e||(e=!0,window.requestAnimationFrame?window.requestAnimationFrame(o):setTimeout(o,66))}function o(){i.forEach(function(t){t()}),e=!1}function a(t,i){return this.inRAF=!1,this.isTransitioning=!1,this.minAspectRatioRequiresTransition=!1,this.minAspectRatio=null,this.latestYOffset=0,this.lastWindowWidth=window.innerWidth,this.scrollDirection="down",this.visibleImages=[],this.settings={containerId:"pig",scroller:window,classPrefix:"pig",figureTagName:"figure",spaceBetweenImages:8,transitionSpeed:500,primaryImageBufferHeight:1e3,secondaryImageBufferHeight:300,thumbnailSize:20,urlForSize:function(t,i){return"/img/"+i+"/"+t},onClickHandler:function(t){},getMinAspectRatio:function(t){return t<=640?2:t<=1280?4:t<=1920?5:6},getImageSize:function(t){return t<=640?100:t<=1920?250:500}},function(t,i){for(var e in i)i.hasOwnProperty(e)&&(t[e]=i[e])}(this.settings,i||{}),this.container=document.getElementById(this.settings.containerId),this.container||console.error("Could not find element with ID "+this.settings.containerId),this.scroller=this.settings.scroller,this.images=this._parseImageData(t),function(t,i,e){var s="#"+t+" { position: relative;}."+i+"-figure { background-color: #D5D5D5; overflow: hidden; left: 0; position: absolute; top: 0; margin: 0;}."+i+"-figure img { left: 0; position: absolute; top: 0; height: 100%; width: 100%; opacity: 0; transition: "+e/1e3+"s ease opacity; -webkit-transition: "+e/1e3+"s ease opacity;}."+i+"-figure img."+i+"-thumbnail { -webkit-filter: blur(30px); filter: blur(30px); left: auto; position: relative; width: auto;}."+i+"-figure img."+i+"-loaded { opacity: 1;}",n=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",o.styleSheet?o.styleSheet.cssText=s:o.appendChild(document.createTextNode(s)),n.appendChild(o)}(this.settings.containerId,this.settings.classPrefix,this.settings.transitionSpeed),this}function r(t,i,e){return this.existsOnPage=!1,this.aspectRatio=t.aspectRatio,this.filename=t.filename,this.index=i,this.pig=e,this.classNames={figure:e.settings.classPrefix+"-figure",thumbnail:e.settings.classPrefix+"-thumbnail",loaded:e.settings.classPrefix+"-loaded"},this}a.prototype._getTransitionTimeout=function(){return 1.5*this.settings.transitionSpeed},a.prototype._getTransitionString=function(){return this.isTransitioning?this.settings.transitionSpeed/1e3+"s transform ease":"none"},a.prototype._recomputeMinAspectRatio=function(){var t=this.minAspectRatio;this.minAspectRatio=this.settings.getMinAspectRatio(this.lastWindowWidth),null!==t&&t!==this.minAspectRatio?this.minAspectRatioRequiresTransition=!0:this.minAspectRatioRequiresTransition=!1},a.prototype._parseImageData=function(t){var s=[];return t.forEach(function(t,i){var e=new r(t,i,this);s.push(e)}.bind(this)),s},a.prototype._computeLayout=function(){var s=parseInt(this.container.clientWidth),n=[],o=0,a=0,r=0;this._recomputeMinAspectRatio(),!this.isTransitioning&&this.minAspectRatioRequiresTransition&&(this.isTransitioning=!0,setTimeout(function(){this.isTransitioning=!1},this._getTransitionTimeout()));var h=this._getTransitionString();[].forEach.call(this.images,function(t,i){if(r+=parseFloat(t.aspectRatio),n.push(t),r>=this.minAspectRatio||i+1===this.images.length){r=Math.max(r,this.minAspectRatio);var e=(s-this.settings.spaceBetweenImages*(n.length-1))/r;n.forEach(function(t){var i=e*t.aspectRatio;t.style={width:parseInt(i),height:parseInt(e),translateX:o,translateY:a,transition:h},o+=i+this.settings.spaceBetweenImages}.bind(this)),n=[],r=0,a+=parseInt(e)+this.settings.spaceBetweenImages,o=0}}.bind(this)),this.totalHeight=a-this.settings.spaceBetweenImages},a.prototype._doLayout=function(){this.container.style.height=this.totalHeight+"px";var t="up"===this.scrollDirection?this.settings.primaryImageBufferHeight:this.settings.secondaryImageBufferHeight,i="down"===this.scrollDirection?this.settings.secondaryImageBufferHeight:this.settings.primaryImageBufferHeight,e=function(t){for(var i=0;isNaN(t.offsetTop)||(i+=t.offsetTop),t=t.offsetParent;);return i}(this.container),s=this.scroller===window?window.innerHeight:this.scroller.offsetHeight,n=this.latestYOffset-e-t,o=this.latestYOffset-e+s+i;this.images.forEach(function(t){t.style.translateY+t.style.height<n||t.style.translateY>o?t.hide():t.load()}.bind(this))},a.prototype._getOnScroll=function(){var i=this;return function(){var t=i.scroller===window?window.pageYOffset:i.scroller.scrollTop;i.previousYOffset=i.latestYOffset||t,i.latestYOffset=t,i.scrollDirection=i.latestYOffset>i.previousYOffset?"down":"up",i.inRAF||(i.inRAF=!0,window.requestAnimationFrame(function(){i._doLayout(),i.inRAF=!1}))}},a.prototype.enable=function(){return this.onScroll=this._getOnScroll(),this.scroller.addEventListener("scroll",this.onScroll),this.onScroll(),this._computeLayout(),this._doLayout(),s.add(function(){this.lastWindowWidth=this.scroller===window?window.innerWidth:this.scroller.offsetWidth,this._computeLayout(),this._doLayout()}.bind(this)),this},a.prototype.disable=function(){return this.scroller.removeEventListener("scroll",this.onScroll),s.disable(),this},r.prototype.load=function(){this.existsOnPage=!0,this._updateStyles(),this.pig.container.appendChild(this.getElement()),setTimeout(function(){this.existsOnPage&&(this.thumbnail||(this.thumbnail=new Image,this.thumbnail.src=this.pig.settings.urlForSize(this.filename,this.pig.settings.thumbnailSize),this.thumbnail.className=this.classNames.thumbnail,this.thumbnail.onload=function(){this.thumbnail&&(this.thumbnail.className+=" "+this.classNames.loaded)}.bind(this),this.getElement().appendChild(this.thumbnail)),this.fullImage||(this.fullImage=new Image,this.fullImage.src=this.pig.settings.urlForSize(this.filename,this.pig.settings.getImageSize(this.pig.lastWindowWidth)),this.fullImage.onload=function(){this.fullImage&&(this.fullImage.className+=" "+this.classNames.loaded)}.bind(this),this.getElement().appendChild(this.fullImage)))}.bind(this),100)},r.prototype.hide=function(){this.getElement()&&(this.thumbnail&&(this.thumbnail.src="",this.getElement().removeChild(this.thumbnail),delete this.thumbnail),this.fullImage&&(this.fullImage.src="",this.getElement().removeChild(this.fullImage),delete this.fullImage)),this.existsOnPage&&this.pig.container.removeChild(this.getElement()),this.existsOnPage=!1},r.prototype.getElement=function(){return this.element||(this.element=document.createElement(this.pig.settings.figureTagName),this.element.className=this.classNames.figure,this.element.addEventListener("click",function(){this.pig.settings.onClickHandler(this.filename)}.bind(this)),this._updateStyles()),this.element},r.prototype._updateStyles=function(){this.getElement().style.transition=this.style.transition,this.getElement().style.width=this.style.width+"px",this.getElement().style.height=this.style.height+"px",this.getElement().style.transform="translate3d("+this.style.translateX+"px,"+this.style.translateY+"px, 0)"},"function"==typeof define&&define.amd?define([],function(){return a}):"undefined"!=typeof module&&module.exports?module.exports=a:t.Pig=a}("undefined"!=typeof window?window:this);'
29
+
30
+ def full_size_html(gallery_name, name, date, prev_url, next_url)
31
+ "---\n" \
32
+ "layout: post\n" \
33
+ "title: #{name}\n" \
34
+ "date: #{date.strftime("%Y-%m-%d %H:%M:%S")}\n" \
35
+ "permalink: /assets/html/#{gallery_name}/#{name}.html\n" \
36
+ "exclude: true\n" \
37
+ "---\n" \
38
+ "<div><a href=\"#{prev_url}\" style=\"display:inline;\">prev</a><a href=\"#{next_url}\" style=\"display:inline; float:right\">next</a></div>\n" \
39
+ "<img src=\"{{site.baseurl}}/assets/img/#{gallery_name}/1024/#{name}\"/>\n"
40
+ end
41
+
42
+ def gallery_html(id, image_data)
43
+ "<div id='#{id}_pig'></div>\n" \
44
+ "<script src='{{site.baseurl}}/assets/js/pig.min.js'></script>\n" \
45
+ "<script>\n" \
46
+ "var #{id}_pig = new Pig(\n" \
47
+ " #{image_data.to_json()},\n" \
48
+ " {\n" \
49
+ " containerId: '#{id}_pig',\n" \
50
+ " classPrefix: '#{id}_pig',\n" \
51
+ " urlForSize: function(filename, size) {\n" \
52
+ " return '{{site.baseurl}}/assets/img/#{id}/' + size + '/' + filename;\n" \
53
+ " },\n" \
54
+ " onClickHandler: function(filename) {\n" \
55
+ " window.location.href = '{{site.baseurl}}/assets/html/#{id}/' + filename + '.html';\n" \
56
+ " }\n" \
57
+ " }\n" \
58
+ ").enable();\n" \
59
+ "</script>"
60
+ end
61
+
62
+ def image_html_url(gallery_name, image_name)
63
+ "/assets/html/#{gallery_name}/#{image_name}.html"
64
+ end
65
+
66
+ #read the image data from the _includes folder
67
+ def get_image_data(gallery_name)
68
+ image_data = []
69
+ #read image_data if existing
70
+ if File.exists?(File.join(@data_path, "#{gallery_name}.json"))
71
+ File.open(File.join(@data_path, "#{gallery_name}.json"), 'r') { |file|
72
+ #get array of image data (drop 'var imageData = ' and ';')
73
+ image_data = JSON.parse(file.read)
74
+ }
75
+ end
76
+ image_data
77
+ end
78
+
79
+ #get a list of image file names from a given path
80
+ def get_images(path)
81
+ patterns = ['*.jpg', '*.jpeg', '*.png'].map { |ext| File.join(path, ext) }
82
+ Dir.glob(patterns).map { |filepath| File.basename(filepath) }
83
+ end
84
+
85
+ def get_image(gallery_path, image_name)
86
+ image = @@image_cache[File.join(gallery_path, image_name)]
87
+ if image == nil
88
+ image = MiniMagick::Image.open(File.join(gallery_path, image_name))
89
+ @@image_cache[File.join(gallery_path, image_name)] = image
90
+ end
91
+ image
92
+ end
93
+
94
+ def get_image_date(gallery_path, image_name)
95
+ image_date = nil
96
+ begin
97
+ image = get_image(gallery_path, image_name)
98
+ exif_date = image.exif['DateTimeOriginal']
99
+ if exif_date == nil
100
+ #no exif date, try to get from file name
101
+ image_date = Time.strptime(image_name, "%Y-%m-%d")
102
+ else
103
+ #try to get the image date from exif
104
+ image_date = Time.strptime(exif_date, "%Y:%m:%d %H:%M:%S")
105
+ end
106
+ rescue
107
+ #get the date from file if possible
108
+ image_date = File.mtime(File.join(gallery_path, image_name))
109
+ end
110
+ image_date
111
+ end
112
+
113
+ def get_previous_url(image_data, gallery_name, image_name)
114
+ index = image_data.index { |data| data['filename'] == image_name }
115
+ index = index - 1
116
+ if index < 0
117
+ index = image_data.length - 1
118
+ end
119
+ image_html_url(gallery_name, image_data[index]['filename'])
120
+ end
121
+
122
+ def get_next_url(image_data, gallery_name, image_name)
123
+ index = image_data.index { |data| data['filename'] == image_name }
124
+ index = index + 1
125
+ if index >= image_data.length
126
+ index = 0
127
+ end
128
+ image_html_url(gallery_name, image_data[index]['filename'])
129
+ end
130
+
131
+ #create thumbnails and fullsize image assets
132
+ def process_images(image_data, gallery_id, gallery_path, images)
133
+ #create thumbs
134
+ sizes = [1024, 500, 250, 100, 20]
135
+ sizes.each { |size|
136
+ #output path for current size
137
+ size_out_path = File.join(@img_path, gallery_id, size.to_s)
138
+ FileUtils.mkdir_p size_out_path unless File.exists? size_out_path
139
+
140
+ #images that have already been processed for the current size
141
+ done_images = get_images(size_out_path)
142
+ #all images in the gallery with the ones already done taken away
143
+ todo_images = images - done_images
144
+
145
+ #function to get the source path to use for creating the given size thumbnail
146
+ #i.e. use the 500px sized images to make the 250px versions
147
+ source_for_size = -> (size) {
148
+ index = sizes.index(size)
149
+ source = gallery_path
150
+ if index != nil && index != 0
151
+ source = File.join(@img_path, gallery_id, sizes[index - 1].to_s)
152
+ end
153
+ source
154
+ }
155
+
156
+ #do the processing in a batch
157
+ mog = MiniMagick::Tool::Mogrify.new
158
+ mog.resize("x#{size}")
159
+ mog.sampling_factor('4:2:0')
160
+ mog.interlace('Plane')
161
+ mog.strip()
162
+ mog.quality('75')
163
+ mog.path(size_out_path)
164
+ source_path = source_for_size.call(size)
165
+ todo_images.each { |todo| mog << File.join(source_path, todo) }
166
+ mog.call
167
+ }
168
+ end
169
+
170
+ #create full size html page for a given image
171
+ def process_image(image_data, gallery_id, gallery_path, image_name)
172
+ full_size_html_path = File.join(@html_path, gallery_id, image_name + ".html")
173
+ #create full size html if it doesn't exist
174
+ if not File.exists? full_size_html_path
175
+ #get image date
176
+ image_date = get_image_date(gallery_path, image_name)
177
+ #create full size html text
178
+ full_size_html = full_size_html(gallery_id, image_name, image_date,
179
+ get_previous_url(image_data, gallery_id, image_name),
180
+ get_next_url(image_data, gallery_id, image_name))
181
+ File.open(full_size_html_path, 'w') { |file|
182
+ file.write(full_size_html)
183
+ }
184
+ end
185
+ end
186
+
187
+ def get_paths
188
+ @assets_path = File.join(@site.source, "assets")
189
+ @js_path = File.join(@assets_path, "js")
190
+ @data_path = File.join(@site.source, "_data")
191
+ @img_path = File.join(@assets_path, "img")
192
+ @html_path = File.join(@assets_path, "html")
193
+ @includes_path = File.join(@site.source, "_includes")
194
+ end
195
+
196
+ def get_galleries
197
+ galleries = []
198
+ config_galleries = Jekyll.configuration({})['galleries']
199
+ if config_galleries != nil
200
+ config_galleries.each do |gallery|
201
+ full_path = File.join(@site.source, gallery['path'])
202
+ if File.directory?(full_path)
203
+ galleries << SourceGallery.new(full_path, gallery['name'])
204
+ end
205
+ end
206
+ else
207
+ default_gallery_path = File.join(@site.source, 'gallery')
208
+ if File.directory?(default_gallery_path)
209
+ galleries << SourceGallery.new(default_gallery_path, 'gallery')
210
+ end
211
+ end
212
+ galleries
213
+ end
214
+
215
+ def make_output_paths
216
+ FileUtils.mkdir_p @assets_path unless File.exists? @assets_path
217
+ FileUtils.mkdir_p @js_path unless File.exists? @js_path
218
+ FileUtils.mkdir_p @img_path unless File.exists? @img_path
219
+ FileUtils.mkdir_p @html_path unless File.exists? @html_path
220
+ FileUtils.mkdir_p @includes_path unless File.exists? @includes_path
221
+ FileUtils.mkdir_p @data_path unless File.exists? @data_path
222
+ end
223
+
224
+ def augment_image_data(gallery, image_data, images)
225
+ images.each do |image_name|
226
+ #append data to image_data array if it's not already there
227
+ if not image_data.any? { |data| data['filename'] == image_name }
228
+ #get image date
229
+ image_date = get_image_date(gallery.path, image_name)
230
+ image = get_image(gallery.path, image_name)
231
+ image_data <<
232
+ {
233
+ 'datetime' => image_date.to_s,
234
+ 'filename' => image_name,
235
+ 'aspectRatio' => image.width.to_f / image.height
236
+ }
237
+ end
238
+ end
239
+ end
240
+
241
+ def generate(site)
242
+ @site = site
243
+ get_paths()
244
+ make_output_paths()
245
+ galleries = get_galleries()
246
+ galleries.each do |gallery|
247
+
248
+ #make gallery specific html and image output paths
249
+ html_output_path = File.join(@html_path, gallery.name)
250
+ FileUtils.mkdir_p html_output_path unless File.exists? html_output_path
251
+ img_output_path = File.join(@img_path, gallery.name)
252
+ FileUtils.mkdir_p img_output_path unless File.exists? img_output_path
253
+
254
+ #write pig.min.js to js path
255
+ if not File.exists? File.join(@js_path, 'pig.min.js')
256
+ File.open(File.join(@js_path, 'pig.min.js'), 'w') { |file| file.write(@@pig_min_js) }
257
+ end
258
+
259
+ #get image data from _data
260
+ image_data = get_image_data(gallery.name)
261
+ old_image_data = image_data.clone
262
+
263
+ #get images from gallery
264
+ images = get_images(gallery.path)
265
+
266
+ #add any additional images to image_data
267
+ augment_image_data(gallery, image_data, images)
268
+
269
+ #sort image data
270
+ image_data = image_data.sort_by { |data| data['datetime'] }
271
+
272
+ #create thumbs
273
+ process_images(image_data, gallery.name, gallery.path, images)
274
+
275
+ images.each do |image_name|
276
+ #create html assets for each image
277
+ process_image(image_data, gallery.name, gallery.path, image_name)
278
+ end
279
+
280
+ if image_data != old_image_data
281
+ #write image_data
282
+ File.open(File.join(@data_path, "#{gallery.name}.json"), 'w') { |file|
283
+ file.write(image_data.to_json)
284
+ }
285
+
286
+ #save this gallery's includable content
287
+ File.open(File.join(@includes_path, "#{gallery.name}.html"), 'w') { |file|
288
+ file.write(gallery_html(gallery.name, image_data))
289
+ }
290
+ end
291
+ end
292
+ end
293
+ end
294
+ end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-pig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Colin Holzman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2020-03-04 00:00:00.000000000 Z
@@ -36,7 +36,7 @@ homepage: https://github.com/clnhlzmn/jekyll-pig
36
36
  licenses:
37
37
  - MIT
38
38
  metadata: {}
39
- post_install_message:
39
+ post_install_message:
40
40
  rdoc_options: []
41
41
  require_paths:
42
42
  - lib
@@ -52,9 +52,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
52
  version: '0'
53
53
  requirements:
54
54
  - ImageMagick or GraphicsMagick
55
- rubyforge_project:
56
- rubygems_version: 2.7.6
57
- signing_key:
55
+ rubygems_version: 3.1.2
56
+ signing_key:
58
57
  specification_version: 4
59
58
  summary: Jekyll image gallery generator
60
59
  test_files: []