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
data/views/index.erb
CHANGED
|
@@ -14,13 +14,17 @@
|
|
|
14
14
|
<div id="chooseSourceImage">
|
|
15
15
|
|
|
16
16
|
<p>
|
|
17
|
-
Enter an image URL, click a thumbnail or search for an image
|
|
18
|
-
thumbnail.
|
|
17
|
+
Enter an image URL, upload an image, click a thumbnail or search for an image
|
|
18
|
+
then click its thumbnail.
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
<p>
|
|
22
22
|
<label for="u">Source image URL: </label>
|
|
23
23
|
<input type="text" id="u" name="u" size="64" value="<%= h @u %>" />
|
|
24
|
+
<form action="upload" method="post" enctype="multipart/form-data">
|
|
25
|
+
<input type="file" id="upload" name="upload" />
|
|
26
|
+
<input type="submit" id="uploadSubmit" value="Upload" disabled="disabled" />
|
|
27
|
+
</form>
|
|
24
28
|
</p>
|
|
25
29
|
|
|
26
30
|
<div id="localSourceImages"></div>
|
|
@@ -50,7 +54,12 @@ thumbnail.
|
|
|
50
54
|
|
|
51
55
|
<div id="positionText">
|
|
52
56
|
|
|
53
|
-
<p>
|
|
57
|
+
<p class="noCanvas" style="display : none;">
|
|
58
|
+
If you were using a browser with canvas support such as Chrome, Firefox,
|
|
59
|
+
Safari or Internet Explorer 9 you could position the text on the image here.
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<p class="hasCanvas">
|
|
54
63
|
<input type="button" id="positionTextButton" value="Position Text" />
|
|
55
64
|
Optionally set the position and size of the text on the image.
|
|
56
65
|
</p>
|
|
@@ -112,339 +121,9 @@ Contact: Matthew M. Boedicker <a href="mailto:matthewm@boedicker.org">matthewm@b
|
|
|
112
121
|
|
|
113
122
|
<p><a href="https://github.com/mmb/meme_captain">source code and API</a></p>
|
|
114
123
|
|
|
115
|
-
<script src="
|
|
124
|
+
<script src="js/jquery-1.7.2.min.js"></script>
|
|
116
125
|
<script src="js/fabric.min.js"></script>
|
|
117
|
-
<script>
|
|
118
|
-
function setSourceUrl(sourceUrl) {
|
|
119
|
-
"use strict";
|
|
120
|
-
|
|
121
|
-
$('#u').val(sourceUrl);
|
|
122
|
-
$('#t1x,#t1y,#t1w,#t1h,#t2x,#t2y,#t2w,#t2h').val('');
|
|
123
|
-
$('#positionTextCanvasDiv').empty();
|
|
124
|
-
$('#positionTable').hide();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function showBingImages(resp) {
|
|
128
|
-
"use strict";
|
|
129
|
-
|
|
130
|
-
var div = $('#imageSearchResults'),
|
|
131
|
-
searchResponse = resp.SearchResponse,
|
|
132
|
-
image = searchResponse.Image;
|
|
133
|
-
|
|
134
|
-
if (image.Total > 0) {
|
|
135
|
-
$.each(image.Results, function (i, img) {
|
|
136
|
-
div.append($('<img />').attr('src', img.Thumbnail.Url).click(
|
|
137
|
-
function () { setSourceUrl(img.MediaUrl); }
|
|
138
|
-
));
|
|
139
|
-
});
|
|
140
|
-
} else {
|
|
141
|
-
div.append($('<p />').append(
|
|
142
|
-
'No Bing results for "' + searchResponse.Query.SearchTerms + '".'
|
|
143
|
-
));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function showGoogleImages(resp) {
|
|
148
|
-
"use strict";
|
|
149
|
-
|
|
150
|
-
var div = $('#imageSearchResults'),
|
|
151
|
-
searchResults = resp.responseData.results;
|
|
152
|
-
|
|
153
|
-
if (searchResults.length > 0) {
|
|
154
|
-
$.each(searchResults, function (i, img) {
|
|
155
|
-
div.append($('<img />').attr('src', img.tbUrl).click(
|
|
156
|
-
function () { setSourceUrl(img.url); }
|
|
157
|
-
));
|
|
158
|
-
});
|
|
159
|
-
} else {
|
|
160
|
-
div.append($('<p />').append('No Google results.'));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function imageSearch() {
|
|
165
|
-
"use strict";
|
|
166
|
-
|
|
167
|
-
var imageSearchInput = $('#imageSearch'),
|
|
168
|
-
imageSearchVal = imageSearchInput.val();
|
|
169
|
-
|
|
170
|
-
if (imageSearchVal.match(/[^\s]/)) {
|
|
171
|
-
imageSearchInput.val('');
|
|
172
|
-
$('#imageSearchResults').empty();
|
|
173
|
-
|
|
174
|
-
$.ajax({
|
|
175
|
-
type : 'GET',
|
|
176
|
-
url : 'http://api.bing.net/json.aspx',
|
|
177
|
-
data : {
|
|
178
|
-
AppId : 'A120380275E87F0071F163210211F0592D0E964C',
|
|
179
|
-
Query : imageSearchVal,
|
|
180
|
-
Sources : 'Image',
|
|
181
|
-
Version : '2.0',
|
|
182
|
-
Market : 'en-us',
|
|
183
|
-
'Image.Count' : 5,
|
|
184
|
-
'Image.Filters' : 'Size:Large',
|
|
185
|
-
'Image.Offset' : 0,
|
|
186
|
-
JsonType : 'callback'
|
|
187
|
-
},
|
|
188
|
-
dataType : 'jsonp',
|
|
189
|
-
jsonpCallback : 'showBingImages',
|
|
190
|
-
jsonp : 'JsonCallback'
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
$.ajax({
|
|
194
|
-
type : 'GET',
|
|
195
|
-
url : 'http://ajax.googleapis.com/ajax/services/search/images',
|
|
196
|
-
data : {
|
|
197
|
-
imgsz : 'large',
|
|
198
|
-
key : 'ABQIAAAA-E0uJIHoMJX6M6atCgYANRS1DzXPXMqKnKNRJm2Z_PRWxvtqGBSOvBqyXOwxGZU5jLxExg_5ym69rw',
|
|
199
|
-
q : imageSearchVal,
|
|
200
|
-
rsz : '5',
|
|
201
|
-
v : '1.0'
|
|
202
|
-
},
|
|
203
|
-
dataType : 'jsonp',
|
|
204
|
-
jsonpCallback : 'showGoogleImages'
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function loadSourceImages() {
|
|
210
|
-
"use strict";
|
|
211
|
-
|
|
212
|
-
$.get('source_images.json', function (data) {
|
|
213
|
-
var pos = 0,
|
|
214
|
-
div = $('#localSourceImages');
|
|
215
|
-
|
|
216
|
-
$.each(data.images, function (i, img) {
|
|
217
|
-
div.append($('<img />').attr('src',
|
|
218
|
-
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAAXNSR0IArs4c6QAAAAJiS0dEAACqjSMyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AIBAQMqmgCy0wAAAAtJREFUCNdjYGAAAAADAAEg1ZTHAAAAAElFTkSuQmCC'
|
|
219
|
-
).addClass('thumb').css({
|
|
220
|
-
'background-image' : 'url(' + data.thumbSpritesUrl + ')',
|
|
221
|
-
'background-position' : pos + 'px 0px',
|
|
222
|
-
height : data.thumbHeight,
|
|
223
|
-
width : img.thumbWidth + 'px'
|
|
224
|
-
}).click(function () { setSourceUrl(img.url); }));
|
|
225
|
-
|
|
226
|
-
pos -= img.thumbWidth;
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// scale width and height so that neither is larger than maxSide
|
|
232
|
-
function resizeToFit(width, height, maxSide) {
|
|
233
|
-
"use strict";
|
|
234
|
-
|
|
235
|
-
var result = {
|
|
236
|
-
width : width,
|
|
237
|
-
height : height
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
if (width > maxSide) {
|
|
241
|
-
result.width = maxSide;
|
|
242
|
-
result.height = height * (maxSide / width);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (result.height > maxSide) {
|
|
246
|
-
result.width = result.width * (maxSide / result.height);
|
|
247
|
-
result.height = maxSide;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return result;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function positionText() {
|
|
254
|
-
"use strict";
|
|
255
|
-
|
|
256
|
-
var imageUrl = $('#u').val(),
|
|
257
|
-
canvas;
|
|
258
|
-
|
|
259
|
-
if (imageUrl.length > 0) {
|
|
260
|
-
$('#positionTable').show();
|
|
261
|
-
$('#positionTextCanvasDiv').empty().append($('<canvas />').attr({
|
|
262
|
-
id : 'positionTextCanvas'
|
|
263
|
-
}));
|
|
264
|
-
|
|
265
|
-
canvas = new fabric.Canvas('positionTextCanvas');
|
|
266
|
-
|
|
267
|
-
canvas.setBackgroundImage(imageUrl, function () {
|
|
268
|
-
var canvasSize = resizeToFit(canvas.backgroundImage.width,
|
|
269
|
-
canvas.backgroundImage.height, 800),
|
|
270
|
-
textWidth,
|
|
271
|
-
textHeight,
|
|
272
|
-
rect1,
|
|
273
|
-
rect2;
|
|
274
|
-
|
|
275
|
-
canvas.setWidth(canvasSize.width);
|
|
276
|
-
canvas.setHeight(canvasSize.height);
|
|
277
|
-
|
|
278
|
-
canvas.renderAll.bind(canvas);
|
|
279
|
-
|
|
280
|
-
textWidth = 0.9 * canvas.getWidth();
|
|
281
|
-
textHeight = 0.25 * canvas.getHeight();
|
|
282
|
-
|
|
283
|
-
rect1 = new fabric.Rect({
|
|
284
|
-
top : textHeight / 2.0,
|
|
285
|
-
left : canvas.getWidth() / 2.0,
|
|
286
|
-
width : textWidth,
|
|
287
|
-
height : textHeight,
|
|
288
|
-
fill : 'red'
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
rect1.name = '1';
|
|
292
|
-
rect1.set('lockRotation', true);
|
|
293
|
-
|
|
294
|
-
canvas.add(rect1);
|
|
295
|
-
|
|
296
|
-
rect2 = new fabric.Rect({
|
|
297
|
-
top : canvas.getHeight() - (textHeight / 2.0),
|
|
298
|
-
left : canvas.getWidth() / 2.0,
|
|
299
|
-
width : textWidth,
|
|
300
|
-
height : textHeight,
|
|
301
|
-
fill: 'red'
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
rect2.name = '2';
|
|
305
|
-
rect2.set('lockRotation', true);
|
|
306
|
-
|
|
307
|
-
canvas.add(rect2);
|
|
308
|
-
|
|
309
|
-
canvas.observe('object:moving', function (o) {
|
|
310
|
-
var target = o.memo.target,
|
|
311
|
-
|
|
312
|
-
halfWidth = target.getWidth() / 2,
|
|
313
|
-
leftSide = Math.round(target.getLeft() - halfWidth),
|
|
314
|
-
rightSide = Math.round(target.getLeft() + halfWidth),
|
|
315
|
-
|
|
316
|
-
halfHeight = target.getHeight() / 2,
|
|
317
|
-
topSide = Math.round(target.getTop() - halfHeight),
|
|
318
|
-
bottomSide = Math.round(target.getTop() + halfHeight);
|
|
319
|
-
|
|
320
|
-
if (leftSide < 0) {
|
|
321
|
-
target.setLeft(halfWidth);
|
|
322
|
-
}
|
|
323
|
-
if (rightSide > canvas.getWidth()) {
|
|
324
|
-
target.setLeft(canvas.getWidth() - halfWidth);
|
|
325
|
-
}
|
|
326
|
-
if (topSide < 0) {
|
|
327
|
-
target.setTop(halfHeight);
|
|
328
|
-
}
|
|
329
|
-
if (bottomSide > canvas.getHeight()) {
|
|
330
|
-
target.setTop(canvas.getHeight() - halfHeight);
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
canvas.observe('object:modified', function (o) {
|
|
335
|
-
var target = o.memo.target;
|
|
336
|
-
|
|
337
|
-
$('#t' + target.name + 'x').val(
|
|
338
|
-
Math.round(target.getLeft() - (target.getWidth() / 2))
|
|
339
|
-
);
|
|
340
|
-
$('#t' + target.name + 'y').val(
|
|
341
|
-
Math.round(target.getTop() - (target.getHeight() / 2))
|
|
342
|
-
);
|
|
343
|
-
$('#t' + target.name + 'w').val(Math.round(target.getWidth()));
|
|
344
|
-
$('#t' + target.name + 'h').val(Math.round(target.getHeight()));
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
canvas.fire('object:modified', { target : rect1 });
|
|
348
|
-
canvas.fire('object:modified', { target : rect2 });
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function createImage() {
|
|
354
|
-
"use strict";
|
|
355
|
-
|
|
356
|
-
var createdImageDiv = $('#createdImage');
|
|
357
|
-
|
|
358
|
-
$('#positionTextCanvasDiv').empty();
|
|
359
|
-
|
|
360
|
-
createdImageDiv.append($('<p />').append('Creating image ...'));
|
|
361
|
-
|
|
362
|
-
$.get('/g', {
|
|
363
|
-
u : $('#u').val(),
|
|
364
|
-
t1 : $('#t1').val(),
|
|
365
|
-
t2 : $('#t2').val(),
|
|
366
|
-
|
|
367
|
-
t1x : $('#t1x').val(),
|
|
368
|
-
t1y : $('#t1y').val(),
|
|
369
|
-
t1w : $('#t1w').val(),
|
|
370
|
-
t1h : $('#t1h').val(),
|
|
371
|
-
|
|
372
|
-
t2x : $('#t2x').val(),
|
|
373
|
-
t2y : $('#t2y').val(),
|
|
374
|
-
t2w : $('#t2w').val(),
|
|
375
|
-
t2h : $('#t2h').val()
|
|
376
|
-
}, function (data) {
|
|
377
|
-
var img = $('<img />').attr('src', data.imageUrl),
|
|
378
|
-
imgLink = $('<a />').attr('href', data.imageUrl).append(
|
|
379
|
-
data.imageUrl
|
|
380
|
-
),
|
|
381
|
-
tweetLink = $('<a />').attr({
|
|
382
|
-
href : 'http://twitter.com/share',
|
|
383
|
-
'class' : 'twitter-share-button',
|
|
384
|
-
'data-count' : 'none',
|
|
385
|
-
'data-text' : ' ',
|
|
386
|
-
'data-url' : data.imageUrl
|
|
387
|
-
}).append('Tweet');
|
|
388
|
-
|
|
389
|
-
createdImageDiv.empty().append(img).append(
|
|
390
|
-
$('<p />').append('Image: ').append(imgLink)
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
// tweet link
|
|
394
|
-
createdImageDiv.append($('<p />').append(tweetLink).append(
|
|
395
|
-
$('<script />').attr('src',
|
|
396
|
-
'http://platform.twitter.com/widgets.js')
|
|
397
|
-
));
|
|
398
|
-
|
|
399
|
-
// Facebook like
|
|
400
|
-
createdImageDiv.append(
|
|
401
|
-
$('<div />').attr('id', 'fb-root')
|
|
402
|
-
).append(
|
|
403
|
-
$('<fb:like />').attr({
|
|
404
|
-
href : data.imageUrl,
|
|
405
|
-
send : 'true',
|
|
406
|
-
width : '450',
|
|
407
|
-
show_faces : 'true',
|
|
408
|
-
font : ''
|
|
409
|
-
})
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
window.fbAsyncInit = function () {
|
|
413
|
-
FB.init({
|
|
414
|
-
appId : '108445492580525',
|
|
415
|
-
status : true,
|
|
416
|
-
cookie : true,
|
|
417
|
-
xfbml : true
|
|
418
|
-
});
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
createdImageDiv.append($('<script />').attr({
|
|
422
|
-
src : 'http://connect.facebook.net/en_US/all.js'
|
|
423
|
-
}));
|
|
424
|
-
}).error(function (j) {
|
|
425
|
-
createdImageDiv.empty().append($('<p />').text(j.responseText));
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
$(function () {
|
|
430
|
-
"use strict";
|
|
431
|
-
|
|
432
|
-
loadSourceImages();
|
|
433
|
-
|
|
434
|
-
$('#imageSearch').keypress(function (event) {
|
|
435
|
-
if (event.which === 13) {
|
|
436
|
-
event.preventDefault();
|
|
437
|
-
imageSearch();
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
$('#imageSearchButton').click(imageSearch);
|
|
442
|
-
|
|
443
|
-
$('#positionTextButton').click(positionText);
|
|
444
|
-
|
|
445
|
-
$('#createImageButton').click(createImage);
|
|
446
|
-
});
|
|
447
|
-
</script>
|
|
126
|
+
<script src="js/meme_captain.js"></script>
|
|
448
127
|
|
|
449
128
|
</body>
|
|
450
129
|
|