summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xhtmljs/gallery/gallery706
-rw-r--r--htmljs/gallery/gallery_main.css245
-rw-r--r--htmljs/gallery/gallery_main.js156
-rw-r--r--htmljs/gallery/index.html97
-rw-r--r--install/database/database_create_statements3
-rw-r--r--install/database/database_schema.sql15
-rwxr-xr-xpb/Breaker/__init__.py268
-rw-r--r--pb/Config/__init__.py20
-rwxr-xr-xpb/Generate/__init__.py231
-rwxr-xr-xpb/Gradient/__init__.py216
-rwxr-xr-xpb/Imgrid/__init__.py232
-rwxr-xr-xpb/Imlandscape/__init__.py101
-rwxr-xr-xpb/Imlandscape/landscape163
-rwxr-xr-xpb/Pattern/__init__.py172
-rw-r--r--[-rwxr-xr-x]pb/lib/Db/__init__.py (renamed from pb/lib/db.py)1
-rw-r--r--pb/lib/Utils/__init__.py (renamed from pb/lib/utils.py)2
-rwxr-xr-xpbserver.py215
-rw-r--r--tests/jsonptest.sh2
18 files changed, 2844 insertions, 1 deletions
diff --git a/htmljs/gallery/gallery b/htmljs/gallery/gallery
new file mode 100755
index 0000000..2b891f2
--- /dev/null
+++ b/htmljs/gallery/gallery
@@ -0,0 +1,706 @@
+#!/usr/bin/python2.7
+import os
+import cgi
+import re
+
+import random
+
+import db
+db = db.db()
+
+BASE_HREF = "http://i.asdf.us/im/"
+PARAMLIST = "addr start limit name interface random tag"
+SQL_LIMIT = 20
+QUERY_LIMIT = 20;
+
+def get_params (paramlist):
+ paramkeys = paramlist.split()
+ form = {}
+ try:
+ qs = os.environ['QUERY_STRING']
+ except:
+ qs = ""
+ if len(qs):
+ pairs = qs.replace("&", "&").split("&")
+ for pair in pairs:
+ k,v = pair.split("=", 1)
+ form[k] = v
+ params = {}
+ for key in paramkeys:
+ if key in form:
+ if key == "random":
+ params[key] = sanitizeInteger(form["random"])
+ else:
+ params[key] = sanitize(form[key])
+ else:
+ params[key] = None
+ return params
+
+def tagTranslate(s):
+ table = {
+ "grid" : "imGrid",
+ "gradient" : "imGradient",
+ "break" : "imBreak"
+ }
+ if s in table:
+ return table[s]
+ else:
+ return s
+
+def sanitize (str):
+ return re.sub(r'\W+', '', str)
+def sanitizeInteger (str):
+ return re.sub(r'\D+', '', str)
+def get_files (params):
+ sql = "SELECT * FROM im_cmd "
+ args = []
+ where = []
+
+ if params['start'] is not None:
+ where.append("id < %s")
+ args.append(params['start'])
+ if params['name'] is not None:
+ where.append("name=%s")
+ args.append(params['name'])
+ if params['tag'] is not None:
+ where.append("tag=%s")
+ args.append(tagTranslate(params['tag']))
+ if len(where):
+ sql += "WHERE "
+ sql += " AND ".join(where)
+ sql += " "
+
+ if params['random'] is not None:
+ if params['random'] == '1':
+ sql += "ORDER BY RAND(" + str(random.randint(1,2**63)) + ") "
+ else:
+ sql += "ORDER BY RAND(" + params['random'] + ") "
+ else:
+ sql += "ORDER BY id DESC "
+ sql += "LIMIT %s"
+
+ if params['limit'] is not None:
+ args.append( int(params['limit']) )
+ else:
+ args.append( SQL_LIMIT )
+ db.execute(sql, args)
+ rows = db.cursor.fetchall ()
+ return rows
+
+def is_image (img):
+ if "jpeg" in img:
+ return True
+ if "jpg" in img:
+ return True
+ if "gif" in img:
+ return True
+ if "png" in img:
+ return True
+ return False
+
+
+params = get_params(PARAMLIST)
+
+titlephrase = random.choice([
+ 'Keep on pickin\' on..',
+ 'Pickolaus Pickleby by Charles Pickens!',
+ 'You pick potato and I pick potahto...',
+ 'Take your piq!',
+ 'Show em what you got',
+ 'I sure know how to pick \'em',
+ 'Jus pick somethin already!',
+ 'You can\'t pick your friends...',
+ 'Select your image my liege',
+ 'There\'s a time to choose...',
+ 'gimme a choice! gimme lil\' choice-a-that...',
+ 'You choose you lose',
+ 'novels by James CHOICE...',
+ 'Choose away, chooser-man...',
+ ])
+
+print "Content-type: text/html"
+print "Pragma: no-cache"
+print
+print """
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+"""
+print "<title>"+titlephrase+"</title>"
+print"""
+<script type="text/javascript" src="/js/jquery.js"></script>
+<script type="text/javascript" src="/js/titleScrambler.js"></script>
+<script type="text/javascript">
+var imagedata = [ """
+
+files = get_files(params)
+count = 0
+lowest_id = 999999999999
+for f in files:
+ # url = BASE_HREF + f.replace(" ","%20")
+ url = BASE_HREF + f[5] + "/" + f[7]
+ username = f[3]
+ print ' ["%s", "%s"],' % (url, username);
+ lowest_id = min(f[0], lowest_id)
+print " []" #putting this here to handle the last "," which causes a crash in ie
+#print "<div><img src='%s' username='%s' class='pb' /></div>" % (url, username)
+#print "</div>"
+print """]
+$(function(){
+ for (var i=0; i< (imagedata.length - 1); i++){
+ var newDiv = document.createElement("div");
+ var newImage = document.createElement("img");
+ newImage.src = imagedata[i][0];
+ newImage.className = "pb";
+ newDiv.appendChild(newImage);
+// consider calling something like isotope add here...and ONLY APPENDING the image to the parent div once it has loaded
+// $(newImage).load(function(){
+// console.log("like a true playa");
+// })
+ $("#images").append(newDiv);
+ }
+});
+</script>
+<script type="text/javascript" src="/js/jquery.isotope.min.js"></script>
+<script type="text/javascript" src="/js/gallery_isotope_config.js?v=3"></script>
+<style type="text/css">
+
+html,body{width:100%;height:100%;margin:0;padding:0;}
+ """
+if params['interface'] is not None and params['interface'] == "off":
+ print """
+body
+ {
+ background-color: white;
+ padding: 0; margin: 0;
+ }
+#images
+ {
+ margin: 12px 0 0 8px;
+ }
+div, div img
+ {
+ padding: 0; margin: 0;
+ margin-left: -4px;
+ margin-top: -4px;
+ }
+"""
+else:
+ print """
+body
+ {
+ background-color: #eee;
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.32, rgb(245,238,235)), color-stop(0.66, rgb(252,252,252)));
+ background-image: -moz-linear-gradient( center bottom, rgb(245,238,235) 32%, rgb(252,252,252) 66%); overflow-y: scroll;
+ }
+"""
+print """
+html
+ {
+ padding-bottom: 200px;
+ }
+#images
+ {
+ width: 100%;
+ margin-top:70px;
+ }
+#images div
+ {
+ width: 200px;
+ display: inline-block;
+ }
+div img
+ {
+ max-width: 200px;
+ max-height: 200px;
+ border: 0;
+ }
+#images img
+ {
+ cursor: pointer;
+ display: none;
+ }
+#dump
+ {
+ position: fixed;
+ left: 0;
+ bottom: 10px;
+ padding: 10px;
+ width: 100%;
+ border-bottom: 2px solid #000;
+ background-color: #f8f8f8;
+ border-top: 1px solid #888;
+ z-index: 1000;
+ }
+#dump #rebus
+ {
+ clear: right;
+ width: 90%;
+ max-height: 700px;
+ overflow-y: scroll;
+ background-color: #fff;
+ padding-bottom: 5px;
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 5px;
+ }
+#dump #rebus img
+ {
+ cursor: pointer;
+ display: inline;
+ max-width: 400px;
+ max-height: 400px;
+ margin-right: -4px;
+ }
+#dump #urlz
+ {
+ width: 90%;
+ font-size: 15px;
+ }
+#actions
+ {
+ position: fixed;
+ top: 10px;
+ left: 10px;
+ cursor: pointer;
+ text-align: left;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#tags
+ {
+ position: fixed;
+ top: 10px;
+ left: 200px;
+ cursor: pointer;
+ text-align: left;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#help
+ {
+ position: fixed;
+ top: 10px;
+ right: 10px;
+ cursor: pointer;
+ text-align: right;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#help b {
+ text-align: right;
+}
+#help div{
+ background: rgba(200,200,200,0.8);
+}
+#keys div{
+ background: none;
+}
+#help .small{
+ font-size: 11px;
+}
+#help b, #actions b, #tags b
+ {
+ padding: 5px;
+ background-color: #f8f4fb;
+ display: block;
+ max-width: 160px;
+ }
+#help b:hover, #actions b:hover, #tags b:hover
+ {
+ color: cyan;
+
+ }
+#help #keys, #sorting-optionsContainer, #tag-optionsContainer
+ {
+ clear: both;
+ padding: 5px;
+ display: none;
+ min-width: 120px;
+ font-size: 14px;
+ }
+.sorting-options, .tag-options {
+ color:black;
+ cursor: pointer;
+ background: rgba(200,200,200,0.8);
+}
+.tag-clear{
+ color:#333;
+ cursor: pointer;
+ background: rgba(200,200,200,0.8);
+
+}
+.sorting-optionsContainer div:hover{
+ color: red;
+}
+.tag-optionsContainer div:hover{
+ color: pink;
+}
+.sorting-options:hover, .tag-options:hover, .tag-clear:hover {
+background: gold;
+}
+#nextpage
+ {
+ position: fixed;
+ right: 190px;
+ font-family: sans-serif;
+ top: 10px;
+ padding: 5px;
+ background-color: rgba(255,255,255,0.7);
+ z-index:9999
+ }
+#nextpage a
+ {
+ color: #33f;
+ }
+.rtlink
+ {
+ display: block;
+ width: 100%;
+ text-align: right;
+ }
+#d_clip_container
+ {
+ display: inline-block;
+ }
+#d_clip_button, #clear
+ {
+ font-family: Lucida Sans Unicode, Lucida Grande, sans-serif;
+ color: #333;
+ font-size: 13px;
+ line-height: 13px;
+ text-align: center;
+ margin: 2px; padding: 5px;
+ display: inline-block;
+ border-top: 1px solid #888;
+ border-left: 1px solid #888;
+ border-right: 1px solid #555;
+ border-bottom: 1px solid #333;
+ background-image: linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -o-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -moz-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -webkit-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -ms-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(235,235,235)), color-stop(0.53, rgb(250,250,250)));
+ }
+#d_clip_button.hover, #clear:hover
+ {
+ color: #555;
+ background-image: linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -o-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -moz-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -webkit-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -ms-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(245,240,245)), color-stop(0.78, rgb(255,255,255)));
+ }
+#d_clip_button.active, #clear:active
+ {
+ color: #111;
+ border-top: 1px solid #333;
+ border-left: 1px solid #555;
+ border-right: 1px solid #555;
+ border-bottom: 1px solid #333;
+ background-image: linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -o-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -moz-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -webkit-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -ms-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(194,194,194)), color-stop(0.53, rgb(235,235,235)));
+ }
+
+.pulsate_and_grow {
+ -webkit-animation: pulsate_and_grow 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+}
+@-webkit-keyframes pulsate_and_grow {
+ 0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.1;}
+ 50% {opacity: 1.0;}
+ 100% {-webkit-transform: scale(1.0, 1.0); opacity: 0.1;}
+}
+.tag-options:active, .tag-clear:active {
+ -webkit-animation: pulsate_opacity 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+
+}
+.sorting-options:active {
+ -webkit-animation: pulsate_opacity 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+
+}
+@-webkit-keyframes pulsate_opacity{
+ 0% { opacity: 0.1;}
+ 50% {opacity: 1.0;}
+ 100% {opacity: 0.1;}
+}
+</style>
+<link href="/im/gallery_style.css" type="text/css" rel="stylesheet" />
+<script type="text/javascript">
+$(function(){
+ $("b").addClass("pulsate_and_grow");
+ $(".sorting-options").click(function(){
+
+ $(".sorting-options").click(function(){
+ console.log("wazzup");
+ if ($(this).hasClass("pulsate_opacity")){
+ $(this).removeClass("pulsate_opacity");
+ }
+ $(this).addClass("pulsate_opacity");
+
+ });
+ });
+});
+
+</script>
+</head>
+<body>
+<div id="help">
+ <b>key controls</b>
+ <div id="keys">
+ <br/>
+ <div class="small"><i>when composer is launched...</i></div>
+ <div>ESC toggle</div>
+ <div>C clear</div>
+ <div>R reverse</div>
+ <br/>
+ <div class="small"><i>in the gallery...</i></div>
+ <div>BACKSPACE delete</div>
+ <div>LEFT ARROW newer</div>
+ <div>RIGHT ARROW older</div>
+ </div>
+</div>
+<div id="actions">
+ <b>sort</b>
+ <div id="sorting-optionsContainer">
+ <div class="sorting-options" id="date">date</div>
+ <div class="sorting-options" id="username">username</div>
+ <div class="sorting-options" id="height">height</div>
+ <div class="sorting-options" id="width">width</div>
+ <div class="sorting-options" id="gif">gif</div>
+ <div class="sorting-options" id="shuffle">shuffle</div>
+ <div class="sorting-options" id="lombada">lombada</div>
+ </div>
+</div>
+<div id="tags">
+ <b>tags</b>
+ <div id="tag-optionsContainer">
+
+
+ <div class="tag-clear" ><i>remove tag</i></div>
+ <div class="tag-options" id="transparent">transparent</div>
+ <div class="tag-options" id="break">break</div>
+ <div class="tag-options" id="gradient">gradient</div>
+ <div class="tag-options" id="grid">grid</div>
+ <div class="tag-options" id="shader">shader</div>
+ <div class="tag-options" id="Over">Over</div>
+ <div class="tag-options" id="ATop">ATop</div>
+ <div class="tag-options" id="Dst_Over">Dst_Over</div>
+ <div class="tag-options" id="Dst_In">Dst_In</div>
+ <div class="tag-options" id="Dst_Out">Dst_Out</div>
+ <div class="tag-options" id="Multiply">Multiply</div>
+ <div class="tag-options" id="Screen">Screen</div>
+ <div class="tag-options" id="Divide">Divide</div>
+ <div class="tag-options" id="Plus">Plus</div>
+ <div class="tag-options" id="Difference">Difference</div>
+ <div class="tag-options" id="Exclusion">Exclusion</div>
+ <div class="tag-options" id="Lighten">Lighten</div>
+ <div class="tag-options" id="Darken">Darken</div>
+ <div class="tag-options" id="Overlay">Overlay</div>
+ <div class="tag-options" id="Hard_Light">Hard_Light</div>
+ <div class="tag-options" id="Soft_Light">Soft_Light</div>
+ <div class="tag-options" id="Pegtop_Light">Pegtop_Light</div>
+ <div class="tag-options" id="Linear_Light">Linear_Light</div>
+ <div class="tag-options" id="Vivid_Light">Vivid_Light</div>
+ <div class="tag-options" id="Pin_Light">Pin_Light</div>
+ <div class="tag-options" id="Linear_Dodge">Linear_Dodge</div>
+ <div class="tag-options" id="Linear_Burn">Linear_Burn</div>
+ <div class="tag-options" id="Color_Dodge">Color_Dodge</div>
+ <div class="tag-options" id="Color_Burn">Color_Burn</div>
+
+ </div>
+</div>
+<div id="dump">
+ <div id="rebus"></div>
+ <input id="urlz" type="text" />
+ <div id="d_clip_container" style="position:relative">
+ <div id="d_clip_button">copy</div>
+ </div>
+ <button id="clear">clear</button>
+</div>
+<div id="images">
+"""
+
+
+previous_id = lowest_id + (SQL_LIMIT * 2)
+back = ["start=%d" % lowest_id, "limit=%d" % SQL_LIMIT]
+newer = ["start=%d" % previous_id, "limit=%d" % SQL_LIMIT]
+random_time = ""
+if params['name'] is not None:
+ back.append("name=%s" % params['name'])
+ newer.append("name=%s" % params['name'])
+ random_time = "name=%s" % params['name']
+if params['tag'] is not None:
+ back.append("tag=%s" % params['tag'])
+ newer.append("tag=%s" % params['tag'])
+ random_time = "tag=%s" % params['tag']
+
+newer_QS = "&".join(newer)
+back_QS = "&".join(back)
+random_time_QS = "";
+if random_time:
+ random_time_QS = "&%s" % random_time;
+print "<div id='nextpage'>"
+print "<a href='/im/'>editor</a>"
+print "|"
+print "<a href='?%s'>&larr; newer</a>" % newer_QS;
+print "|"
+if params['random'] is not None and params['random'] == '1':
+ print "<a href='?random=%d%s'>random</a>" % (random.randint(1,2**63), random_time_QS);
+else:
+ print "<a href='?random=%d%s'>random</a>" % (1, random_time_QS);
+print "|"
+print "<a href='?%s'>older &rarr;</a>" % back_QS;
+print "</div>"
+print """
+</body>
+<script type="text/javascript" src="/js/ZeroClipboard.js"></script>
+<script type="text/javascript" src="http://asdf.us/js/pbembed.js"></script>
+<script type="text/javascript">
+ZeroClipboard.setMoviePath( 'http://asdf.us/swf/ZeroClipboard10.swf' );
+var clip = new ZeroClipboard.Client();
+clip.glue( 'd_clip_button' );
+var Dump =
+ {
+ pick: function ()
+ {
+ Dump.pickUrl( $(this).attr("src") )
+ },
+ pickUrl: function (url)
+ {
+ $("#rebus").append ($ ("<img>").attr ("src", url))
+ $("#rebus").show()
+ var theDump = $("#urlz").val() + " " + url
+ $("#urlz").val( theDump )
+ clip.setText( theDump )
+ return false
+ },
+ clear: function ()
+ {
+ $("#rebus").html("")
+ $("#urlz").val("")
+ clip.setText("")
+ },
+ backspace: function ()
+ {
+ $("#rebus img:last").remove()
+ var urllist = $("#urlz").val().split(" ")
+ urllist.pop()
+ $("#urlz").val( urllist.join(" ") )
+ },
+ reverse: function ()
+ {
+ urllist = $("#urlz").val().split(" ")
+ Dump.clear()
+ for (i in urllist.reverse())
+ if (urllist[i])
+ Dump.pickUrl(urllist[i])
+ },
+ showNewer: function()
+ {
+ window.location.href = '?"""+newer_QS+"""'
+ },
+ showOlder: function()
+ {
+ window.location.href = '?"""+back_QS+"""'
+ }
+ }
+function applyTag(tagname){
+ tag_regex = /&tag=[^&]*/;
+ if (document.URL.match(tag_regex)){
+ return document.URL.replace(tag_regex, "&tag="+tagname);
+ }else if(document.URL.match(/\/$/)){
+ return document.URL.replace(/\/$/, "?tag="+tagname);
+ }
+ else{
+ return document.URL+"&tag="+tagname;
+ }
+}
+var Main =
+ {
+ editing: false,
+ kp: function (event)
+ {
+ console.log(event.keyCode);
+ switch (event.keyCode)
+ {
+ // BS
+ case 8:
+ if (! Main.editing)
+ Dump.backspace()
+ return false
+ // C
+ case 67:
+ if (! Main.editing)
+ Dump.clear()
+ break
+ // R
+ case 82:
+ if (! Main.editing)
+ Dump.reverse()
+ break
+ // ESC
+ case 27:
+ // H
+ case 72:
+ if (! Main.editing)
+ $("#rebus").toggle()
+ break
+ // LEFT ARROW
+ case 37:
+ if (! Main.editing)
+ Dump.showNewer()
+ break
+ // RIGHT ARROW
+ case 39:
+ if (! Main.editing)
+ Dump.showOlder()
+ break
+ }
+ return true
+ },
+ poll: function ()
+ {
+ },
+ pollCallback: function ()
+ {
+ },
+ init: function ()
+ {
+ $(document).keydown(Main.kp)
+ $("#urlz").focus(function(){ Main.editing = true })
+ $("#urlz").blur(function(){ Main.editing = false })
+ $("#clear").live("click", Dump.clear)
+ $("#help").click(function(){ $("#keys").slideToggle() })
+ $("#actions b").click(function(){ $("#sorting-optionsContainer").slideToggle() })
+ $("#tags b").click(function(){ $("#tag-optionsContainer").slideToggle() })
+ $(".tag-options").click(function(){document.location.href= applyTag(this.id)});
+ $(".tag-clear").click(function(){ document.location.href = document.URL.replace(/&?tag=[^&]*/ ,"").replace(/\?$/,"")});
+ $("div img").live("click", Dump.pick)
+ Dump.clear()
+ }
+ }
+"""
+if params['interface'] is not None and params['interface'] == "off":
+ print """
+$("#nextpage,#help,#dump").hide()
+$("body").css({"margin": 0, "padding": 0, "overflow": hidden, "background-color": white})
+"""
+else:
+ print "Main.init()"
+print """
+</script>
+</html>
+"""
+
diff --git a/htmljs/gallery/gallery_main.css b/htmljs/gallery/gallery_main.css
new file mode 100644
index 0000000..3f06b19
--- /dev/null
+++ b/htmljs/gallery/gallery_main.css
@@ -0,0 +1,245 @@
+body
+ {
+ background-color: #eee;
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.32, rgb(245,238,235)), color-stop(0.66, rgb(252,252,252)));
+ background-image: -moz-linear-gradient( center bottom, rgb(245,238,235) 32%, rgb(252,252,252) 66%); overflow-y: scroll;
+ }
+html
+ {
+ padding-bottom: 200px;
+ }
+#images
+ {
+ width: 100%;
+ margin-top:70px;
+ }
+#images div
+ {
+ width: 200px;
+ display: inline-block;
+ }
+div img
+ {
+ max-width: 200px;
+ max-height: 200px;
+ border: 0;
+ }
+#images img
+ {
+ cursor: pointer;
+ display: none;
+ }
+#dump
+ {
+ position: fixed;
+ left: 0;
+ bottom: 10px;
+ padding: 10px;
+ width: 100%;
+ border-bottom: 2px solid #000;
+ background-color: #f8f8f8;
+ border-top: 1px solid #888;
+ z-index: 1000;
+ }
+#dump #rebus
+ {
+ clear: right;
+ width: 90%;
+ max-height: 700px;
+ overflow-y: scroll;
+ background-color: #fff;
+ padding-bottom: 5px;
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 5px;
+ }
+#dump #rebus img
+ {
+ cursor: pointer;
+ display: inline;
+ max-width: 400px;
+ max-height: 400px;
+ margin-right: -4px;
+ }
+#dump #urlz
+ {
+ width: 90%;
+ font-size: 15px;
+ }
+#actions
+ {
+ position: fixed;
+ top: 10px;
+ left: 10px;
+ cursor: pointer;
+ text-align: left;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#tags
+ {
+ position: fixed;
+ top: 10px;
+ left: 200px;
+ cursor: pointer;
+ text-align: left;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#help
+ {
+ position: fixed;
+ top: 10px;
+ right: 10px;
+ cursor: pointer;
+ text-align: right;
+ font-family: sans-serif;
+ z-index:1000;
+ }
+#help b {
+ text-align: right;
+}
+#help div{
+ background: rgba(200,200,200,0.8);
+}
+#keys div{
+ background: none;
+}
+#help .small{
+ font-size: 11px;
+}
+#help b, #actions b, #tags b
+ {
+ padding: 5px;
+ background-color: #f8f4fb;
+ display: block;
+ max-width: 160px;
+ }
+#help b:hover, #actions b:hover, #tags b:hover
+ {
+ color: cyan;
+
+ }
+#help #keys, #sorting-optionsContainer, #tag-optionsContainer
+ {
+ clear: both;
+ padding: 5px;
+ display: none;
+ min-width: 120px;
+ font-size: 14px;
+ }
+.sorting-options, .tag-options {
+ color:black;
+ cursor: pointer;
+ background: rgba(200,200,200,0.8);
+}
+.tag-clear{
+ color:#333;
+ cursor: pointer;
+ background: rgba(200,200,200,0.8);
+
+}
+.sorting-optionsContainer div:hover{
+ color: red;
+}
+.tag-optionsContainer div:hover{
+ color: pink;
+}
+.sorting-options:hover, .tag-options:hover, .tag-clear:hover {
+background: gold;
+}
+#nextpage
+ {
+ position: fixed;
+ right: 190px;
+ font-family: sans-serif;
+ top: 10px;
+ padding: 5px;
+ background-color: rgba(255,255,255,0.7);
+ z-index:9999
+ }
+#nextpage a
+ {
+ color: #33f;
+ }
+.rtlink
+ {
+ display: block;
+ width: 100%;
+ text-align: right;
+ }
+#d_clip_container
+ {
+ display: inline-block;
+ }
+#d_clip_button, #clear
+ {
+ font-family: Lucida Sans Unicode, Lucida Grande, sans-serif;
+ color: #333;
+ font-size: 13px;
+ line-height: 13px;
+ text-align: center;
+ margin: 2px; padding: 5px;
+ display: inline-block;
+ border-top: 1px solid #888;
+ border-left: 1px solid #888;
+ border-right: 1px solid #555;
+ border-bottom: 1px solid #333;
+ background-image: linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -o-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -moz-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -webkit-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -ms-linear-gradient(bottom, rgb(235,235,235) 0%, rgb(250,250,250) 53%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(235,235,235)), color-stop(0.53, rgb(250,250,250)));
+ }
+#d_clip_button.hover, #clear:hover
+ {
+ color: #555;
+ background-image: linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -o-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -moz-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -webkit-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -ms-linear-gradient(bottom, rgb(245,240,245) 0%, rgb(255,255,255) 78%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(245,240,245)), color-stop(0.78, rgb(255,255,255)));
+ }
+#d_clip_button.active, #clear:active
+ {
+ color: #111;
+ border-top: 1px solid #333;
+ border-left: 1px solid #555;
+ border-right: 1px solid #555;
+ border-bottom: 1px solid #333;
+ background-image: linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -o-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -moz-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -webkit-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -ms-linear-gradient(bottom, rgb(194,194,194) 0%, rgb(235,235,235) 53%);
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(194,194,194)), color-stop(0.53, rgb(235,235,235)));
+ }
+
+.pulsate_and_grow {
+ -webkit-animation: pulsate_and_grow 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+}
+@-webkit-keyframes pulsate_and_grow {
+ 0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.1;}
+ 50% {opacity: 1.0;}
+ 100% {-webkit-transform: scale(1.0, 1.0); opacity: 0.1;}
+}
+.tag-options:active, .tag-clear:active {
+ -webkit-animation: pulsate_opacity 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+
+}
+.sorting-options:active {
+ -webkit-animation: pulsate_opacity 0.5s ease-out;
+ -webkit-animation-iteration-count: 3;
+ opacity: 1.0;
+
+}
+@-webkit-keyframes pulsate_opacity{
+ 0% { opacity: 0.1;}
+ 50% {opacity: 1.0;}
+ 100% {opacity: 0.1;}
+}
diff --git a/htmljs/gallery/gallery_main.js b/htmljs/gallery/gallery_main.js
new file mode 100644
index 0000000..dedc9eb
--- /dev/null
+++ b/htmljs/gallery/gallery_main.js
@@ -0,0 +1,156 @@
+var imagedata = [ ]; //FIXME post request here
+$(function(){
+ for (var i=0; i< (imagedata.length - 1); i++){
+ var newDiv = document.createElement("div");
+ var newImage = document.createElement("img");
+ newImage.src = imagedata[i][0];
+ newImage.className = "pb";
+ newDiv.appendChild(newImage);
+// consider calling something like isotope add here...and ONLY APPENDING the image to the parent div once it has loaded
+// $(newImage).load(function(){
+// console.log("like a true playa");
+// })
+ $("#images").append(newDiv);
+ }
+});
+
+$(function(){
+ $("b").addClass("pulsate_and_grow");
+ $(".sorting-options").click(function(){
+
+ $(".sorting-options").click(function(){
+ console.log("wazzup");
+ if ($(this).hasClass("pulsate_opacity")){
+ $(this).removeClass("pulsate_opacity");
+ }
+ $(this).addClass("pulsate_opacity");
+
+ });
+ });
+});
+$(function(){
+ZeroClipboard.setMoviePath( 'http://asdf.us/swf/ZeroClipboard10.swf' );
+var clip = new ZeroClipboard.Client();
+clip.glue( 'd_clip_button' );
+var Dump =
+ {
+ pick: function ()
+ {
+ Dump.pickUrl( $(this).attr("src") )
+ },
+ pickUrl: function (url)
+ {
+ $("#rebus").append ($ ("<img>").attr ("src", url))
+ $("#rebus").show()
+ var theDump = $("#urlz").val() + " " + url
+ $("#urlz").val( theDump )
+ clip.setText( theDump )
+ return false
+ },
+ clear: function ()
+ {
+ $("#rebus").html("")
+ $("#urlz").val("")
+ clip.setText("")
+ },
+ backspace: function ()
+ {
+ $("#rebus img:last").remove()
+ var urllist = $("#urlz").val().split(" ")
+ urllist.pop()
+ $("#urlz").val( urllist.join(" ") )
+ },
+ reverse: function ()
+ {
+ urllist = $("#urlz").val().split(" ")
+ Dump.clear()
+ for (i in urllist.reverse())
+ if (urllist[i])
+ Dump.pickUrl(urllist[i])
+ },
+ showNewer: function()
+ {
+ window.location.href = //FIXME
+ },
+ showOlder: function()
+ {
+ window.location.href = //FIXME
+ }
+ }
+function applyTag(tagname){
+ tag_regex = /&tag=[^&]*/;
+ if (document.URL.match(tag_regex)){
+ return document.URL.replace(tag_regex, "&tag="+tagname);
+ }else if(document.URL.match(/\/$/)){
+ return document.URL.replace(/\/$/, "?tag="+tagname);
+ }
+ else{
+ return document.URL+"&tag="+tagname;
+ }
+}
+var Main =
+ {
+ editing: false,
+ kp: function (event)
+ {
+ console.log(event.keyCode);
+ switch (event.keyCode)
+ {
+ // BS
+ case 8:
+ if (! Main.editing)
+ Dump.backspace()
+ return false
+ // C
+ case 67:
+ if (! Main.editing)
+ Dump.clear()
+ break
+ // R
+ case 82:
+ if (! Main.editing)
+ Dump.reverse()
+ break
+ // ESC
+ case 27:
+ // H
+ case 72:
+ if (! Main.editing)
+ $("#rebus").toggle()
+ break
+ // LEFT ARROW
+ case 37:
+ if (! Main.editing)
+ Dump.showNewer()
+ break
+ // RIGHT ARROW
+ case 39:
+ if (! Main.editing)
+ Dump.showOlder()
+ break
+ }
+ return true
+ },
+ poll: function ()
+ {
+ },
+ pollCallback: function ()
+ {
+ },
+ init: function ()
+ {
+ $(document).keydown(Main.kp)
+ $("#urlz").focus(function(){ Main.editing = true })
+ $("#urlz").blur(function(){ Main.editing = false })
+ $("#clear").live("click", Dump.clear)
+ $("#help").click(function(){ $("#keys").slideToggle() })
+ $("#actions b").click(function(){ $("#sorting-optionsContainer").slideToggle() })
+ $("#tags b").click(function(){ $("#tag-optionsContainer").slideToggle() })
+ $(".tag-options").click(function(){document.location.href= applyTag(this.id)});
+ $(".tag-clear").click(function(){ document.location.href = document.URL.replace(/&?tag=[^&]*/ ,"").replace(/\?$/,"")});
+ $("div img").live("click", Dump.pick)
+ Dump.clear()
+ }
+ }
+ Main.init()
+})
diff --git a/htmljs/gallery/index.html b/htmljs/gallery/index.html
new file mode 100644
index 0000000..5cbc43f
--- /dev/null
+++ b/htmljs/gallery/index.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<title>PHOTOBLASTER GALLERY</title>
+<script type="text/javascript" src="/js/jquery.js"></script>
+<script type="text/javascript" src="/js/titleScrambler.js"></script>
+<script type="text/javascript" src="/js/gallery_main.js"> </script>
+<script type="text/javascript" src="/js/jquery.isotope.min.js"></script>
+<script type="text/javascript" src="/js/gallery_isotope_config.js?v=3"></script>
+<link href="/im/gallery_main.css" type="text/css" rel="stylesheet" />
+<link href="/im/gallery_style.css" type="text/css" rel="stylesheet" />
+</head>
+<body>
+<div id="help">
+ <b>key controls</b>
+ <div id="keys">
+ <br/>
+ <div class="small"><i>when composer is launched...</i></div>
+ <div>ESC toggle</div>
+ <div>C clear</div>
+ <div>R reverse</div>
+ <br/>
+ <div class="small"><i>in the gallery...</i></div>
+ <div>BACKSPACE delete</div>
+ <div>LEFT ARROW newer</div>
+ <div>RIGHT ARROW older</div>
+ </div>
+</div>
+<div id="actions">
+ <b>sort</b>
+ <div id="sorting-optionsContainer">
+ <div class="sorting-options" id="date">date</div>
+ <div class="sorting-options" id="username">username</div>
+ <div class="sorting-options" id="height">height</div>
+ <div class="sorting-options" id="width">width</div>
+ <div class="sorting-options" id="gif">gif</div>
+ <div class="sorting-options" id="shuffle">shuffle</div>
+ <div class="sorting-options" id="lombada">lombada</div>
+ </div>
+</div>
+<div id="tags">
+ <b>tags</b>
+ <div id="tag-optionsContainer">
+
+
+ <div class="tag-clear" ><i>remove tag</i></div>
+ <div class="tag-options" id="transparent">transparent</div>
+ <div class="tag-options" id="break">break</div>
+ <div class="tag-options" id="gradient">gradient</div>
+ <div class="tag-options" id="grid">grid</div>
+ <div class="tag-options" id="shader">shader</div>
+ <div class="tag-options" id="Over">Over</div>
+ <div class="tag-options" id="ATop">ATop</div>
+ <div class="tag-options" id="Dst_Over">Dst_Over</div>
+ <div class="tag-options" id="Dst_In">Dst_In</div>
+ <div class="tag-options" id="Dst_Out">Dst_Out</div>
+ <div class="tag-options" id="Multiply">Multiply</div>
+ <div class="tag-options" id="Screen">Screen</div>
+ <div class="tag-options" id="Divide">Divide</div>
+ <div class="tag-options" id="Plus">Plus</div>
+ <div class="tag-options" id="Difference">Difference</div>
+ <div class="tag-options" id="Exclusion">Exclusion</div>
+ <div class="tag-options" id="Lighten">Lighten</div>
+ <div class="tag-options" id="Darken">Darken</div>
+ <div class="tag-options" id="Overlay">Overlay</div>
+ <div class="tag-options" id="Hard_Light">Hard_Light</div>
+ <div class="tag-options" id="Soft_Light">Soft_Light</div>
+ <div class="tag-options" id="Pegtop_Light">Pegtop_Light</div>
+ <div class="tag-options" id="Linear_Light">Linear_Light</div>
+ <div class="tag-options" id="Vivid_Light">Vivid_Light</div>
+ <div class="tag-options" id="Pin_Light">Pin_Light</div>
+ <div class="tag-options" id="Linear_Dodge">Linear_Dodge</div>
+ <div class="tag-options" id="Linear_Burn">Linear_Burn</div>
+ <div class="tag-options" id="Color_Dodge">Color_Dodge</div>
+ <div class="tag-options" id="Color_Burn">Color_Burn</div>
+
+ </div>
+</div>
+<div id="dump">
+ <div id="rebus"></div>
+ <input id="urlz" type="text" />
+ <div id="d_clip_container" style="position:relative">
+ <div id="d_clip_button">copy</div>
+ </div>
+ <button id="clear">clear</button>
+</div>
+<div id="images">
+<div id='nextpage'>
+ <a href='/im/'>editor</a>
+ <a href='?%s'>&larr; newer</a>
+ <a href='?random=%d%s'>random</a>
+ <a href='?%s'>older &rarr;</a>
+</div>
+</body>
+<script type="text/javascript" src="/js/ZeroClipboard.js"></script>
+<script type="text/javascript" src="http://asdf.us/js/pbembed.js"></script>
+</html>
diff --git a/install/database/database_create_statements b/install/database/database_create_statements
new file mode 100644
index 0000000..9fa9e39
--- /dev/null
+++ b/install/database/database_create_statements
@@ -0,0 +1,3 @@
+create database if not exists asdfus;
+grant all privileges on asdfus.* to asdfus@localhost identified by 'gTYgT&M6q';
+flush privileges;
diff --git a/install/database/database_schema.sql b/install/database/database_schema.sql
new file mode 100644
index 0000000..802aa49
--- /dev/null
+++ b/install/database/database_schema.sql
@@ -0,0 +1,15 @@
+CREATE TABLE if not exists `im_cmd` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `date` int(11) DEFAULT NULL,
+ `remote_addr` varchar(16) DEFAULT NULL,
+ `name` varchar(16) DEFAULT NULL,
+ `url` varchar(256) DEFAULT NULL,
+ `dir` varchar(2) DEFAULT NULL,
+ `oldfile` varchar(256) DEFAULT NULL,
+ `newfile` varchar(256) DEFAULT NULL,
+ `cmd` blob,
+ `dataobj` blob,
+ `tag` varchar(50) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM AUTO_INCREMENT=386739 DEFAULT CHARSET=utf8;
+
diff --git a/pb/Breaker/__init__.py b/pb/Breaker/__init__.py
new file mode 100755
index 0000000..9f5d31b
--- /dev/null
+++ b/pb/Breaker/__init__.py
@@ -0,0 +1,268 @@
+#!/usr/bin/python2.7
+import os
+import sys
+import random
+import re
+import pb.lib.Utils as utils
+import urllib
+from pb.Config import *
+
+DEFAULT_FINALFORMAT = "png";
+SUBTLE_BREAK_MARK = 'pron'
+EXTREME_BREAK_MARK = 'sugar'
+
+HEADER_OFFSET = 2000
+
+# 'CLASSIC':'jpg',
+# 'REDUX':'pcds',
+# 'BLURRY_BREAK':'viff',
+# 'BLURRY_BREAK_2':'mat',
+# 'SWIPE':'miff',
+# 'RGB_WASH':'psd',
+# 'RGB_WASH_2':'psb',
+# 'NOISY_BREAK':'palm',
+# 'NOISY_BREAK_2':'fig',
+# 'BROKEN_VIGNETTE':'pbm',
+# 'FAX_MACHINE':'cals',
+# 'STRIPES':'exr',
+# 'PHOTOCOPY':'art',
+
+class Breaker():
+ def __init__(self, **kwargs):
+ self.params = {}
+ self.tag = "imBreak"
+ self.commands = [];
+ self._required_keys = [
+ "url",
+ "breaktype",
+ "finalformat",
+ "breakmode",
+ "breakangle",
+ "username",
+ "expanded"
+ ]
+ self.now = utils.now()
+ self.files_created = []
+ for k in self._required_keys:
+ if k in kwargs:
+ if k == 'breaktype':
+ self.params['breaktype'] = self._get_breaktype(kwargs[k])
+ elif k == 'url':
+ self.params[k] = kwargs[k]
+ else:
+ self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k]))
+ else:
+ self.params[k] = False;
+
+
+ self.params = utils.dotdict(self.params)
+
+ self.basename, self._first_format = self._get_filename();
+ self._downloaded_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self._first_format)) # same here
+
+ try:
+ utils.download(self.params.url, self._downloaded_file)
+ self.files_created.append(self._downloaded_file)
+ except Exception as e:
+ sys.stderr.write(str(e))
+ raise;
+ self._gif_frames = utils.gif_frames(self._downloaded_file)
+ self._gif_frames = self._gif_frames if len(self._gif_frames) > 1 else False
+ self.width, self.height = utils.dimensions(self._downloaded_file) # same here
+
+ if not self.params.finalformat:
+ self.params.finalformat = DEFAULT_FINALFORMAT
+ if self._gif_frames:
+ self.params.finalformat = 'gif'
+ if self.params.breaktype == 'miff':
+ self.params.finalformat = 'jpg'
+ self.params.breakmode = 'subtle'
+ #final filepath is stored in self.filepath
+ self.filename = "{}.{}".format(self.basename, self.params.finalformat)
+ self.filepath = os.path.join(WORKING_DIR, self.filename)
+ self._conversion_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self.params.breaktype)) # this
+
+
+ def _call_cmd(self, cmd, error=""):
+ try:
+ utils.call_cmd(cmd)
+ self.commands.append(" ".join(cmd));
+ except Exception:
+ raise Exception("Unable to call cmd {}".format(str(cmd)))
+
+ def _get_breaktype(self, key):
+ #{{{ conversion table
+ breaktypeTranslate = {
+ 'CLASSIC':'jpg',
+ 'REDUX':'pcds',
+ 'BLURRY_BREAK':'viff',
+ 'BLURRY_BREAK_2':'mat',
+ 'SWIPE':'miff',
+ 'RGB_WASH':'psd',
+ 'RGB_WASH_2':'psb',
+ 'NOISY_BREAK':'palm',
+ 'NOISY_BREAK_2':'fig',
+ 'BROKEN_VIGNETTE':'pbm',
+ 'FAX_MACHINE':'cals',
+ 'STRIPES':'exr',
+ 'PHOTOCOPY':'art',
+ }
+ #}}}
+ return breaktypeTranslate[key]
+
+ def _get_filename (self):
+ url = self.params.url
+ name_part = "";
+ file_format = "";
+ if "?" in url:
+ url = url.split("?")[0]
+ if "/" in url:
+ url = urllib.unquote(url).replace(" ","")
+ name_part = url.split("/")[-1]
+ try:
+ parts = name_part.split(".")
+ name_part = utils.sanitize(parts[-2])
+ file_format = utils.sanitize(parts[-1])
+ if not name_part or not file_format:
+ sys.stderr.write( "Incompatible input file type")
+ raise;
+ except Exception as e:
+ sys.stderr.write( "Incompatible input file type")
+ raise;
+ else:
+ sys.stderr.write( "Incompatible url")
+ raise;
+ if (len(name_part) > 20):
+ name_part = name_part[:-20]
+ return "{}{}_{}_{}".format(self.tag, name_part, self.now, self.params.username or ""), file_format
+
+#{{{#########rotatefunctions#######################################
+ def _rotate(self):
+ cmd = [BIN_CONVERT,self._downloaded_file,"-rotate",self.params.breakangle,"+repage",self._downloaded_file]
+ self._call_cmd(cmd)
+
+ def _rotate_back(self):
+ angle = str(360-int(self.params.breakangle))
+ cmd = [BIN_CONVERT,self.filepath,"-rotate",angle,"+repage",self.filepath]
+ self._call_cmd(cmd)
+ if not self.params.expanded:
+ cmd = [BIN_CONVERT,self.filepath,"-gravity","Center","-crop","{}x{}+0+0".format(
+ self.width, self.height),"+repage",self.filepath]
+ self._call_cmd(cmd)
+#}}}
+ def _subtle_break(self):
+ #assume the header is no longer than HEADER_OFFSET bytes
+ breakpoint = random.randint(HEADER_OFFSET, len(self.file_data))
+ newfile = ""
+ newfile = self.file_data[0:breakpoint];
+ newfile += SUBTLE_BREAK_MARK;
+ newfile += self.file_data[breakpoint:]
+ self.file_data = newfile[0:len(self.file_data)]
+
+ def _extreme_break(self):
+ increment = len(self.file_data)/10;
+ i = 0
+ newfile = "";
+ for b in self.file_data:
+ if i > HEADER_OFFSET and not (i % increment):
+ b += EXTREME_BREAK_MARK
+ newfile += b
+ i += 1
+ self.file_data = newfile[0:len(self.file_data)]
+
+ def _choose_frame(self):
+ frame = random.choice(self._gif_frames)
+ cmd = [BIN_CONVERT, frame, self._downloaded_file]
+ self._call_cmd(cmd)
+
+ def _enforce_jpg(self):
+ if self.params.breaktype in [ "exr", "bmp", "miff" ] and not re.match(r'jpe?g', self._first_format, re.IGNORECASE):
+ jpg_file = os.path.join(WORKING_DIR, "{}.{}".format(self.basename, "jpg"))
+ cmd = [BIN_CONVERT,self._downloaded_file,jpg_file]
+ self._call_cmd(cmd)
+ cmd = ["rm",self._downloaded_file]
+ self._call_cmd(cmd)
+
+
+ def _first_conversion(self):
+ if self._first_format == self.params.breaktype:
+ self._downloaded_file = self._conversion_file
+ return
+ cmd = [BIN_CONVERT, self._downloaded_file, self._conversion_file]
+ self._call_cmd(cmd)
+ self.files_created.append(self._conversion_file)
+
+ def _read_data(self, filepath):
+ f = open(filepath, 'r');
+ data = f.read()
+ f.close()
+ return data
+
+ def _prepare_filedata(self):
+ if self._gif_frames:
+ self._choose_frame()
+ if self.params.breakangle:
+ self._rotate()
+ self._enforce_jpg();
+ self._first_conversion();
+ self.file_data = self._read_data(self._conversion_file)
+ if not self.file_data:
+ sys.stderr.write("Unable to get file_data")
+ raise;
+
+ def _add_false_data(self, breakmode):
+ if breakmode == "subtle":
+ self._subtle_break()
+ elif breakmode == "extreme":
+ self._extreme_break()
+ f = open(self._conversion_file, 'w')
+ f.write(self.file_data)
+ f.close();
+
+#{{{ SHRINK (UNUSED)
+ def _shrink(self):
+ cmd = [ BIN_CONVERT, "-resize", "500x500", self._downloaded_file, self._downloaded_file ];
+ self._call_cmd(cmd)
+#}}}
+
+ def _final_conversion(self):
+ cmd = [BIN_CONVERT, self._conversion_file, self.filepath]
+ self._call_cmd(cmd)
+ def psd_psbfilepath(num):
+ return os.path.join(WORKING_DIR, "{}-{}.{}".format(self.basename, num, self.params.finalformat))
+ if self.params.breaktype == 'psd':
+ cmd = ['mv', psd_psbfilepath(1), self.filepath]
+ self._call_cmd(cmd)
+ self.files_created.append(psd_psbfilepath(0))
+ if self.params.breaktype == 'psb':
+ cmd = ['mv', psd_psbfilepath(0), self.filepath]
+ self._call_cmd(cmd)
+ self.files_created.append(psd_psbfilepath(1))
+
+ if self.params.breakangle:
+ self._rotate_back()
+
+ def _cleanup(self):
+ cmd = ["rm"]+self.files_created
+ self._call_cmd(cmd)
+
+ def create(self, breakmode=""):
+ if not breakmode: breakmode = self.params.breakmode
+ self._prepare_filedata();
+ self._add_false_data(breakmode);
+ self._final_conversion()
+ self._cleanup()
+
+if __name__ == "__main__":
+ TEST_PARAMS = {
+ "url" : "http://i.asdf.us/im/27/1424816234661dumpfmpfifferkinggr_1424816412_pfifferking.gif" ,
+ "breaktype" : "RGB_WASH",
+ "finalformat" : "png",
+ "breakmode" : "extreme",
+ "breakangle" : "10",
+ "username" : "donkey",
+ "expanded" : "false"
+ }
+ b = Breaker(**TEST_PARAMS)
+ b.create();
+ print b.filepath
diff --git a/pb/Config/__init__.py b/pb/Config/__init__.py
new file mode 100644
index 0000000..b849b9e
--- /dev/null
+++ b/pb/Config/__init__.py
@@ -0,0 +1,20 @@
+MAX_SIZE = 1024 * 1024 * 1.2 * 1.5
+
+#PATHS
+BIN_CONVERT = "/usr/bin/convert"
+BIN_COMPOSITE = "/usr/bin/composite"
+BIN_IDENTIFY = "/usr/bin/identify"
+THREEDROTATE = "./bin/3Drotate"
+GRID = "./bin/grid"
+BEVELBORDER = "./bin/bevelborder"
+
+DEFAULT_FINALFORMAT = "png";
+
+
+#mounted on tmpfs
+WORKING_DIR = "/var/www/cache"
+
+#s3
+AWS_ACCESS_KEY_ID = 'AKIAIR53VPBXKJMXZIBA'
+AWS_SECRET_ACCESS_KEY = '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'
+BUCKET_NAME = 'i.asdf.us'
diff --git a/pb/Generate/__init__.py b/pb/Generate/__init__.py
new file mode 100755
index 0000000..fbb74e3
--- /dev/null
+++ b/pb/Generate/__init__.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python2.7
+import sys
+import os
+
+from pb.Config import *
+import pb.lib.Utils as utils
+
+#FIXME these guys can do stuff wider than 1000
+LIKE_A_BOSS = "ryz pepper seamonkey JAMES".split(" ")
+DEFAULT_FINALFORMAT = "gif"
+DEFAULT_TAG = "im";
+
+GRAVITY_PARAMS = ["NorthWest","North","NorthEast","West","Center","East","SouthWest","South","SouthEast"]
+GRAVITY_DEFAULT = "Center"
+FORMAT_PARAMS = ["jpg", "gif", "png"]
+COMPOSE_PARAMS = [ "Over", "ATop", "Dst_Over", "Dst_In", "Dst_Out", "Multiply",
+ "Screen", "Divide", "Plus", "Difference", "Exclusion",
+ "Lighten", "Darken", "Overlay", "Hard_Light", "Soft_Light",
+ "Linear_Dodge", "Linear_Burn", "Color_Dodge", "Color_Burn" ]
+DISPOSE_PARAMS = ["None","Previous","Background"]
+DISPOSE_DEFAULT = "None"
+
+def debuglog(s):
+ sys.stderr.write(str(s) + "\n");
+
+class Generate():
+ def __init__(self, **kwargs):
+ self.params = {}
+ self.now = utils.now()
+ self.files_created = []
+ self.commands = [];
+ self._required_keys = [
+#{{{ required_keys
+ #IMAGES
+ "url",
+ "background",
+
+ #BOOLS
+ "coalesce",
+ "dispose",
+ "nearest",
+ "merge_early",
+ "flip",
+ "flop",
+ "tile",
+ "transparent",
+
+ #COLORS
+ "black",
+ "white",
+ "subtract",
+
+ #INTS
+ "fuzz",
+ "width",
+ "height",
+ "brightness",
+ "contrast",
+ "saturation",
+ "rotate",
+ "hue",
+
+ #ENUMS
+ "compose",
+ "gravity",
+ "format",
+
+ #STRINGS
+ "username",
+ "callback",
+#}}}
+ ]
+ for k in self._required_keys:
+ if k in kwargs:
+ if k in [ 'url', 'background' ] and kwargs[k] != "" and kwargs[k] != None:
+ self.params[k] = {
+ 'url' : kwargs[k],
+ 'filename' : self._make_tempname(k),
+ 'path' : os.path.join(WORKING_DIR, self._make_tempname(k)) ,
+ }
+ try:
+ utils.download(self.params[k]['url'], self.params[k]['path'])
+ self.files_created.append(self.params[k]['path'])
+ self.params[k]['mimetype'] = utils.get_mimetype(self.params[k]['path'])
+ except Exception as e:
+ sys.stderr.write(str(e))
+ raise Exception ("BAD PARAMS");
+ elif k in [ 'black', 'white', 'subtract' ]:
+ try:
+ self.params[k] = utils.is_color(kwargs[k])
+ except Exception:
+ raise Exception("Unable to process color for:\n{}".format(k))
+ elif k in [
+ "coalesce", "dispose", "nearest", "merge_early",
+ "flip", "flop", "tile", "transparent",
+ ]:
+ self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k]))
+ elif k == 'gravity' and self._test_enum(kwargs[k], GRAVITY_PARAMS):
+ self.params[k] = kwargs[k]
+ elif k == 'format' and self._test_enum(kwargs[k], FORMAT_PARAMS):
+ self.params[k] = kwargs[k]
+ elif k == 'compose' and self._test_enum(kwargs[k], COMPOSE_PARAMS):
+ self.params[k] = kwargs[k]
+ elif k == 'dispose' and self._test_enum(kwargs[k], DISPOSE_PARAMS):
+ self.params[k] = kwargs[k]
+ elif k in [ "fuzz", "width", "height", "brightness", "contrast", "saturation", "rotate", "hue" ]:
+ if kwargs[k] == '':
+ self.params[k] = None
+ else:
+ try:
+ self.params[k] = str(int(kwargs[k]))
+ except Exception as e:
+ raise Exception("Problem with param {}:\n".format(k) + str(e))
+ else:
+
+
+ self.params[k] = utils.sanitize(kwargs[k])
+
+ if self.params.get('background'):
+ self.tag = self.params.get('compose')
+ else:
+ self.tag = self.params.get('transparent', DEFAULT_TAG)
+
+ self.basename = self._get_filename();
+ self.filename = "{}.{}".format(self.basename, self.params.get('format', DEFAULT_FINALFORMAT))
+ self.filepath = os.path.join(WORKING_DIR, self.filename)
+
+ def _make_tempname(self, s):
+ return "PBTMP{}{}".format(self.now, s);
+
+ def _test_enum(self, e, arr):
+ if e in arr: return True
+ raise Exception ("Bad value: {}".format(e))
+
+ def _get_filename(self):
+ return "{}_{}_{}".format(
+ self.tag,
+ self.now,
+ self.params.get('username',"")
+ );
+
+ def _call_cmd(self, cmd):
+ try:
+ utils.call_cmd(cmd)
+ self.commands.append(" ".join(cmd));
+ except Exception:
+ raise Exception("Unable to call cmd {}".format(str(cmd)))
+
+ def _cleanup(self):
+ if not len(self.files_created):
+ pass
+ cmd = ["rm", "-f"] + self.files_created
+ self._call_cmd(cmd)
+
+ def _composite (self):
+ cmd = [
+ BIN_CONVERT, self.params['background']['path'],
+ "null:", self.filepath, "-matte",
+ "-dispose", self.params.get('dispose', DISPOSE_DEFAULT),
+ "-gravity", self.params.get("gravity",GRAVITY_DEFAULT),
+ "-compose", self.params['compose'], "-layers", "composite",
+ self.filepath ]
+ self._call_cmd(cmd);
+
+ def _convert(self):
+ cmd = [BIN_CONVERT, self.params['url']['path'] ]
+ if self.params.get('rotate'): cmd += ["-rotate", self.params['rotate'] ]
+ if self.params.get('flip'): cmd += ["-flip"]
+ if self.params.get('flop'): cmd += ["-flop"]
+ if self.params.get('transparent'):
+ if self.params.get('fuzz'):
+ cmd += ["-fuzz", "{}%".format(self.params['fuzz']) ]
+ cmd += [ "-transparent", self.params.get('subtract', "white") ]
+ if self.params.get('width') or self.params.get('height'):
+ if self.params.get('nearest') and self.params.get('format') == "gif":
+ cmd += [ "-coalesce","+map","-interpolate","Nearest","-interpolative-resize" ]
+ else:
+ cmd.append("-resize")
+ cmd += [ "{}x{}".format(self.params.get('width',"") or "", self.params.get('height',"") or "") ]
+ if self.params.get('black') != "black" or self.params.get('white') != 'white':
+ cmd += [ "+level-colors" , "{},{}".format(self.params.get('black','black'), self.params.get('white', 'white')) ]
+ if self.params.get('contrast'): cmd += [ '-contrast-stretch', self.params['contrast'] ]
+ if any( e in self.params.keys() for e in ['brightness', 'saturation', 'hue' ]):
+ cmd += [
+ "-modulate", "{},{},{}".format(
+ (self.params.get('brightness', 100) or 100),
+ (self.params.get('contrast', 100) or 100),
+ (self.params.get('hue', 100) or 100)
+ )]
+ cmd.append("-coalesce"); #why? #FIXME
+ cmd += [ self.filepath ];
+ self._call_cmd(cmd);
+
+ def create(self):
+ self._convert()
+ if self.params.get('background'):
+ self._composite()
+ self._cleanup();
+
+if __name__ == "__main__":
+
+ TEST_PARAMS = {
+ 'nearest': 'true',
+# 'height': None,
+ 'compose': 'Soft_Light',
+ 'coalesce': 'true',
+ 'dispose': 'None',
+ 'gravity': 'Center',
+ 'width': '200',
+ 'black': 'black',
+ 'tile': 'true',
+ 'white': 'white',
+ 'contrast': '100',
+ 'hue': '90',
+ 'saturation': '100',
+ 'merge_early': 'true',
+ 'format': 'gif',
+ 'background': 'http://i.asdf.us/im/bc/new_1430440747.gif',
+ 'subtract': '#EE7AE9',
+ 'transparent': 'true',
+# 'rotate': None,
+ 'name': 'yo',
+# 'brightness': None,
+ 'url': 'http://asdf.us/im/new.gif',
+ 'flop': 'true',
+ 'flip': 'false',
+ 'callback': 'jsonp1430442384162',
+ 'fuzz': '5'
+ }
+ g = Generate(**TEST_PARAMS);
+ g.create()
diff --git a/pb/Gradient/__init__.py b/pb/Gradient/__init__.py
new file mode 100755
index 0000000..aeb4d21
--- /dev/null
+++ b/pb/Gradient/__init__.py
@@ -0,0 +1,216 @@
+#!/usr/bin/python2.7
+import re
+import time
+from subprocess import call
+import simplejson as json
+import sys
+import os
+import sha
+import pb.lib.Utils as utils
+from pb.Config import *
+
+
+PARAM_LIST = [
+ "width", "height",
+ "color1", "color2",
+ "stripes",
+ "stripenumber", "stripeintensity",
+ "blurriness",
+ "contrast",
+ "brightness", "saturation", "hue",
+ "halftone",
+ "bevel", "percentbeveled",
+ "rotate", "flip", "flop", "tilt",
+ "filetype",
+ "gradienttype",
+ "username",
+]
+DEFAULT_FORMAT = "png"
+DEFAULT_COLORS = {
+ "color1" : "white",
+ "color2" : "black",
+};
+
+DEFAULT_WIDTH = "200"
+DEFAULT_HEIGHT = "200"
+DEFAULT_BEVEL_PERCENT = "12";
+
+HALFTONEVALUES = {
+ "checkeredfade": "h6x6a",
+ "etchedtransition": "o8x8",
+ "bendaydots": "h16x16o",
+ "smallerdots1": "h8x8o",
+ "smallerdots2": "c7x7w",
+ "flatstripes": "o2x2",
+ }
+
+
+class Gradient:
+ def __init__(self, **kwargs):
+ self.tag = "imGradient"
+ self.directory = WORKING_DIR
+ self.commands = []
+ self.filename = ""
+ self.filepath = ""
+ self.now = utils.now()
+
+ params = {}
+ for key in PARAM_LIST:
+ if key in kwargs:
+ if key in ['color1', 'color2']:
+ params[key] = utils.is_color(kwargs[key])
+ else:
+ params[key] = utils.sanitize(kwargs[key])
+
+ if key in ['rotate','tilt','blurriness','stripenumber','stripeintensity']:
+ params[key] = params[key] if utils.is_number(params[key]) else ""
+ elif key in ['brightness', 'contrast', 'hue']:
+ if not utils.is_number(params[key]) or params[key] == "100": params[key] = ""
+ else:
+ params[key] = ""
+ params['width'] = params['width'] if utils.is_number(params['width']) else DEFAULT_WIDTH
+ params['height'] = params['height'] if utils.is_number(params['height']) else DEFAULT_HEIGHT
+ params["color1"] = params["color1"] or DEFAULT_COLORS["color1"];
+ params["color2"] = params["color2"] or DEFAULT_COLORS["color2"];
+ self.params = params
+ if not self.params['percentbeveled']: self.params['percentbeveled'] = DEFAULT_BEVEL_PERCENT
+ self._bevelvalues = [
+ "flatout", "flatinner", "evenlyframed", "biginner",
+ "bigouter", "dramaticflatout", "dramaticflatinner",
+ ]
+
+ def newfilename(self):
+ return "{}{}-{}_{}_{}.{}".format(
+ self.tag,
+ self.params['color1'].replace('#','').replace('(','-').replace(')','-'),
+ self.params['color2'].replace('#','').replace('(','-').replace(')','-'),
+ self.now,
+ self.params['username'],
+ self.params['filetype'] or DEFAULT_FORMAT,
+ )
+
+ def _call_cmd(self, cmd):
+ try:
+ utils.call_cmd(cmd)
+ self.commands.append(" ".join(cmd));
+ except Exception:
+ raise Exception("Unable to call cmd {}".format(str(cmd)))
+
+
+ def _build_cmd(self):
+ cmd = [BIN_CONVERT]
+ cmd.extend([
+ '-size',
+ "{}x{}".format(self.params["width"],self.params["height"])
+ ])
+
+ if self.params['rotate']: cmd.extend(["-rotate", self.params["rotate"]])
+ if self.params['tilt']: cmd.extend(["-distort","SRT",self.params['tilt']])
+ if self.params['flip'] == "true": cmd.append("-flip")
+ if self.params['flop'] == "true": cmd.append("-flop")
+ if self.params['contrast']: cmd.extend(["-contrast-stretch", self.params['contrast']])
+ gradients = {
+ "canvas" : ["canvas:{}".format(self.params['color1'])],
+ "radial" : [
+ "radial-gradient:{}-{}".format( self.params['color1'], self.params['color2'])
+ ],
+ "colorspace" : [
+ "-colorspace",
+ "Gray",
+ "plasma:{}-{}".format(self.params['color1'], self.params['color2'])
+ ],
+ "mirrored" : [
+ "plasma:{}-{}".format(self.params['color1'], self.params['color2']),
+ "\(","+clone","-flop","\)",
+ "append"
+ ],
+ "plasmawash" : [
+ "plasma:{}-{}".format(self.params['color1'], self.params['color2']),
+ "-set","colorspace","HSB"
+ ],
+ "gradientwash" : [
+ "gradient:{}-{}".format(self.params['color1'], self.params['color2']),
+ "-set","colorspace","HSB"
+ ],
+ "noise" : ["xc:","+noise","Random","-virtual-pixel","tile"]
+ }
+ if self.params["gradienttype"] in gradients:
+ cmd.extend(gradients[self.params['gradienttype']])
+ else:
+ cmd.append("gradient:{}-{}".format(self.params['color1'], self.params['color2']))
+
+ if self.params['blurriness']:
+ cmd.extend(["-blur","0x{}".format(self.params["blurriness"]),"-auto-level"])
+
+ if self.params['stripes'] == "true" and len(self.params['stripenumber']):
+ cmd.extend(["-function","Sinusoid"])
+ if self.params['stripeintensity']:
+ cmd.append("{},{}".format(self.params['stripenumber'],self.params["stripeintensity"]))
+ else:
+ cmd.append(self.params['stripenumber'])
+ if self.params["halftone"] in HALFTONEVALUES:
+ cmd.extend([
+ "-ordered-dither",
+ HALFTONEVALUES[self.params["halftone"]]
+ ])
+ cmd += [
+ '-modulate',
+ "{},{},{}".format(
+ self.params['brightness'] or "100",
+ self.params['saturation'] or "100",
+ self.params['hue'] or "100")
+ ]
+ cmd.append(os.path.join(self.directory,self.filename));
+ self._call_cmd(cmd)
+
+ def _get_bevelvalue(self):
+ w, h = map(int, (self.params['width'], self.params['height']))
+ if h >= w:
+ bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(h))
+ else:
+ bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(w))
+ return {
+ "flatout": ["-s",bevpercentval,"-m","outer"],
+ "flatinner": ["-s",bevpercentval,"-m","inner"],
+ "evenlyframed": ["-s ",bevpercentval,"-m", "split"],
+ "biginner": ["-s",bevpercentval,"-m","outer","-c","50","-b","red","-a","25"],
+ "bigouter": ["-s",bevpercentval,"-m","split","-c","50","-b","red","-a","25"],
+ "dramaticflatout": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"],
+ "dramaticflatinner": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"],
+ }[self.params['bevel']]
+
+ def _make_bevel(self):
+ cmd = [BEVELBORDER]
+ cmd += self._get_bevelvalue()
+ cmd += [ os.path.join(self.directory,self.filename), os.path.join(self.directory, self.filename) ]
+ self._call_cmd(cmd)
+
+ def create(self):
+ self.filename = self.newfilename()
+ self.filepath = os.path.join(self.directory, self.filename)
+ self._build_cmd()
+ if self.params['bevel'] in self._bevelvalues:
+ self._make_bevel()
+
+if __name__ == "__main__":
+ TEST_FORM = {
+ "width" : "200",
+ "color1" : "#ffdead",
+ "color2" : "blue",
+ "stripes" : "true",
+ "stripenumber" : "20",
+ "gradienttype" : "radial",
+ "stripeintensity" : "20",
+ "halftone" : "checkeredfade",
+ "percentbeveled" : "30",
+ "flip" : "true",
+ "bevel" : "flatinner",
+ "rotate" : "20",
+ "height" : "200",
+ "filetype" : "jpg",
+ "username" : "whatever"
+ }
+ g = Gradient(**TEST_FORM);
+ g.create();
+ print " ".join(g.commands)
+ print g.filename
diff --git a/pb/Imgrid/__init__.py b/pb/Imgrid/__init__.py
new file mode 100755
index 0000000..d74029d
--- /dev/null
+++ b/pb/Imgrid/__init__.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python2.7
+import sys
+import re
+import os
+import simplejson as json
+import random
+import pb.lib.Utils as utils
+from pb.Config import *
+import tempfile
+
+DEFAULT_HEIGHT = 400
+DEFAULT_WIDTH = 600
+DEFAULT_LINE_COLOR = "silver"
+
+class Imgrid():
+ def __init__(self, **kwargs):
+ self.tag = "imGrid"
+ self.files_created = []
+ self.commands = [];
+ self._required_keys = [
+#{{{ required_keys
+ "width",
+ "height",
+ "linethickness",
+ "opacity",
+ "linecolor",
+ "spacing",
+ "vlines",
+ "hlines",
+ "shadow",
+ "bgimage",
+ "bgcolor",
+ "imageinstead",
+ "planebgcolor",
+ "planebgimage",
+ "swing",
+ "tilt",
+ "roll",
+ "zoom",
+ "skycolor",
+ "transition",
+ "trim",
+ "format",
+ "username"
+#}}}
+ ]
+ self.now = utils.now()
+
+ #Work out params ...
+ #note, tmpfile lib is pretty much useless here, given imagemagick's behavior with gifs (it splits them) etc...
+ #instead we're just making our own in /var/www/cache (tmpfs mounted there)
+ self.params = {}
+ for k in self._required_keys:
+ if k in kwargs:
+ if k in [ 'bgimage', 'planebgimage', 'imageinstead' ] and utils.bool_correct(kwargs[k]):
+ self.params[k] = {
+ 'url' : kwargs[k],
+ 'filename' : self._make_tempname(k),
+ 'path' : os.path.join(WORKING_DIR, self._make_tempname(k)) ,
+ }
+ try:
+ utils.download(self.params[k]['url'], self.params[k]['path'])
+ self.files_created.append(self.params[k]['path'])
+ self.params[k]['mimetype'] = utils.get_mimetype(self.params[k]['path'])
+ frames = utils.gif_frames(self.params[k]['path'])
+ if len(frames) > 1:
+ self.params[k]['path'] = random.choice(frames)
+
+ except Exception:
+ sys.stderr.write(str(e))
+ raise Exception ("BAD PARAMS");
+ elif k in [ 'skycolor', 'bgcolor', 'planebgcolor','linecolor' ]:
+ try:
+ self.params[k] = utils.is_color(kwargs[k])
+ except Exception:
+ sys.stderr.write(kwargs[k] + "\n")
+ raise Exception("Unable to process color for:\n{}".format(k))
+ elif k == 'opacity':
+ self.params[k] = str(float(kwargs[k]))
+ elif k == 'zoom':
+ self.params[k] = int(float(kwargs[k]))
+ else:
+ self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k]))
+ else:
+ self.params[k] = None;
+
+ self.params = utils.dotdict(self.params)
+
+ self.basename = self._get_filename();
+
+ if not self.params.finalformat:
+ self.params.finalformat = DEFAULT_FINALFORMAT
+ self.filename = "{}.{}".format(self.basename, self.params.finalformat)
+ #final filepath is stored in self.filepath
+ self.filepath = os.path.join(WORKING_DIR, self.filename)
+
+ def _get_filename(self):
+ return "{}_{}_{}".format(
+ self.tag,
+ self.now,
+ self.params.username or ""
+ );
+
+ def _call_cmd(self, cmd):
+ try:
+ utils.call_cmd(cmd)
+ self.commands.append(" ".join(cmd));
+ except Exception:
+ raise Exception("Unable to call cmd {}".format(str(cmd)))
+
+ def _make_tempname(self, s):
+ return "IMGRIDTMP{}{}".format(self.now, s);
+
+
+ #makes a canvas file...step 1 (if not bgimage)
+ def _make_canvas(self):
+ dimensions = "{}x{}".format(
+ self.params.width or DEFAULT_WIDTH,
+ self.params.height or DEFAULT_HEIGHT
+ )
+ if self.params.bgimage:
+ return
+ bgcolor = "xc:{}".format(self.params.bgcolor or 'transparent')
+ cmd = [ BIN_CONVERT, "-size", dimensions, bgcolor, self.filepath ]
+ self._call_cmd(cmd)
+
+ #2nd step-- run grid
+ def _grid_command(self):
+ cmd = [GRID]
+ if self.params.spacing:
+ if self.params.vlines:
+ width = 2 * int(self.params.width or DEFAULT_WIDTH)
+ cmd += ["-s","{},{}".format(self.params.spacing,width)]
+ elif self.params.hlines:
+ height = 2 * int(self.params.height or DEFAULT_HEIGHT)
+ cmd += ["-s", "{},{}".format(height,self.params.spacing)]
+ else:
+ cmd += ["-s",self.params.spacing]
+ cmd += [ "-c", self.params.linecolor or DEFAULT_LINE_COLOR]
+ if self.params.linethickness: cmd += ['-t',self.params.linethickness]
+ if self.params.opacity: cmd += ['-o',self.params.opacity]
+ cmd += [ self.filepath, self.filepath ]
+ self._call_cmd(cmd)
+
+ def _shadow_cmd(self):
+ #convert 1.png \( +clone -background black -shadow 110x1+9+9 \) +swap -background none -layers merge +repage 2.png
+ cmd = [
+ BIN_CONVERT,
+ self.filepath,
+ "(","+clone","-background","black","-shadow","100x2+20+10",")",
+ "+swap","-background","none","-layers","merge","+repage" ,
+ self.filepath
+ ]
+ self._call_cmd(cmd)
+
+
+ def _threed_rotate_cmd (self):
+ #3rd step--run 3Drotate
+ cmd = [THREEDROTATE]
+ if self.params.swing: cmd += ["pan={}".format(self.params.swing)]
+ if self.params.tilt: cmd += ["tilt={}".format(self.params.tilt)]
+ if self.params.roll: cmd += ["roll={}".format(self.params.roll)]
+ if self.params.zoom:
+ cmd += ["zoom={}".format(self.params.zoom)]
+ if cmd == [THREEDROTATE]: #if nothing has been added
+ return
+ if self.params.planebgcolor and not self.params.planebgimage:
+ cmd += ["bgcolor={}".format(self.params.planebgcolor)]
+ else:
+ cmd += ["bgcolor=none"]
+ cmd += ["skycolor={}".format(self.params.skycolor or 'none')]
+ if self.params.transition: cmd += ["vp={}".format(self.params.transition)]
+ cmd += [ self.filepath, self.filepath ]
+ self._call_cmd(cmd)
+
+
+ def _trim_cmd (self):
+ cmd = [BIN_CONVERT, self.filepath, "-trim", "+repage", self.filepath]
+ self._call_cmd(cmd)
+
+ def _prepare_gridimage(self, image):
+ if image['mimetype'] != 'png':
+ cmd = [BIN_CONVERT, image['path'], self.filepath]
+ else:
+ cmd = ['cp', image['path'], self.filepath]
+ self._call_cmd(cmd)
+
+
+ def _overlay_planebgimage(self):
+ cmd = [
+ BIN_COMPOSITE,
+ "-compose", "Dst_Over", "-gravity", "center",
+ self.params.planebgimage["path"],
+ self.filepath,
+ self.filepath
+ ]
+ self._call_cmd(cmd)
+
+ def _cleanup(self):
+ if not len(self.files_created):
+ pass
+ cmd = ["rm", "-f"] + self.files_created
+ self._call_cmd(cmd)
+
+ def create(self):
+ if self.params.bgimage:
+ self._prepare_gridimage(self.params.bgimage)
+ self._grid_command()
+ elif self.params.imageinstead:
+ self._prepare_gridimage(self.params.imageinstead)
+ else:
+ self._make_canvas()
+ self._grid_command()
+ if self.params.shadow: self._shadow_cmd()
+ self._threed_rotate_cmd()
+ if self.params.planebgimage: self._overlay_planebgimage()
+ if self.params.trim: self._trim_cmd()
+ self._cleanup()
+
+if __name__ == "__main__":
+ g = Imgrid(**{
+ 'bgimage' : 'http://i.asdf.us/im/1a/imBreak_1424909483_xx_abridged___.gif',
+ 'planebgimage' : 'http://i.imgur.com/FICZtph.png',
+ 'tilt' : '30',
+ 'spacing' : '30',
+ 'hlines' : 'true',
+ 'roll' : '30',
+ 'shadow' : 'true',
+ 'trim' : 'true'
+ })
+ g.create()
+ print g.commands
diff --git a/pb/Imlandscape/__init__.py b/pb/Imlandscape/__init__.py
new file mode 100755
index 0000000..24cee8d
--- /dev/null
+++ b/pb/Imlandscape/__init__.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python2.7
+import os
+import sys
+import random
+import re
+import pb.lib.Utils as utils
+import urllib
+import urlparse
+from pb.Config import *
+
+import base64
+import time
+import string
+import urllib
+from subprocess import Popen, PIPE
+import sha
+import simplejson as json
+
+import mimetypes
+
+class Imlandscape(object):
+ def __init__(self, **kwargs):
+ self.params = {}
+ self.tag = "imlandscape"
+ self.commands = [];
+ self._required_keys = [
+ "heightmap",
+ "imgdata",
+ "texture",
+ "name",
+ ]
+ self.now = utils.now()
+ self.files_created = []
+ for k in self._required_keys:
+ if k in kwargs:
+ self.params[k] = kwargs[k]
+ else:
+ self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k]))
+
+ def _filename_from_url (self, url, name=""):
+ if "?" in url:
+ url = url.split("?")[0]
+ if "/" in url:
+ url = urllib.unquote(url).replace(" ","")
+ filename = url.split("/")[-1]
+ filetype = "png"
+ filename = sanitize(filename[:-4])
+ else:
+ filename = ""
+ if name != "":
+ name = name+"_"
+ return "{}_{}{}_{}.{}".format("imlandscape", name, filename,self.now, "png")
+
+ def _saveImgData(self, imgdata, filename):
+ try:
+# up = urlparse.urlparse(url)
+# head, data = imgdata.split(',', 1)
+# bits = head.split(';')
+ parts = imgdata.split(';')
+ mime_type = parts[0] if parts[0] else 'text/plain'
+ data = parts[1]
+ charset, b64 = 'ASCII', False
+ for part in parts[1]:
+ if part.startswith('charset='):
+ charset = part[8:]
+ elif part == 'base64':
+ b64 = True
+
+ # Do something smart with charset and b64 instead of assuming
+ if b64:
+ plaindata = base64.b64decode(data)
+ else:
+ plaindata = data
+ with open(filename, 'wb') as f:
+ f.write(plaindata)
+ except Exception as e:
+ sys.stderr.write("ERROR: {}\n".format(str(e)));
+
+# def _cleanup(self):
+# cmd = ["rm"]+self.files_created
+# self._call_cmd(cmd)
+
+ def create(self, breakmode=""):
+ self.filepath = self._filename_from_url(self.params.get('texture',""), self.params.get('name',""));
+ self._saveImgData(self.params.get('imgdata'), self.filepath);
+
+if __name__ == "__main__":
+ f = open("/tmp/base64img")
+ data = f.read()
+ f.close()
+ TEST_PARAMS = {
+ "heightmap" : "https%3A%2F%2Fwww.google.com%2Fimages%2Fsrpr%2Flogo11w.png" ,
+ "imgdata" : data,
+ "texture" : "https%3A%2F%2Fwww.google.com%2Fimages%2Fsrpr%2Flogo11w.png",
+ "name" : "pepper",
+ }
+ b = Imlandscape(**TEST_PARAMS)
+ b.create();
+ print b.filepath
+
+
diff --git a/pb/Imlandscape/landscape b/pb/Imlandscape/landscape
new file mode 100755
index 0000000..10e8ede
--- /dev/null
+++ b/pb/Imlandscape/landscape
@@ -0,0 +1,163 @@
+#!/usr/bin/python2.7
+import cgi
+import sys
+import os
+import re
+import time
+import string
+import urllib
+from subprocess import Popen, PIPE
+import sha
+import simplejson as json
+
+import mimetypes
+import s3
+
+import db
+DB = db.db ()
+
+import base64
+import urlparse
+
+
+AWS_ACCESS_KEY_ID = 'AKIAIR53VPBXKJMXZIBA'
+AWS_SECRET_ACCESS_KEY = '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'
+BUCKET_NAME = 'i.asdf.us'
+BASE_PATH = "/var/www/asdf.us/httpdocs/imlandscape"
+BASE_URL = "http://i.asdf.us/"
+PARAM_LIST = "heightmap texture name imgdata filename"
+BIN_IDENTIFY = "/usr/bin/identify"
+
+print "Content-type: text/plain"
+print ""
+def insert_cmd (dir, newfile, name, texture, dataobj):
+ if texture == "":
+ texture = "NULL"
+ try:
+ sql = "INSERT INTO im_cmd (date,remote_addr,name,url,dir,oldfile,newfile,cmd, dataobj, tag) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s, %s)"
+
+ args = (now(), "NULL", name, texture, dir, "NULL", newfile, "NULL", dataobj, "imlandscape")
+ DB.execute(sql, args)
+ except ():
+ return
+
+def hash_dir (s):
+ return sha.new(s).hexdigest()[:2]
+
+def bin_identify (filename):
+ ident = Popen([BIN_IDENTIFY, filename], stdout=PIPE).communicate()[0]
+ partz = ident.split(" ")
+ width,height = partz[2].split("x")
+ return width, height
+
+def get_params (paramlist):
+ paramkeys = paramlist.split()
+ form = cgi.FieldStorage()
+ params = {}
+ for key in paramkeys:
+ if key in form:
+ if key == 'heightmap':
+ params[key] = form[key].value
+ elif key == 'imgdata':
+ params[key] = form[key].value
+ elif key == 'texture':
+ params[key] = form[key].value
+ else:
+ params[key] = sanitize(form[key].value)
+ else:
+ params[key] = None
+ return params
+
+def error (e):
+ print "#@imlandscape"
+ print "ERROR\t"+e
+ sys.exit()
+
+def now ():
+ return int(time.mktime(time.localtime()))
+
+def sanitize (str):
+ return re.sub(r'\W+', '', str)
+
+def filename_from_url (url, name=""):
+ if "?" in url:
+ url = url.split("?")[0]
+ if "/" in url:
+ url = urllib.unquote(url).replace(" ","")
+ filename = url.split("/")[-1]
+ filetype = "png"
+ filename = sanitize(filename[:-4])
+ else:
+ filename = ""
+ if name != "":
+ name = name+"_"
+ return "{}_{}{}_{}.{}".format("imlandscape", name, filename,now(), "png")
+
+def saveImgData(url, filename):
+ try:
+ up = urlparse.urlparse(url)
+ head, data = up.path.split(',', 1)
+ bits = head.split(';')
+ mime_type = bits[0] if bits[0] else 'text/plain'
+ charset, b64 = 'ASCII', False
+ for bit in bits[1]:
+ if bit.startswith('charset='):
+ charset = bit[8:]
+ elif bit == 'base64':
+ b64 = True
+
+ # Do something smart with charset and b64 instead of assuming
+ plaindata = base64.b64decode(data)
+
+ with open(filename, 'wb') as f:
+ f.write(plaindata)
+ except Exception as e:
+ error(str(e));
+
+def file_size (file):
+ return os.stat(file)[6]
+
+def moveToS3(filename,objectname):
+ conn = s3.AWSAuthConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
+ sys.stderr.write( "Uploading %s" % filename)
+ filedata = open(filename, 'rb').read()
+ content_type = mimetypes.guess_type(filename)[0]
+ if not content_type:
+ content_type = 'text/plain'
+ conn.put(BUCKET_NAME, objectname, s3.S3Object(filedata),
+ {'x-amz-acl': 'public-read', 'Content-Type': content_type, 'x-amz-storage-class': 'REDUCED_REDUNDANCY'})
+
+param = get_params(PARAM_LIST)
+if param['imgdata'] is None:
+ error("no imgdata")
+url = param['imgdata']
+if param['texture'] is None:
+ param['texture'] = "";
+if param['heightmap'] is None:
+ param['heightmap'] = "";
+if param['name'] is None:
+ param['name'] = "";
+
+dataobj = json.dumps({
+ 'texture' : param['texture'],
+ 'heightmap' : param['heightmap'],
+ 'name' : param['name']
+})
+
+dir = hash_dir(param['imgdata']);
+
+filename = filename_from_url(param['texture'], param['name']);
+
+tag = "imlandscape"
+objectname = "im/"+dir+"/"+filename
+
+saveImgData(param['imgdata'], filename);
+
+print "#@imlandscape"
+#print ", ".join([k+"="+str(v) for k,v in param.iteritems()])
+print file_size (filename)
+print bin_identify (filename)
+print BASE_URL+objectname
+insert_cmd(dir, filename, param['name'], param['texture'], dataobj);
+moveToS3(filename, objectname);
+os.remove(filename);
diff --git a/pb/Pattern/__init__.py b/pb/Pattern/__init__.py
new file mode 100755
index 0000000..b1fb9af
--- /dev/null
+++ b/pb/Pattern/__init__.py
@@ -0,0 +1,172 @@
+#!/usr/bin/python2.7
+import os
+import sys
+import random
+import re
+import urllib
+from pb.Config import *
+import pb.lib.Utils as utils
+
+import simplejson as json
+from PIL import Image
+import uuid
+
+FUSE_MODE="Pin_Light"
+
+class Pattern:
+ def __init__(self, **kwargs):
+ self.params = {}
+ self.tag = "imPattern";
+ self._pid = str(os.getpid())
+ self.commands = [];
+ self.now = utils.now()
+ self.height = ""
+ self.width = ""
+ self._required_keys = [
+ #FIXME change name to username in js
+ #FIXME change js api
+ "pattern_url",
+ "pattern_data",
+ "username",
+ "image_url",
+ ]
+ self.files_created = []
+ for k in self._required_keys:
+ if k in kwargs:
+ if k in [ 'pattern_url', 'image_url' ]:
+ self.params[k] = kwargs[k]
+ elif k == 'pattern_data':
+ self.params[k] = kwargs[k] #FIXME add conversion data
+ else:
+ self.params[k] = utils.sanitize(kwargs[k])
+ else:
+ self.params[k] = False;
+
+ if not self.params['image_url']:
+ sys.stderr.write('no image url');
+ raise ValueError
+ self.params = utils.dotdict(self.params)
+
+ self.basename, self._format = self._get_filename();
+ #FIXME omit file extension for downloaded files
+ self._downloaded_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_DL{}_{}.{}".format(self.basename, self._pid, self._format)) # same here
+ #lets go back to this in a second
+ self._pattern_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_PTN{}_{}.{}".format(self.basename, self._pid, self._format)) # this
+
+ self._download(self.params.image_url, self._downloaded_file)
+
+ self.width, self.height = utils.dimensions(self._downloaded_file) # same here
+
+ self.filename = "{}.{}".format(self.basename, self._format)
+ self.filepath = os.path.join(WORKING_DIR, self.filename)
+
+ if self.params['pattern_url']:
+ self._download(self.params['pattern_url'], self._pattern_file)
+ elif self.params['pattern_data']:
+ self._from_pattern_data()
+ else:
+ sys.stderr.write("pattern must be supplied as json array or as a png url")
+ raise ValueError;
+
+ def _download(self, url, dest):
+ try:
+ utils.download(url, dest)
+ self.files_created.append(dest)
+ except Exception as e:
+ sys.stderr.write(str(e))
+ raise;
+
+ def _call_cmd(self, cmd):
+ try:
+ utils.call_cmd(cmd)
+ self.commands.append(" ".join(cmd));
+ except Exception:
+ raise Exception("Unable to call cmd {}".format(str(cmd)))
+
+ def _from_pattern_data(self):
+ def boolToColor(boolean):
+ if boolean:
+ return (0,0,0,255);
+ else:
+ return (255,255,255,255)
+ specs = json.loads(self.params.pattern_data);
+ if int(specs['width']) > 100 or int(specs['height']) > 100:
+ raise ValueError
+ sys.stderr.write("height and width need to be less than 100 px")
+ img = Image.new('RGBA', (int(specs['width']), int(specs['height'])));
+ pixels = img.load();
+ for i in range(0, len(specs['matrix'])):
+ for j in range(0, len(specs['matrix'][i])):
+ pixels[j,i] = boolToColor(int(specs['matrix'][i][j]));
+
+ img.save(self._pattern_file, "PNG")
+
+
+ def _get_filename (self):
+ url = self.params.image_url
+ name_part = "";
+ file_format = "";
+ if "?" in url:
+ url = url.split("?")[0]
+ if "/" in url:
+ url = urllib.unquote(url).replace(" ","")
+ name_part = url.split("/")[-1]
+ try:
+ parts = name_part.split(".")
+ name_part = utils.sanitize(parts[-2])
+ file_format = utils.sanitize(parts[-1])
+ if not name_part or not file_format:
+ sys.stderr.write( "Incompatible input file type")
+ raise;
+ except Exception as e:
+ sys.stderr.write( "Incompatible input file type")
+ raise;
+ else:
+ sys.stderr.write( "Incompatible url")
+ raise;
+ if (len(name_part) > 20):
+ name_part = name_part[:-20]
+ return "{}{}_{}_{}".format(self.tag, name_part, self.now, self.params.username or ""), file_format
+
+ def _cleanup(self):
+ cmd = ["rm"]+self.files_created
+ self._call_cmd(cmd)
+
+ #first step
+ def _make_canvas(self):
+ cmd = [BIN_CONVERT,"-size",self.width+"x"+self.height,"canvas:transparent", self.filepath]
+ self._call_cmd(cmd)
+
+ #second step use the Canvas as a background
+ def _make_mask(self):
+ #tile the pattern pattern on the canvas
+ cmd = [BIN_COMPOSITE,"-tile", self._pattern_file, self.filepath, self.filepath];
+ self._call_cmd(cmd)
+ #fuse the tiled file to create a mask
+ #convert thebg.gif -compose Dst_In null: thefile.gif -matte -layers composite new.gif
+ cmd = [BIN_CONVERT, self.filepath, "-compose", "Dst_In", "null:",
+ self._downloaded_file, "-matte", "-layers", "composite", self.filepath]
+ self._call_cmd(cmd)
+
+ #third step
+ def _fuse_mask(self, fuse_mode=FUSE_MODE):
+ cmd = [BIN_CONVERT, "-dispose", "2", self.filepath, "null:",
+ self._downloaded_file, "-matte", "-compose", fuse_mode, "-layers", "composite",
+ self.filepath]
+ self._call_cmd(cmd)
+
+ def create(self):
+ self._make_canvas();
+ self._make_mask()
+ self._fuse_mask();
+
+if __name__ == "__main__":
+ TEST_PARAMS = {
+ # "pattern_url" : "http://asdf.us/impattern/patterns/1.png",
+ "pattern_data" : '{"matrix":[["0","0","0","0","0","1","0","0","0","0"],["0","0","0","0","1","1","1","0","0","0"],["0","0","1","1","1","0","1","0","0","0"],["0","1","1","0","0","0","0","0","0","0"],["0","1","0","0","1","0","0","0","0","0"],["0","1","0","0","1","0","0","0","1","0"],["0","1","0","0","1","1","0","0","1","0"],["0","1","0","0","0","1","1","1","1","0"],["0","1","1","1","1","0","0","0","0","0"],["0","0","0","0","1","0","0","0","0","0"]],"width":"10","height":"10"}',
+ # "username" : "garfield",
+ "image_url" : "http://i.asdf.us/im/be/PinkHijab_1425078647_reye.gif",
+ }
+ p = Pattern(**TEST_PARAMS)
+ p.create()
+
diff --git a/pb/lib/db.py b/pb/lib/Db/__init__.py
index 66db35d..91b0fcf 100755..100644
--- a/pb/lib/db.py
+++ b/pb/lib/Db/__init__.py
@@ -1,4 +1,5 @@
import MySQLdb
+import time
USER = "asdfus"
PASSWORD = "gTYgT&M6q"
DATABASE = "asdfus"
diff --git a/pb/lib/utils.py b/pb/lib/Utils/__init__.py
index 5ca5b3e..1d5a708 100644
--- a/pb/lib/utils.py
+++ b/pb/lib/Utils/__init__.py
@@ -1,5 +1,5 @@
import re
-from pb.config import *
+from pb.Config import *
import time
import urllib
import urllib2
diff --git a/pbserver.py b/pbserver.py
new file mode 100755
index 0000000..a0068e9
--- /dev/null
+++ b/pbserver.py
@@ -0,0 +1,215 @@
+#!/usr/bin/python2.7
+from bottle import route, run, post, request, static_file
+
+from pb.Gradient import Gradient
+from pb.Imgrid import Imgrid
+from pb.Breaker import Breaker
+from pb.Pattern import Pattern
+from pb.Generate import Generate
+from pb.Imlandscape import Imlandscape
+
+from pb.Config import AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, BUCKET_NAME, BIN_IDENTIFY
+import pb.lib.Utils as utils
+
+import os
+import sys
+from pb.lib.Db import Db
+
+import sha
+from subprocess import call, Popen, PIPE
+import simplejson as json
+
+from boto.s3.connection import S3Connection
+from boto.s3.key import Key
+#
+try:
+ db = Db();
+except Exception as e:
+ sys.stderr.write("Could not connect to db:\n{}".format(e))
+ sys.exit(1);
+BASE_URL = "http://i.asdf.us"
+
+def hashdir(filename):
+ return sha.new(filename).hexdigest()[:2]
+
+def bin_identify (filepath):
+ ident = Popen([BIN_IDENTIFY, filepath], stdout=PIPE).communicate()[0]
+ partz = ident.split(" ")
+ width,height = partz[2].split("x")
+ return [ width, height ]
+
+def cleanup(filepath):
+ try:
+ call(['rm', filepath])
+ except Exception as e:
+ sys.stderr.write(str(e))
+ raise
+
+def s3move(filename,objectname):
+ try:
+ conn = S3Connection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, is_secure=False)
+ b = conn.get_bucket(BUCKET_NAME)
+ k = Key(b)
+ k.key = objectname
+ k.set_contents_from_filename(filename)
+ k.set_acl('public-read')
+ k.storage_class = 'REDUCED_REDUNDANCY'
+ except Exception as e:
+ sys.stderr.write(str(e));
+ raise(e)
+
+def format_im_data(im, insert_url="NULL"):
+ directory = hashdir(im.filename)
+ dimensions = bin_identify(im.filepath)
+ size = utils.file_size(im.filepath)
+ objectname = "im/{}/{}".format(directory, im.filename)
+ try:
+ s3move(im.filepath, objectname)
+ cleanup(im.filepath)
+ db.insert_cmd(
+ date=im.now,
+ remote_addr=request.environ.get('REMOTE_ADDR', "NULL"),
+ username=im.params.get('username', "NULL"),
+ url=insert_url,
+ directory=directory,
+ oldfile="NULL",
+ newfile=im.filename,
+ dataobj=";".join(im.commands),
+ cmd=json.dumps(im.params),
+ tag=im.tag,
+ )
+ return json.dumps({
+ 'url' : "{}/{}".format(BASE_URL, objectname),
+ 'size' : size,
+ 'width' : "{}px".format(dimensions[0]),
+ 'height' : "{}px".format(dimensions[1]),
+ })
+ except Exception as e:
+ sys.stderr.write(str(e))
+ raise;
+
+
+def return_image(im, insert_url="NULL"):
+ return format_im_data(im, insert_url)
+
+
+def return_jsonp(im, insert_url="NULL"):
+ return "{}({})".format(im.get("callback"), format_im_data(im, insert_url))
+
+
+@post('/im/api/imgradient')
+def gradient():
+ try:
+ im = Gradient(**(dict(request.forms)))
+ im.create();
+ return return_image(im)
+ except Exception as e:
+ sys.stderr.write("imgradient failure\n")
+ sys.stderr.write("params:\n")
+ for i in request.forms:
+ sys.stderr.write("{}:{}\n".format(i, request.forms[i]))
+ raise;
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+@post('/im/api/imgrid')
+def imgrid():
+ try:
+ im = Imgrid(**(dict(request.forms)))
+ im.create();
+ url= "NULL"
+ for elem in [ im.params.imageinstead , im.params.bgimage, im.params.planebgimage ]:
+ if elem:
+ url = elem['url']
+ break
+ return return_image(im, url)
+ except Exception as e:
+ sys.stderr.write(str(e))
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+@post('/im/api/generate')
+def generate():
+ try:
+ im = Generate(**(dict(request.forms)))
+ im.create();
+ return return_image(im)
+ except Exception as e:
+ sys.stderr.write(str(e))
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+@post('/im/api/imbreak')
+def breaker():
+ try:
+ im = Breaker(**(dict(request.forms)))
+ im.create();
+ return return_image(im, im.params['url'])
+ except Exception as e:
+ sys.stderr.write(str(e))
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+@post('/im/api/impattern')
+def pattern():
+ try:
+ im = Pattern(**(dict(request.forms)))
+ im.create();
+ return return_image(im, im.params['image_url'])
+ except Exception as e:
+ sys.stderr.write(str(e)+"\n")
+ for i in request.forms:
+ sys.stderr.write("{}:{}\n".format(i, request.forms[i]))
+ raise;
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+@post('/im/api/imlandscape')
+def imlandscape():
+ try:
+ im = Imlandscape(**(dict(request.forms)))
+ im.create();
+ sys.stderr.write(str(im.params))
+ return return_image(im, im.params['texture'])
+ except Exception as e:
+ sys.stderr.write(str(e))
+ return json.dumps({ 'error' : 'Request could not be processed' })
+
+
+
+#static routes
+@route('/im/<filename>')
+def server_static(filename):
+ return static_file(filename, root='frontend/im/')
+@route('/im')
+def server_static():
+ return static_file("index.html", root='frontend/im/')
+@route('/imgrid')
+def server_static():
+ return static_file("index.html", root='frontend/imgrid/')
+@route('/imgradient')
+def server_static():
+ return static_file("index.html", root='frontend/imgradient/')
+@route('/imlandscape')
+def server_static():
+ return static_file("index.html", root='frontend/imlandscape/')
+@route('/impattern')
+def server_static():
+ return static_file("index.html", root='frontend/impattern/')
+@route('/imbreak')
+def server_static():
+ return static_file("index.html", root='frontend/imbreak/')
+@route('/')
+def server_static():
+ return static_file("index.html", root='frontend/im/')
+@route('/css/<filename>')
+def server_static(filename):
+ return static_file(filename, root='frontend/css/')
+@route('/js/<filename>')
+def server_static(filename):
+ return static_file(filename, root='frontend/js/')
+@route('/img/<filename>')
+def server_static(filename):
+ return static_file(filename, root='frontend/img/')
+
+
+#run(host='0.0.0.0', server='flup', port=8999, debug=True)
+run(host='0.0.0.0', port=8999, debug=True)
+
+
+
diff --git a/tests/jsonptest.sh b/tests/jsonptest.sh
new file mode 100644
index 0000000..8539853
--- /dev/null
+++ b/tests/jsonptest.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+curl 'http://asdf.us/cgi-bin/im/generate?callback=jsonp1431361693303&url=http%3A%2F%2Fwww.maskworld.com%2Fpix%2Fmasks%2F025-party-face-gesicht-fasching-karneval-carnival-halloween-latex-film-movie-larp-theatre-theater-horror-rubber-gummi-mask-masks-maske-masken.jpg&name=test&transparent=true&fuzz=5' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://carbonpictures.com/pb/' -H 'Cookie: imname=yo' -H 'Connection: keep-alive' --compressed