meme_captain 0.1.0 → 0.1.1
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.
- data/ChangeLog +62 -2
- data/Gemfile +3 -0
- data/README.md +6 -1
- data/config.ru +4 -0
- data/doc/lightweight_front_end.md +64 -0
- data/doc/setup.md +13 -0
- data/lib/meme_captain/image_list/fetch.rb +2 -0
- data/lib/meme_captain/meme.rb +16 -4
- data/lib/meme_captain/memebg.rb +62 -0
- data/lib/meme_captain/norm_params.rb +92 -0
- data/lib/meme_captain/pretty_format.rb +12 -0
- data/lib/meme_captain/server.rb +134 -74
- data/lib/meme_captain/upload.rb +30 -0
- data/lib/meme_captain/version.rb +1 -1
- data/lib/meme_captain.rb +4 -1
- data/meme_captain.gemspec +2 -0
- data/public/css/screen.css +14 -0
- data/public/favicon.ico +0 -0
- data/public/js/fabric.min.js +3 -3
- data/public/js/jquery-1.7.2.min.js +4 -0
- data/public/js/meme_captain.js +403 -0
- data/public/source_images.json +65 -1
- data/public/thumbs.jpg +0 -0
- data/public/thumbs_1330486916.jpg +0 -0
- data/public/thumbs_1333591668.jpg +0 -0
- data/public/thumbs_1334189407.jpg +0 -0
- data/public/thumbs_1334973608.jpg +0 -0
- data/script/thumb_sprites.rb +57 -14
- data/spec/caption_choice_spec.rb +53 -0
- data/spec/caption_spec.rb +45 -0
- data/spec/image_list/fetch_spec.rb +33 -0
- data/spec/meme_captain_spec.rb +8 -2
- data/spec/memebg_spec.rb +14 -0
- data/spec/norm_params_spec.rb +223 -0
- data/spec/pretty_format_spec.rb +9 -0
- data/spec/text_pos_spec.rb +29 -0
- data/views/index.erb +14 -335
- metadata +150 -161
- data/lib/meme_captain/file_body.rb +0 -15
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
var MEMECAPTAIN = (function (window, $, fabric) {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var my = {},
|
|
5
|
+
|
|
6
|
+
bingAppId = 'A120380275E87F0071F163210211F0592D0E964C',
|
|
7
|
+
facebookAppId = '108445492580525',
|
|
8
|
+
googleApiKey = 'ABQIAAAA-E0uJIHoMJX6M6atCgYANRS1DzXPXMqKnKNRJm2Z_PRWxvtqGBSOvBqyXOwxGZU5jLxExg_5ym69rw',
|
|
9
|
+
genUrl = '/g',
|
|
10
|
+
genDataType = genUrl === '/g' ? 'json' : 'jsonp',
|
|
11
|
+
imageMaxSide = 800;
|
|
12
|
+
|
|
13
|
+
function setSourceUrl(sourceUrl) {
|
|
14
|
+
$('#u').val(sourceUrl).addClass('attn');
|
|
15
|
+
$('#t1x,#t1y,#t1w,#t1h,#t2x,#t2y,#t2w,#t2h').val('');
|
|
16
|
+
$('#positionTextCanvasDiv').empty();
|
|
17
|
+
$('#positionTable').hide();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// scale width and height so that neither is larger than maxSide
|
|
21
|
+
function resizeToFit(width, height, maxSide) {
|
|
22
|
+
var result = {
|
|
23
|
+
width : width,
|
|
24
|
+
height : height
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (width > maxSide) {
|
|
28
|
+
result.width = maxSide;
|
|
29
|
+
result.height = Math.round(height * (maxSide / width));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (result.height > maxSide) {
|
|
33
|
+
result.width = Math.round(
|
|
34
|
+
result.width * (maxSide / result.height)
|
|
35
|
+
);
|
|
36
|
+
result.height = maxSide;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// build an image search result thumbnail
|
|
43
|
+
function searchThumbnail(thumbnailUrl, imgUrl, imgWidth, imgHeight) {
|
|
44
|
+
var scaledDimensions = resizeToFit(imgWidth, imgHeight, imageMaxSide),
|
|
45
|
+
title = scaledDimensions.width + ' x ' + scaledDimensions.height,
|
|
46
|
+
thumbnailImage = $('<img />').attr({
|
|
47
|
+
src : thumbnailUrl,
|
|
48
|
+
title : title,
|
|
49
|
+
width : scaledDimensions.width / 4.0,
|
|
50
|
+
height : scaledDimensions.height / 4.0
|
|
51
|
+
}).addClass('thumb');
|
|
52
|
+
|
|
53
|
+
return thumbnailImage.click(function () { setSourceUrl(imgUrl); });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function showBingImages(resp) {
|
|
57
|
+
var div = $('#imageSearchResults'),
|
|
58
|
+
searchResponse = resp.SearchResponse,
|
|
59
|
+
image = searchResponse.Image;
|
|
60
|
+
|
|
61
|
+
if (image.Total > 0) {
|
|
62
|
+
$.each(image.Results, function (i, img) {
|
|
63
|
+
div.append(searchThumbnail(
|
|
64
|
+
img.Thumbnail.Url,
|
|
65
|
+
img.MediaUrl,
|
|
66
|
+
img.Width,
|
|
67
|
+
img.Height
|
|
68
|
+
));
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
div.append($('<p />').append(
|
|
72
|
+
'No Bing results for "' + searchResponse.Query.SearchTerms + '".'
|
|
73
|
+
));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function showGoogleImages(resp) {
|
|
78
|
+
var div = $('#imageSearchResults'),
|
|
79
|
+
searchResults = resp.responseData.results;
|
|
80
|
+
|
|
81
|
+
if (searchResults.length > 0) {
|
|
82
|
+
$.each(searchResults, function (i, img) {
|
|
83
|
+
div.append(searchThumbnail(img.tbUrl, img.unescapedUrl,
|
|
84
|
+
parseInt(img.width, 10), parseInt(img.height, 10)));
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
div.append($('<p />').append('No Google results.'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function loadSourceImages() {
|
|
92
|
+
$.get('source_images.json', function (data) {
|
|
93
|
+
var pos = 0,
|
|
94
|
+
div = $('#localSourceImages');
|
|
95
|
+
|
|
96
|
+
$.each(data.images, function (i, img) {
|
|
97
|
+
div.append($('<img />').attr('src',
|
|
98
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAAXNSR0IArs4c6QAAAAJiS0dEAACqjSMyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AIBAQMqmgCy0wAAAAtJREFUCNdjYGAAAAADAAEg1ZTHAAAAAElFTkSuQmCC'
|
|
99
|
+
).addClass('thumb').css({
|
|
100
|
+
'background-image' : 'url(' + data.thumbSpritesUrl + ')',
|
|
101
|
+
'background-position' : pos + 'px 0px',
|
|
102
|
+
height : data.thumbHeight,
|
|
103
|
+
width : img.thumbWidth + 'px'
|
|
104
|
+
}).click(function () { setSourceUrl(img.url); }));
|
|
105
|
+
|
|
106
|
+
pos -= img.thumbWidth;
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function imageSearch() {
|
|
112
|
+
var imageSearchInput = $('#imageSearch'),
|
|
113
|
+
imageSearchVal = imageSearchInput.val();
|
|
114
|
+
|
|
115
|
+
if (imageSearchVal.match(/[^\s]/)) {
|
|
116
|
+
imageSearchInput.val('');
|
|
117
|
+
$('#imageSearchResults').empty();
|
|
118
|
+
|
|
119
|
+
$.ajax({
|
|
120
|
+
type : 'GET',
|
|
121
|
+
url : 'http://api.bing.net/json.aspx',
|
|
122
|
+
data : {
|
|
123
|
+
AppId : bingAppId,
|
|
124
|
+
Query : imageSearchVal,
|
|
125
|
+
Sources : 'Image',
|
|
126
|
+
Version : '2.0',
|
|
127
|
+
Market : 'en-us',
|
|
128
|
+
'Image.Count' : 5,
|
|
129
|
+
'Image.Filters' : 'Size:Large',
|
|
130
|
+
'Image.Offset' : 0,
|
|
131
|
+
JsonType : 'callback'
|
|
132
|
+
},
|
|
133
|
+
dataType : 'jsonp',
|
|
134
|
+
jsonp : 'JsonCallback',
|
|
135
|
+
success : showBingImages
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
$.ajax({
|
|
139
|
+
type : 'GET',
|
|
140
|
+
url : 'http://ajax.googleapis.com/ajax/services/search/images',
|
|
141
|
+
data : {
|
|
142
|
+
imgsz : 'large',
|
|
143
|
+
key : googleApiKey,
|
|
144
|
+
q : imageSearchVal,
|
|
145
|
+
rsz : '5',
|
|
146
|
+
v : '1.0'
|
|
147
|
+
},
|
|
148
|
+
dataType : 'jsonp',
|
|
149
|
+
success : showGoogleImages
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function positionText() {
|
|
155
|
+
var imageUrl = $('#u').val(),
|
|
156
|
+
canvas;
|
|
157
|
+
|
|
158
|
+
if (imageUrl.length > 0) {
|
|
159
|
+
$('#positionTable').show();
|
|
160
|
+
$('#positionTextCanvasDiv').empty().append($('<canvas />').attr({
|
|
161
|
+
id : 'positionTextCanvas'
|
|
162
|
+
}));
|
|
163
|
+
|
|
164
|
+
canvas = new fabric.Canvas('positionTextCanvas');
|
|
165
|
+
|
|
166
|
+
canvas.setBackgroundImage(imageUrl, function () {
|
|
167
|
+
var canvasSize = resizeToFit(canvas.backgroundImage.width,
|
|
168
|
+
canvas.backgroundImage.height, imageMaxSide),
|
|
169
|
+
textWidth,
|
|
170
|
+
textHeight,
|
|
171
|
+
rect1,
|
|
172
|
+
rect2;
|
|
173
|
+
|
|
174
|
+
canvas.setWidth(canvasSize.width);
|
|
175
|
+
canvas.setHeight(canvasSize.height);
|
|
176
|
+
|
|
177
|
+
canvas.renderAll.bind(canvas);
|
|
178
|
+
|
|
179
|
+
textWidth = 0.9 * canvas.getWidth();
|
|
180
|
+
textHeight = 0.25 * canvas.getHeight();
|
|
181
|
+
|
|
182
|
+
rect1 = new fabric.Rect({
|
|
183
|
+
top : textHeight / 2.0,
|
|
184
|
+
left : canvas.getWidth() / 2.0,
|
|
185
|
+
width : textWidth,
|
|
186
|
+
height : textHeight,
|
|
187
|
+
fill : 'red'
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
rect1.name = '1';
|
|
191
|
+
rect1.set('lockRotation', true);
|
|
192
|
+
|
|
193
|
+
canvas.add(rect1);
|
|
194
|
+
|
|
195
|
+
rect2 = new fabric.Rect({
|
|
196
|
+
top : canvas.getHeight() - (textHeight / 2.0),
|
|
197
|
+
left : canvas.getWidth() / 2.0,
|
|
198
|
+
width : textWidth,
|
|
199
|
+
height : textHeight,
|
|
200
|
+
fill: 'red'
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
rect2.name = '2';
|
|
204
|
+
rect2.set('lockRotation', true);
|
|
205
|
+
|
|
206
|
+
canvas.add(rect2);
|
|
207
|
+
|
|
208
|
+
canvas.observe('object:moving', function (o) {
|
|
209
|
+
var target = o.memo.target,
|
|
210
|
+
|
|
211
|
+
halfWidth = target.getWidth() / 2,
|
|
212
|
+
leftSide = Math.round(target.getLeft() - halfWidth),
|
|
213
|
+
rightSide = Math.round(target.getLeft() + halfWidth),
|
|
214
|
+
|
|
215
|
+
halfHeight = target.getHeight() / 2,
|
|
216
|
+
topSide = Math.round(target.getTop() - halfHeight),
|
|
217
|
+
bottomSide = Math.round(target.getTop() + halfHeight);
|
|
218
|
+
|
|
219
|
+
if (leftSide < 0) {
|
|
220
|
+
target.setLeft(halfWidth);
|
|
221
|
+
}
|
|
222
|
+
if (rightSide > canvas.getWidth()) {
|
|
223
|
+
target.setLeft(canvas.getWidth() - halfWidth);
|
|
224
|
+
}
|
|
225
|
+
if (topSide < 0) {
|
|
226
|
+
target.setTop(halfHeight);
|
|
227
|
+
}
|
|
228
|
+
if (bottomSide > canvas.getHeight()) {
|
|
229
|
+
target.setTop(canvas.getHeight() - halfHeight);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
canvas.observe('object:modified', function (o) {
|
|
234
|
+
var target = o.memo.target;
|
|
235
|
+
|
|
236
|
+
$('#t' + target.name + 'x').val(
|
|
237
|
+
Math.round(target.getLeft() - (target.getWidth() / 2))
|
|
238
|
+
);
|
|
239
|
+
$('#t' + target.name + 'y').val(
|
|
240
|
+
Math.round(target.getTop() - (target.getHeight() / 2))
|
|
241
|
+
);
|
|
242
|
+
$('#t' + target.name + 'w').val(Math.round(target.getWidth()));
|
|
243
|
+
$('#t' + target.name + 'h').val(Math.round(target.getHeight()));
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
canvas.fire('object:modified', { target : rect1 });
|
|
247
|
+
canvas.fire('object:modified', { target : rect2 });
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function redditLink(url) {
|
|
253
|
+
return $('<a />').attr('href',
|
|
254
|
+
'http://www.reddit.com/submit?url=' +
|
|
255
|
+
encodeURIComponent(url)).append('reddit');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// build a Twitter tweet link for a url
|
|
259
|
+
function tweetLink(url) {
|
|
260
|
+
return $('<a />').attr({
|
|
261
|
+
href : 'http://twitter.com/share',
|
|
262
|
+
'class' : 'twitter-share-button',
|
|
263
|
+
'data-count' : 'none',
|
|
264
|
+
'data-text' : ' ',
|
|
265
|
+
'data-url' : url
|
|
266
|
+
}).append('Tweet');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// build Twitter tweet script tag
|
|
270
|
+
function tweetScript() {
|
|
271
|
+
return $('<script />').attr(
|
|
272
|
+
'src',
|
|
273
|
+
'http://platform.twitter.com/widgets.js'
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// build Facebook Like div for a url
|
|
278
|
+
function facebookLikeDiv(url) {
|
|
279
|
+
return $('<div />').attr('id', 'fb-root').addClass('share').append(
|
|
280
|
+
$('<fb:like />').attr({
|
|
281
|
+
href : url,
|
|
282
|
+
send : 'true',
|
|
283
|
+
width : '450',
|
|
284
|
+
show_faces : 'true',
|
|
285
|
+
font : ''
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Facebook asynchronous init
|
|
291
|
+
function fbAsyncInit() {
|
|
292
|
+
FB.init({
|
|
293
|
+
appId : facebookAppId,
|
|
294
|
+
status : true,
|
|
295
|
+
cookie : true,
|
|
296
|
+
xfbml : true
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function facebookScript() {
|
|
301
|
+
return $('<script />').attr({
|
|
302
|
+
src : 'http://connect.facebook.net/en_US/all.js'
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function createImage() {
|
|
307
|
+
var createdImageDiv,
|
|
308
|
+
uVal = $('#u').val();
|
|
309
|
+
|
|
310
|
+
if (uVal !== '') {
|
|
311
|
+
createdImageDiv = $('#createdImage');
|
|
312
|
+
|
|
313
|
+
$('#positionTextCanvasDiv').empty();
|
|
314
|
+
|
|
315
|
+
createdImageDiv.prepend($('<p />').append('Creating image ...'));
|
|
316
|
+
|
|
317
|
+
$.get(genUrl, {
|
|
318
|
+
u : uVal,
|
|
319
|
+
t1 : $('#t1').val(),
|
|
320
|
+
t2 : $('#t2').val(),
|
|
321
|
+
|
|
322
|
+
t1x : $('#t1x').val(),
|
|
323
|
+
t1y : $('#t1y').val(),
|
|
324
|
+
t1w : $('#t1w').val(),
|
|
325
|
+
t1h : $('#t1h').val(),
|
|
326
|
+
|
|
327
|
+
t2x : $('#t2x').val(),
|
|
328
|
+
t2y : $('#t2y').val(),
|
|
329
|
+
t2w : $('#t2w').val(),
|
|
330
|
+
t2h : $('#t2h').val()
|
|
331
|
+
}, function (data) {
|
|
332
|
+
var img = $('<img />').attr('src', data.imageUrl),
|
|
333
|
+
imgLink = $('<a />').attr('href', data.imageUrl).append(
|
|
334
|
+
data.imageUrl
|
|
335
|
+
),
|
|
336
|
+
templateLink = $('<a />').attr(
|
|
337
|
+
'href',
|
|
338
|
+
data.templateUrl
|
|
339
|
+
).append(data.templateUrl);
|
|
340
|
+
|
|
341
|
+
createdImageDiv.empty().append(img).append(
|
|
342
|
+
$('<p />').append('Image: ').append(imgLink)
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
// template link
|
|
346
|
+
createdImageDiv.append(
|
|
347
|
+
$('<p />').append('To make more with this source image: ').
|
|
348
|
+
append(templateLink)
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
// reddit link
|
|
352
|
+
createdImageDiv.append($('<div />').addClass(
|
|
353
|
+
'share'
|
|
354
|
+
).append(redditLink(data.imageUrl)));
|
|
355
|
+
|
|
356
|
+
// tweet link
|
|
357
|
+
createdImageDiv.append($('<div />').addClass('share').append(
|
|
358
|
+
tweetLink(data.imageUrl)
|
|
359
|
+
).append(tweetScript()));
|
|
360
|
+
|
|
361
|
+
// Facebook like
|
|
362
|
+
createdImageDiv.append(facebookLikeDiv(data.imageUrl));
|
|
363
|
+
window.fbAsyncInit = fbAsyncInit;
|
|
364
|
+
createdImageDiv.append(facebookScript());
|
|
365
|
+
}, genDataType).error(function (j) {
|
|
366
|
+
createdImageDiv.empty().append($('<p />').text(j.responseText));
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
my.init = function () {
|
|
372
|
+
loadSourceImages();
|
|
373
|
+
|
|
374
|
+
$('#imageSearch').keypress(function (event) {
|
|
375
|
+
if (event.which === 13) {
|
|
376
|
+
event.preventDefault();
|
|
377
|
+
imageSearch();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
$('#imageSearchButton').click(imageSearch);
|
|
382
|
+
|
|
383
|
+
$('#positionTextButton').click(positionText);
|
|
384
|
+
|
|
385
|
+
$('#createImageButton').click(createImage);
|
|
386
|
+
|
|
387
|
+
$('#upload').change(function () {
|
|
388
|
+
$('#uploadSubmit').removeAttr('disabled');
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// highlight input fields that have been preloaded from the query string
|
|
392
|
+
$(":text[value!='']").addClass('attn');
|
|
393
|
+
|
|
394
|
+
if (!window.CanvasRenderingContext2D) {
|
|
395
|
+
$('.hasCanvas').hide();
|
|
396
|
+
$('.noCanvas').show();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
return my;
|
|
401
|
+
}(window, $, fabric));
|
|
402
|
+
|
|
403
|
+
$(MEMECAPTAIN.init);
|
data/public/source_images.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"thumbHeight": 50,
|
|
3
|
-
"thumbSpritesUrl": "http://memecaptain.com/
|
|
3
|
+
"thumbSpritesUrl": "http://memecaptain.com/thumbs_1334973608.jpg",
|
|
4
4
|
"images": [
|
|
5
5
|
{
|
|
6
6
|
"url": "http://memecaptain.com/all_the_things.jpg",
|
|
@@ -10,10 +10,26 @@
|
|
|
10
10
|
"url": "http://memecaptain.com/all_the_things2.jpg",
|
|
11
11
|
"thumbWidth": 67
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"url": "http://memecaptain.com/annoying_facebook_girl.jpg",
|
|
15
|
+
"thumbWidth": 50
|
|
16
|
+
},
|
|
13
17
|
{
|
|
14
18
|
"url": "http://memecaptain.com/aw_yeah.png",
|
|
15
19
|
"thumbWidth": 50
|
|
16
20
|
},
|
|
21
|
+
{
|
|
22
|
+
"url": "http://memecaptain.com/bad_joke_eel.jpg",
|
|
23
|
+
"thumbWidth": 67
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"url": "http://memecaptain.com/bad_luck_brian.jpg",
|
|
27
|
+
"thumbWidth": 42
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"url": "http://memecaptain.com/bad_time.jpg",
|
|
31
|
+
"thumbWidth": 60
|
|
32
|
+
},
|
|
17
33
|
{
|
|
18
34
|
"url": "http://memecaptain.com/bear_grylls.jpg",
|
|
19
35
|
"thumbWidth": 45
|
|
@@ -26,6 +42,10 @@
|
|
|
26
42
|
"url": "http://memecaptain.com/business_cat.jpg",
|
|
27
43
|
"thumbWidth": 50
|
|
28
44
|
},
|
|
45
|
+
{
|
|
46
|
+
"url": "http://memecaptain.com/conspiracy_keanu.jpg",
|
|
47
|
+
"thumbWidth": 50
|
|
48
|
+
},
|
|
29
49
|
{
|
|
30
50
|
"url": "http://memecaptain.com/cool_story_bro.jpg",
|
|
31
51
|
"thumbWidth": 72
|
|
@@ -38,6 +58,10 @@
|
|
|
38
58
|
"url": "http://memecaptain.com/dwight_schrute.jpg",
|
|
39
59
|
"thumbWidth": 73
|
|
40
60
|
},
|
|
61
|
+
{
|
|
62
|
+
"url": "http://memecaptain.com/first_world_problems.jpg",
|
|
63
|
+
"thumbWidth": 72
|
|
64
|
+
},
|
|
41
65
|
{
|
|
42
66
|
"url": "http://memecaptain.com/fry.png",
|
|
43
67
|
"thumbWidth": 67
|
|
@@ -62,6 +86,10 @@
|
|
|
62
86
|
"url": "http://memecaptain.com/joseph_ducreux.jpg",
|
|
63
87
|
"thumbWidth": 38
|
|
64
88
|
},
|
|
89
|
+
{
|
|
90
|
+
"url": "http://memecaptain.com/laundry_room_viking.jpg",
|
|
91
|
+
"thumbWidth": 67
|
|
92
|
+
},
|
|
65
93
|
{
|
|
66
94
|
"url": "http://memecaptain.com/me_gusta.png",
|
|
67
95
|
"thumbWidth": 50
|
|
@@ -74,10 +102,22 @@
|
|
|
74
102
|
"url": "http://memecaptain.com/ned_stark.jpg",
|
|
75
103
|
"thumbWidth": 55
|
|
76
104
|
},
|
|
105
|
+
{
|
|
106
|
+
"url": "http://memecaptain.com/neil_degrasse_tyson.png",
|
|
107
|
+
"thumbWidth": 50
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"url": "http://memecaptain.com/not_bad.png",
|
|
111
|
+
"thumbWidth": 50
|
|
112
|
+
},
|
|
77
113
|
{
|
|
78
114
|
"url": "http://memecaptain.com/ok.png",
|
|
79
115
|
"thumbWidth": 50
|
|
80
116
|
},
|
|
117
|
+
{
|
|
118
|
+
"url": "http://memecaptain.com/paranoid_parrot.jpg",
|
|
119
|
+
"thumbWidth": 50
|
|
120
|
+
},
|
|
81
121
|
{
|
|
82
122
|
"url": "http://memecaptain.com/philosoraptor.jpg",
|
|
83
123
|
"thumbWidth": 50
|
|
@@ -86,6 +126,10 @@
|
|
|
86
126
|
"url": "http://memecaptain.com/rage.png",
|
|
87
127
|
"thumbWidth": 50
|
|
88
128
|
},
|
|
129
|
+
{
|
|
130
|
+
"url": "http://memecaptain.com/ron_swanson.jpg",
|
|
131
|
+
"thumbWidth": 73
|
|
132
|
+
},
|
|
89
133
|
{
|
|
90
134
|
"url": "http://memecaptain.com/sap.jpg",
|
|
91
135
|
"thumbWidth": 50
|
|
@@ -102,10 +146,22 @@
|
|
|
102
146
|
"url": "http://memecaptain.com/slowpoke.jpg",
|
|
103
147
|
"thumbWidth": 50
|
|
104
148
|
},
|
|
149
|
+
{
|
|
150
|
+
"url": "http://memecaptain.com/socially_awesome_awkward_penguin.jpg",
|
|
151
|
+
"thumbWidth": 50
|
|
152
|
+
},
|
|
105
153
|
{
|
|
106
154
|
"url": "http://memecaptain.com/success_kid.jpg",
|
|
107
155
|
"thumbWidth": 50
|
|
108
156
|
},
|
|
157
|
+
{
|
|
158
|
+
"url": "http://memecaptain.com/the_more_you_know.jpg",
|
|
159
|
+
"thumbWidth": 76
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"url": "http://memecaptain.com/ti_duck.jpg",
|
|
163
|
+
"thumbWidth": 50
|
|
164
|
+
},
|
|
109
165
|
{
|
|
110
166
|
"url": "http://memecaptain.com/town_crier.jpg",
|
|
111
167
|
"thumbWidth": 75
|
|
@@ -126,6 +182,10 @@
|
|
|
126
182
|
"url": "http://memecaptain.com/tyler_durden.jpg",
|
|
127
183
|
"thumbWidth": 50
|
|
128
184
|
},
|
|
185
|
+
{
|
|
186
|
+
"url": "http://memecaptain.com/wonka.jpg",
|
|
187
|
+
"thumbWidth": 50
|
|
188
|
+
},
|
|
129
189
|
{
|
|
130
190
|
"url": "http://memecaptain.com/xzibit.jpg",
|
|
131
191
|
"thumbWidth": 77
|
|
@@ -137,6 +197,10 @@
|
|
|
137
197
|
{
|
|
138
198
|
"url": "http://memecaptain.com/yao_ming.jpg",
|
|
139
199
|
"thumbWidth": 42
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"url": "http://memecaptain.com/you_should_feel_bad.jpg",
|
|
203
|
+
"thumbWidth": 67
|
|
140
204
|
}
|
|
141
205
|
]
|
|
142
206
|
}
|
data/public/thumbs.jpg
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/script/thumb_sprites.rb
CHANGED
|
@@ -1,33 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
require 'RMagick'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
3
2
|
|
|
4
3
|
# make a combined thumbnail image from a list of images for use in CSS sprites
|
|
5
4
|
# generate source images description json
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'optparse'
|
|
8
|
+
|
|
9
|
+
require 'RMagick'
|
|
10
|
+
|
|
11
|
+
OPTIONS = {
|
|
12
|
+
:json_file => 'source_images.json',
|
|
13
|
+
:source_url_prefix => '',
|
|
14
|
+
:thumb_file => "thumbs_#{Time.now.to_i}.jpg",
|
|
15
|
+
:thumb_height => 50,
|
|
16
|
+
:url_root => 'http://memecaptain.com/',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
OptionParser.new do |opts|
|
|
20
|
+
opts.banner = 'usage: thumb_sprites.rb [options] FILE...'
|
|
21
|
+
|
|
22
|
+
opts.on('-j', '--json-file JSON_FILE', 'output JSON file path') do |j|
|
|
23
|
+
OPTIONS[:json_file] = j
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opts.on('-s', '--source-url-prefix SOURCE_URL_PREFIX',
|
|
27
|
+
'source image URL prefix') do |s|
|
|
28
|
+
OPTIONS[:source_url_prefix] = s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
opts.on('-t', '--thumb-height THUMB_HEIGHT',
|
|
32
|
+
'thumbnail height in pixels') do |t|
|
|
33
|
+
OPTIONS[:thumb_height] = t
|
|
34
|
+
end
|
|
8
35
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
36
|
+
opts.on('-u', '--url-root URL_ROOT', 'URL root') do |u|
|
|
37
|
+
OPTIONS[:url_root] = u
|
|
38
|
+
end
|
|
39
|
+
end.parse!
|
|
40
|
+
|
|
41
|
+
DATA = {
|
|
42
|
+
:thumbHeight => OPTIONS[:thumb_height],
|
|
43
|
+
:thumbSpritesUrl => "#{OPTIONS[:url_root]}#{OPTIONS[:thumb_file]}",
|
|
12
44
|
:images => [],
|
|
13
45
|
}
|
|
14
46
|
|
|
15
|
-
|
|
47
|
+
puts <<eos
|
|
48
|
+
source URL prefix: #{OPTIONS[:source_url_prefix]}
|
|
49
|
+
thumbnail height: #{OPTIONS[:thumb_height]}
|
|
50
|
+
URL root: #{OPTIONS[:url_root]}
|
|
51
|
+
|
|
52
|
+
eos
|
|
53
|
+
|
|
54
|
+
THUMBS = Magick::ImageList.new
|
|
16
55
|
|
|
17
56
|
ARGV.sort.each do |file|
|
|
57
|
+
puts " processing #{file}"
|
|
18
58
|
image = Magick::ImageList.new(file)
|
|
19
|
-
image.resize_to_fit!(0,
|
|
59
|
+
image.resize_to_fit!(0, DATA[:thumbHeight])
|
|
20
60
|
image.each do |frame|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
:url =>
|
|
61
|
+
THUMBS.push frame
|
|
62
|
+
DATA[:images] << {
|
|
63
|
+
:url =>
|
|
64
|
+
"#{OPTIONS[:url_root]}#{OPTIONS[:source_url_prefix]}#{File.basename(file)}",
|
|
24
65
|
:thumbWidth => frame.columns
|
|
25
66
|
}
|
|
26
67
|
end
|
|
27
68
|
end
|
|
28
69
|
|
|
29
|
-
open(
|
|
30
|
-
f.write(JSON.pretty_generate(
|
|
70
|
+
open(OPTIONS[:json_file], 'w') do |f|
|
|
71
|
+
f.write(JSON.pretty_generate(DATA))
|
|
72
|
+
puts "wrote #{OPTIONS[:json_file]}"
|
|
31
73
|
end
|
|
32
74
|
|
|
33
|
-
|
|
75
|
+
THUMBS.append(false).write(OPTIONS[:thumb_file])
|
|
76
|
+
puts "wrote #{OPTIONS[:thumb_file]}"
|