User:Eleanorg/1.3/Dissolute Image/Code1: Difference between revisions

From XPUB & Lens-Based wiki
No edit summary
 
(7 intermediate revisions by the same user not shown)
Line 1: Line 1:
==August 2012==
Code below is the prototype shown at WORM in July 2012. I'm now re-working how the pixels are embedded so that users will be given an image file to host, rather than a boring old string.
<br />
[[User:Eleanorg/1.3/Dissolute_Image/Code2 | Image embedding: code experiments]]
==Make database of pixels==
==Make database of pixels==
Splits up image into pixels with imageMagick, then inserts each one as a hash in a Mongo database. Shown here with dummy values for testing, imagemagick bits commented out.
Splits up image into pixels (and their associated info) with imageMagick, then inserts each one as a hash in a Mongo database. To be run once only.


<source lang="python">
<source lang="python">
Line 13: Line 18:




#--------- create database -----------------------#
#--------- create database --------------------------------#


connection = Connection()
connection = Connection()
Line 21: Line 26:


#--------- determine image dimensions-----------------------#
#--------- determine image dimensions-----------------------#
 
image = "20by10PixelsSection1.png"
image = "thatwouldbetelling!"
sizeQuery = "identify -format '%w %h' " + image # system command gets image dimensions with ImageMagick
sizeQuery = "identify -format '%w %h' " + image # system command gets image dimensions with ImageMagick
size = os.popen(sizeQuery, 'r').read() # captures output of system call
size = os.popen(sizeQuery, 'r').read() # captures output of system call
Line 29: Line 34:
rows = int(height)
rows = int(height)


#print columns
#print rows
##--------- assign pixel details to database-----------------#


#--------- assign pixel details to database-----------------#


def getcolors ():
def getcolors ():
     n = 0
     ID = 0
     for row in range (0, rows): # for each row in the image...
     for row in range (0, rows): # for each row in the image...
         for column in range (0, columns): # for each column in the row...
         for column in range (0, columns): # for each column in the row...
            ID = ID + 1
             colorQuery = "convert " + image + " -format '%[pixel:p{" + str(column) + "," + str(row) + "}]' info:-"
             colorQuery = "convert " + image + " -format '%[pixel:p{" + str(column) + "," + str(row) + "}]' info:-"
             colorResult = os.popen(colorQuery, 'r').read() # makes & captures output of system call
             colorResult = os.popen(colorQuery, 'r').read() # makes & captures output of system call
             color = re.sub("\n", "", colorResult) # strips newline character from end of sys call result
             rgbResult = re.sub("\n", "", colorResult) # strips newline character from end of sys call result
             pixelName = {'xpos': str(column), 'ypos': str(row), 'color': color }
             pat = r"(\d\d\d),(\d\d\d),(\d\d\d)," # use dirty dirty regex to manually convert rgb result to a tuple
             collection.insert(pixelName) # insert this pixel into the db  
            for m in re.finditer(pat,rgbResult):
                r = int((m.group(1)))
getcolors()  
                g = int((m.group(2)))
                b = int((m.group(3)))
            RGB = r,g,b
            hexa = "".join(map(chr, RGB)).encode('hex') # converts tuple from rgb form to hex value
            color = re.sub(hexa, "#"+hexa, hexa) # replaces hex value with the same value plus a leading #
            pixelHash = {'ID': ID, 'xpos': str(column), 'ypos': str(row), 'color': color, 'url':"" }
             collection.insert(pixelHash) # insert this pixel into the db
           
 
getcolors()
</source>
</source>


==Give user an unadopted pixel==
==Give user an unadopted pixel==
Finds all the pixels in the db with no url associated. Picks one at random and gives it to the user, with an input form for them to enter the url where they have put it. #TODO needs to be made into a .cgi script.
Finds all the pixels in the db with no url associated. Picks one at random and gives it to the user, with an input form for them to enter the url where they have put it.  
 
<source lang="python">
<source lang="python">
#!/usr/bin/python
#!/usr/bin/python
#-*- coding:utf-8 -*-
#-*- coding:utf-8 -*-


import cgi
import cgitb; cgitb.enable()
import pymongo, random   
import pymongo, random   
from pymongo import Connection
from pymongo import Connection
Line 60: Line 80:


connection = Connection()
connection = Connection()
myDB = connection['pixelDatabaseTest4']
myDB = connection['pixelDbQuery1']
 
 
#--------- some db queries for testing------------#
 
# print whole db thus:
#for entry in myDB.collection.find():
#    print entry
 
#myDB.collection.update( {"id":"2"}, {"$set":{"url": "ovulation.com"}}) # update url of entry with id '2'
 
#print myDB.collection.find({"id": "2"})["color"]


#--------- generate pixel string ------------#
#--------- generate pixel string ------------#


# find all empty urls in a loop:
# find all entries where url is empty:
unadopted = []
unadopted = []
for entry in myDB.collection.find({"url": ""}):
for entry in myDB.collection.find({"url": ""}):
     unadopted.append(entry) # add this pixel's hash as an item to the 'unadopted' dictionary
     unadopted.append(entry) # add this pixel's hash as an item to the 'unadopted' dictionary
#print unadopted


howMany = len(unadopted) # find out how many items in 'unadopted' list
howMany = len(unadopted) # find out how many items in 'unadopted' list
#print howMany
random = random.randint(0,howMany) # pick a random number in this range
random = random.randint(0,howMany) # pick a random number in this range
#print random
pixelHash = unadopted[random] # ...and choose the pixel at this index
pixelHash = unadopted[random] # ...and choose the pixel at this index
print pixelHash['color']
#print pixelHash


pixelString = "I'm adopting pixel " + pixelHash['id'] + " of 10,000 at position " + pixelHash['xpos'] + "," + pixelHash['ypos'] + " with color " + pixelHash['color']
pixelString = "ID=" + str(pixelHash['ID']) + ";x=" + pixelHash['xpos'] + ";y=" + pixelHash['ypos'] + ";col=" + pixelHash['color']
print pixelString
#print pixelString




Line 96: Line 108:
     <title>Adopt a Pixel</title>
     <title>Adopt a Pixel</title>
         <link <link rel="stylesheet" href="../../pixels.css">
         <link <link rel="stylesheet" href="../../pixels.css">
        <link href='http://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
   </head>
   </head>
   <body>"""
   <body>"""
Line 104: Line 117:
print htmlHeader
print htmlHeader
print """
print """
<div class="centred" style="margin-top:50px;">
<h1>the DISSOLUTE IMAGE</h1>
Below is the unique identifier for your pixel.
 
Copy and paste it somewhere public on the interwebs, exactly as it appears:
<div class="main">
<div class="menu">
<ul class="menuList">
<li><a href="pixelsShowImage.cgi">Home</a></li>
<li><a href="../../forbiddenPixels/pixelsAbout.html">About</a></li>
<li>Host a Pixel</li>
</ul>
</div>
</div>
</div>
<div class="container txt">
<div class="heading">Host a Pixel</div>
 
<span class="pixelString">""" +
<div class="rightBox" style="">
  pixelString +
 
"""</span>
<div class="pixelInfo">
You'll be hosting pixel <strong>""" + str(pixelHash['ID']) + """</strong> out of a total 95600. Enlarged preview:
<div id="pixelPreview" style="background-color: """ + pixelHash['color'] + """">
</div>
 
<div class="pixelDetails">
Here are the unique details for your pixel: <br />
</div>
</div>
<div class="centred" style="margin-top:50px;">
 
Then tell us the URL of the page where you pasted it:
<form action="pixelsScrapeAndVerify.cgi" name="inputForm"> 
    <input name="pixel" class="pixelInput" value=""" + pixelString + """><br /> 
 
<div class="inputBox">
    To host this pixel, just copy & paste the details above<br /> somewhere public on the web, exactly as they appear.<br />
    Then tell us the full URL of the page where you pasted them:<br />
</div>
</div>
<div class="container txt">
    </span>
  <form action="saveUrl.cgi" name="inputForm"
    URL: <input name="url" class="urlInput" value="">
    <span class="containerText">Paste url: </span>
    <input name="url">
     <input type="submit" value="OK">
     <input type="submit" value="OK">
  </form>
</form>
</div>
 
<div class="centred">
 
 
  <div class="">
Your pixel will appear in the image for as long as the text remains at this URL.
Your pixel will appear in the image for as long as the text remains at this URL.
  </div>
</div>
</div>
 
</body>
</body>
</html>"""
</html>"""


</source>
</source>
==Verify the url submitted by user==
==Verify the url submitted by user==


[[User:Eleanorg/1.3/Dissolute Image/Code/verify input | code experiments on verifying user input]]
<!--[[User:Eleanorg/1.3/Dissolute Image/Code/verify input | code experiments on verifying user input]]-->
Scrapes the url given by the user to see if the right pixel can be found there. If yes, that url gets associated with the appropriate pixel in the db so it no longer comes up for adoption.
Scrapes the url given by the user to see if the right pixel can be found there. If yes, that url gets associated with the appropriate pixel in the db so it no longer comes up for adoption. The pixel is then added to the image via a system call to Imagemagick.
#TODO how to submit the pixel string to server along with the user input, without user being able to tamper with it?


<source lang="python">
<source lang="python">
Line 142: Line 174:
#-*- coding:utf-8 -*-
#-*- coding:utf-8 -*-
   
   
import cgi, os, subprocess
import cgi
import os, subprocess, re, urllib2
import cgitb; cgitb.enable()
import cgitb; cgitb.enable()
import pymongo  
import pymongo  
from pymongo import Connection
from pymongo import Connection
 
# recieves url from inputForm.html scrapes it to check if pixel has been put there correctly
# recieves url from inputForm.html scrapes it to check if pixel has been put there correctly
# if yes = updates db entry for that pixel
# if yes = updates db entry for that pixel
Line 160: Line 193:
     <title>A form talking to a python script</title>
     <title>A form talking to a python script</title>
         <link <link rel="stylesheet" href="../../pixels.css">
         <link <link rel="stylesheet" href="../../pixels.css">
        <link href='http://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
   </head>
   </head>
   <body>
   <body>
    <div class="container txt" style="margin-top:100px;">"""
  <h1>the DISSOLUTE IMAGE</h1>
  <div class="main">
<div class="menu">
<ul class="menuList">
<li><a href="../mongo/pixelsShowImage.cgi">Home</a></li>
<li><a href="../../forbiddenPixels/pixelsAbout.html">About</a></li>
<li><a href="../cgi-bin/mongo/pixelsShowUnadoptedPixel.cgi">Host a Pixel</a></li>
</ul>
</div>
  <div class="rightBox">
    """
    
    
htmlFooter = """
htmlFooter = """
      </div>
 
  </div>
  </div>
   </body>
   </body>
</html>"""
</html>"""


error = """Sorry, your pixel details couldn't be found at that URL! <br />
scrapingError = """Sorry, your pixel details couldn't be found at that URL! <br />
          <li>Did you paste it exactly as it appears here?</li>
<ul>
          <li>Is the page where you pasted it publicly accessible?</li>
<li>Did you paste them exactly as they appear?</li>
<li>Did you give the URL for the specific page or tweet where you pasted them?</li>
<li>Is the page where you pasted them publicly accessible?</li>
</li>
<br />
Use your browser's back button to try again, or <a href="pixelsShowUnadoptedPixel.cgi">try another pixel</a>.
       """
       """
verifyError = """Sorry, the details you've put online for that pixel seem to be wrong. <br />
thankyou = """Thanks, URL submitted. <br />
<ul>
              Your pixel has been added to the image."""
<li>Did you paste the pixel details exactly as they appear?</li>
</ul>
<br />
Use your browser's back button to try again, or <a href="pixelsShowUnadoptedPixel.cgi">try another pixel</a>."""
             
thankyou = """<strong>Thanks, URL submitted.</strong><br /><br />
Your pixel has been added to the image,<br /> and will remain there as long as you keep your pixel details online."""
   
   
#------------- get URL from input form -------------------#
#------------- get URL from input form -------------------#
   
   
form = cgi.FieldStorage() # Grabs whatever input comes from form
form = cgi.FieldStorage() # Grabs whatever input comes from form
string = form.getvalue("pixel")
#TODO check if valid url/protocol given. urllib2 bit breaks if not.
url = form.getvalue("url", "http://ox4.org/~nor/trials/hostedString.html")  # assigns form's input to var 'url'. url on the right is a default value that will be printed for testing if nothing is recieved from the form  
url = form.getvalue("url", "http://ox4.org/~nor/trials/hostedString.html")  # assigns form's input to var 'url'. url on the right is a default value that will be printed for testing if nothing is recieved from the form  


#TODO get unique pixel string along with the form. how?
#for testing:
# pat = 'unique pixel string'
#string = r"ID=65;x=4;y=3;col=red"
#url = "http://ox4.org/~nor/trials/hostedString.html"
 
#------------- print html header--------------------------#
 
print "Content-Type: text/html"
print
print htmlHeader


#------------- scrape url for the specified pixel---------#
# if not found, throw error
# if found, print thankyou and update db


#------------ define splitting function-------------------#
# to split user's string into a hash which can be verified against the one in db


text = urllib2.urlopen(url).read() # reads page at the specified URL
def splitString (stg) :
pat = r"the correct pixel string" # pattern to be matched is the pixel string associated with input form
    pat = re.compile("(\w{1,4}=[^;]+);?") # captures each foo=blah pair in the string, separated by ;s
# string to be matched must be marked up with capture ()s thus: Pixel position:(\d\d\d).(\d\d\d)\;\ Color:(rgba\(.*\))
    cap = pat.findall(stg)                  # cap variable contains all four captures - id, x, y, color (if valid)
print "Content-Type: text/html"
    print
    # put captures into a hash for this pixel
     print htmlHeader
    myhash = {}
    for s in cap :
#        print s
        k,v = s.split('=') # splits each capture on the = into key and value
myhash[k] = v # puts new k/v pair into hash with these values
    # return hash so it can be compared with that in the db
    try :
        myhash['ID'] and myhash['x'] and myhash['y'] and myhash['col']
    except:
        return # missing parameter! return nothing
     return myhash  # returns a hash as above, accessed thus: split['x'] etc
      
      
if not re.search(pat, text): # if pattern 'pat' (ie unique pixel string) isn't matched within 'text'
    print error # print error message to user
else: 
    print thankyou
    connection = Connection()
    myDB = connection['pixelDatabaseTest4']
    collection = myDB.collection 
    collection.update( {"string":pat}, {"$set":{"url": url}}) # set pixel with string matching 'pat' to url given by user
      
      
#print splitString(string)
#   
##------------- scrape and check the url -----------------#
## if correct string not found, throw error
## if found, print thankyou and update db
#connect to db for verification, and possible updating
connection = Connection()
myDB = connection['pixelDbQuery1']
collection = myDB.collection 
text = urllib2.urlopen(url).read() # reads page at the specified URL


print htmlFooter
# TODO change regex method to only scrape the first instance of string on a page
if not re.search(string, text): # if string isn't matched within 'text'
    print scrapingError         # print error message to user
else: 


#---------------- trigger pixelsCheckDb.py -----------#
    split = splitString(string) # calls split string function, passing it the string recieved from the input form, and assigns it to var 'split'
    if split:
        idNo = int(split['ID'])         # get idNo according to user's string; cast as int to compare with db
        pixelHash = myDB.collection.find_one({'ID': idNo})  # this grabs a hash with the right id number (if valid)
        if pixelHash:
        # now check if attributes from string recieved (xpos, ypos) match attributes for that ID in DB? 
            if split['x'] == pixelHash['xpos'] and split['y'] == pixelHash['ypos']:
                # print "correct x and y value given"
                collection.update( {'ID': idNo}, {"$set":{'url': url}}) # set pixel with string matching 'pat' to url given by user
                # draw a new pixel onto the img with a syscall
                color = split['col']
                x = str(split['x'])
                y = str(split['y'])
               
                command = """convert ../../forbiddenPixels/images/dissolute1.png -fill '""" + color + """' -draw 'point """ + x + "," + y + """' ../../forbiddenPixels/images/dissolute2.png"""                     
                #print command           
                os.popen(command, 'r').read()
                print thankyou
            else:
                print verifyError
        else: print verifyError
           
    else:
          print verifyError


print htmlFooter


command = "python pixelsCheckDB.py" # script called here must be executable!
os.popen(command, 'r').read()
</source>
</source>


==Check database for accuracy==
==Periodic check and re-draw to flush invalid urls==
This script is triggered every time a new pixel is adopted (should maybe be run more regularly tho - cron job?). It scrapes each pixel's url in the db and removes it if the correct string is no longer found there.
This script checks the database to see if urls can still be scraped for a valid string. If not, they are removed and their pixel disappears from the image.
 
Pipe to bash to redraw the image with Imagemagick.


<source lang="python">
<source lang="python">
#!/usr/bin/python
#-*- coding:utf-8 -*-
import pymongo, urllib2, glob
from pymongo import Connection
import re
## loops thru db. finds all entries (ie pixels) with an associated url. all that have a valid url are sent to imagemagick command to re-draw the image; invalid ones are removed.
##---------------------- connect to db:
connection = Connection()
myDB = connection['pixelDbQuery1']
collection = myDB.collection 
##---------------------- find all entries with a url:
valid = [] # adopted will be a list of hashes.
for entry in myDB.collection.find( {"url" : { "$ne" : "" } }): # $ne returns all where url is not equal to empty
url = entry["url"]
string = "ID=" + str(entry["ID"]) + ";x=" + str(entry['xpos']) + ";y=" + str(entry['ypos']) + ";col=" + entry['color']
text = urllib2.urlopen(url).read() # reads page at the specified URL
if not re.search(string, text): # TODO change regex method to only scrape the first instance of string on a page
  collection.update( {'url': url}, {"$set":{'url': ""}})     # if the exact string, matching db values, not found, the url is removed from db
else: 
valid.append(entry)
# if all is good, add this pixel's hash to the 'adopted' list
   
   
##---------------------- loop through valid values, drawing onto image     
# prints bash commands; pipe this script to bash
# [0]['url'] << this accesses the url of the first pixel in 'valid'
images = glob.glob('../../forbiddenPixels/images/*')
current = '%05d' % len(images) # counts number of files in images folder to find out latest img filename
new = '%05d' % (int(current) + 1) # converts to 5 digits. note: this changes type from int to str
print "convert ../../forbiddenPixels/images/00001.png \\" # starts from original black image, making the image from scratch
for entry in valid:
                print """-fill '""" + entry["color"] + """' -draw 'point """ + entry["xpos"] + "," + entry["ypos"] + "' \\"                       
print "../../forbiddenPixels/images/" + new + ".png"   
</source>
</source>
==Draw new image==
For every pixel in the db which has a url associated, a pixel is drawn onto the original blank image. Maybe this should be merged with script above - so checking & drawing are done at once? Saves looping thru db more times than necessary. (If url is valid, draw on pixel. If not, remove url from db.)

Latest revision as of 15:09, 3 August 2012

August 2012

Code below is the prototype shown at WORM in July 2012. I'm now re-working how the pixels are embedded so that users will be given an image file to host, rather than a boring old string.
Image embedding: code experiments

Make database of pixels

Splits up image into pixels (and their associated info) with imageMagick, then inserts each one as a hash in a Mongo database. To be run once only.

#!/usr/bin/python
#-*- coding:utf-8 -*-

# this script grabs pixel data from imagemagick & creates the mongo database of pixels. to be run once.

import os, re
import pymongo  #the library that serves as python interface to mongo database system
from pymongo import Connection


#--------- create database --------------------------------#	

connection = Connection()
myDB = connection['pixelDbQuery1']
collection = myDB.collection  					#tables in Mongo are called 'collections'. variable name on the left can be anything.


#--------- determine image dimensions-----------------------#	

image = "thatwouldbetelling!"
sizeQuery = "identify -format '%w %h' " + image			# system command gets image dimensions with ImageMagick
size = os.popen(sizeQuery, 'r').read()				# captures output of system call
(width, height) = size.split()					# splits ImageMagick output into separate column & row no's
columns = int(width)
rows = int(height)

#print columns
#print rows


##--------- assign pixel details to database-----------------#		


def getcolors ():
    ID = 0
    for row in range (0, rows):					# for each row in the image...		
        for column in range (0, columns):			# for each column in the row...
            ID = ID + 1
            colorQuery = "convert " + image + " -format '%[pixel:p{" + str(column) + "," + str(row) + "}]' info:-"
            colorResult = os.popen(colorQuery, 'r').read()	# makes & captures output of system call
            rgbResult = re.sub("\n", "", colorResult)			# strips newline character from end of sys call result
            pat = r"(\d\d\d),(\d\d\d),(\d\d\d),"		# use dirty dirty regex to manually convert rgb result to a tuple
            for m in re.finditer(pat,rgbResult):		
                r = int((m.group(1)))
                g = int((m.group(2)))
                b = int((m.group(3)))
            RGB = r,g,b	
            hexa = "".join(map(chr, RGB)).encode('hex')		# converts tuple from rgb form to hex value	
            color = re.sub(hexa, "#"+hexa, hexa)		# replaces hex value with the same value plus a leading #
            pixelHash = {'ID': ID, 'xpos': str(column), 'ypos': str(row), 'color': color, 'url':"" }
            collection.insert(pixelHash)			# insert this pixel into the db
            

getcolors()

Give user an unadopted pixel

Finds all the pixels in the db with no url associated. Picks one at random and gives it to the user, with an input form for them to enter the url where they have put it.

#!/usr/bin/python
#-*- coding:utf-8 -*-

import cgi
import cgitb; cgitb.enable()
import pymongo, random  
from pymongo import Connection

## grab a random unadopted pixel from the database and give user a unique string for it

connection = Connection()
myDB = connection['pixelDbQuery1']

#--------- generate pixel string ------------#

# find all entries where url is empty:
unadopted = []
for entry in myDB.collection.find({"url": ""}):
    unadopted.append(entry)			# add this pixel's hash as an item to the 'unadopted' dictionary
#print unadopted

howMany = len(unadopted)			# find out how many items in 'unadopted' list
#print howMany
random = random.randint(0,howMany)		# pick a random number in this range
#print random
pixelHash = unadopted[random]			# ...and choose the pixel at this index
#print pixelHash

pixelString = "ID=" + str(pixelHash['ID']) + ";x=" + pixelHash['xpos'] + ";y=" + pixelHash['ypos'] + ";col=" + pixelHash['color']
#print pixelString


#--------- print input form with pixel string ------------#

htmlHeader = """<!DOCTYPE html>
<html>
  <head>
    <title>Adopt a Pixel</title>
        <link <link rel="stylesheet" href="../../pixels.css">
        <link href='http://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
  </head>
  <body>"""
 
 
print "Content-Type: text/html"
print 
print htmlHeader
print """
<h1>the DISSOLUTE IMAGE</h1>

<div class="main">
	<div class="menu">
		<ul class="menuList">
			<li><a href="pixelsShowImage.cgi">Home</a></li>
			<li><a href="../../forbiddenPixels/pixelsAbout.html">About</a></li>
			<li>Host a Pixel</li>
		</ul>
	</div>
</div>
<div class="heading">Host a Pixel</div>

<div class="rightBox" style="">

<div class="pixelInfo">
You'll be hosting pixel <strong>""" + str(pixelHash['ID']) + """</strong> out of a total 95600. Enlarged preview: 
<div id="pixelPreview" style="background-color: """ + pixelHash['color'] + """">
</div>

<div class="pixelDetails">
Here are the unique details for your pixel: <br />
</div>

<form action="pixelsScrapeAndVerify.cgi" name="inputForm">  
    <input name="pixel" class="pixelInput" value=""" + pixelString + """><br />   

<div class="inputBox">
    To host this pixel, just copy & paste the details above<br /> somewhere public on the web, exactly as they appear.<br />
    Then tell us the full URL of the page where you pasted them:<br />
</div>
    </span>
    URL: <input name="url" class="urlInput" value="">
    <input type="submit" value="OK">
</form>



  <div class="">
Your pixel will appear in the image for as long as the text remains at this URL.
  </div>
</div>

</body>
</html>"""

Verify the url submitted by user

Scrapes the url given by the user to see if the right pixel can be found there. If yes, that url gets associated with the appropriate pixel in the db so it no longer comes up for adoption. The pixel is then added to the image via a system call to Imagemagick.

#!/usr/bin/python
#-*- coding:utf-8 -*-
 
import cgi
import os, subprocess, re, urllib2
import cgitb; cgitb.enable()
import pymongo 
from pymongo import Connection

# recieves url from inputForm.html scrapes it to check if pixel has been put there correctly
# if yes = updates db entry for that pixel
# if no = throws error
 
 

#-------------- error / thank you messages ----------------#
 
htmlHeader = """<!DOCTYPE html>
<html>
  <head>
    <title>A form talking to a python script</title>
        <link <link rel="stylesheet" href="../../pixels.css">
        <link href='http://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
  </head>
  <body>
  <h1>the DISSOLUTE IMAGE</h1>
  <div class="main">
	<div class="menu">
		<ul class="menuList">
			<li><a href="../mongo/pixelsShowImage.cgi">Home</a></li>
			<li><a href="../../forbiddenPixels/pixelsAbout.html">About</a></li>
			<li><a href="../cgi-bin/mongo/pixelsShowUnadoptedPixel.cgi">Host a Pixel</a></li>
		</ul>
	</div>
  <div class="rightBox">
     """
  
htmlFooter = """
  
  </div>
  </div>
   </body>
</html>"""

scrapingError = """Sorry, your pixel details couldn't be found at that URL! <br />
<ul>
<li>Did you paste them exactly as they appear?</li>
<li>Did you give the URL for the specific page or tweet where you pasted them?</li>
<li>Is the page where you pasted them publicly accessible?</li>
</li>
<br />
Use your browser's back button to try again, or <a href="pixelsShowUnadoptedPixel.cgi">try another pixel</a>.
       """
verifyError = """Sorry, the details you've put online for that pixel seem to be wrong. <br />
<ul>
<li>Did you paste the pixel details exactly as they appear?</li>
</ul>
<br />
Use your browser's back button to try again, or <a href="pixelsShowUnadoptedPixel.cgi">try another pixel</a>."""
               
thankyou = """<strong>Thanks, URL submitted.</strong><br /><br />
Your pixel has been added to the image,<br /> and will remain there as long as you keep your pixel details online."""
 
#------------- get URL from input form -------------------#
 
form = cgi.FieldStorage()			# Grabs whatever input comes from form
string = form.getvalue("pixel")
#TODO check if valid url/protocol given. urllib2 bit breaks if not.
url = form.getvalue("url", "http://ox4.org/~nor/trials/hostedString.html")  # assigns form's input to var 'url'. url on the right is a default value that will be printed for testing if nothing is recieved from the form 

#for testing:
#string = r"ID=65;x=4;y=3;col=red" 
#url = "http://ox4.org/~nor/trials/hostedString.html"

#------------- print html header--------------------------#

print "Content-Type: text/html"
print 
print htmlHeader


#------------ define splitting function-------------------#
# to split user's string into a hash which can be verified against the one in db

def splitString (stg) :
    pat = re.compile("(\w{1,4}=[^;]+);?") 	# captures each foo=blah pair in the string, separated by ;s
    cap = pat.findall(stg)                   	# cap variable contains all four captures - id, x, y, color (if valid)
	
    # put captures into a hash for this pixel
    myhash = {}
    for s in cap :
#        print s
        k,v = s.split('=') 	# splits each capture on the = into key and value
	myhash[k] = v		# puts new k/v pair into hash with these values
 
    # return hash so it can be compared with that in the db
    try :
        myhash['ID'] and myhash['x'] and myhash['y'] and myhash['col']
    except:
        return # missing parameter! return nothing
    return myhash   # returns a hash as above, accessed thus: split['x'] etc
    
    
#print splitString(string)

#    
##------------- scrape and check the url -----------------#

## if correct string not found, throw error
## if found, print thankyou and update db

#connect to db for verification, and possible updating
connection = Connection()
myDB = connection['pixelDbQuery1']
collection = myDB.collection  



text = urllib2.urlopen(url).read()		# reads page at the specified URL

# TODO change regex method to only scrape the first instance of string on a page
if not re.search(string, text):			# if string isn't matched within 'text'				
    print scrapingError			        # print error message to user
else:   

    split = splitString(string)			# calls split string function, passing it the string recieved from the input form, and assigns it to var 'split'
    if split:
        idNo = int(split['ID'])		        # get idNo according to user's string; cast as int to compare with db
        pixelHash = myDB.collection.find_one({'ID': idNo})   # this grabs a hash with the right id number (if valid)
        if pixelHash:			
        # now check if attributes from string recieved (xpos, ypos) match attributes for that ID in DB?  
            if split['x'] == pixelHash['xpos'] and split['y'] == pixelHash['ypos']:
                # print "correct x and y value given"
                collection.update( {'ID': idNo}, {"$set":{'url': url}}) # set pixel with string matching 'pat' to url given by user
                # draw a new pixel onto the img with a syscall
                color = split['col']
                x = str(split['x'])
                y = str(split['y'])
                
                command = """convert ../../forbiddenPixels/images/dissolute1.png -fill '""" + color + """' -draw 'point """ + x + "," + y + """' ../../forbiddenPixels/images/dissolute2.png"""             	           	
                #print command             
                os.popen(command, 'r').read()
                print thankyou
            else:
                print verifyError
        else: print verifyError
             
    else:
          print verifyError

print htmlFooter

Periodic check and re-draw to flush invalid urls

This script checks the database to see if urls can still be scraped for a valid string. If not, they are removed and their pixel disappears from the image.

Pipe to bash to redraw the image with Imagemagick.

#!/usr/bin/python
#-*- coding:utf-8 -*-

import pymongo, urllib2, glob
from pymongo import Connection
import re


## loops thru db. finds all entries (ie pixels) with an associated url. all that have a valid url are sent to imagemagick command to re-draw the image; invalid ones are removed.

##---------------------- connect to db:

connection = Connection()
myDB = connection['pixelDbQuery1']
collection = myDB.collection  

 
##---------------------- find all entries with a url:

valid = []							# adopted will be a list of hashes. 
for entry in myDB.collection.find( {"url" : { "$ne" : "" } }):		# $ne returns all where url is not equal to empty
	url = entry["url"]
	string = "ID=" + str(entry["ID"]) + ";x=" + str(entry['xpos']) + ";y=" + str(entry['ypos']) + ";col=" + entry['color']
	text = urllib2.urlopen(url).read()		# reads page at the specified URL
	if not re.search(string, text):			# TODO change regex method to only scrape the first instance of string on a page			
   		collection.update( {'url': url}, {"$set":{'url': ""}})	     	# if the exact string, matching db values, not found, the url is removed from db
	else:   
		valid.append(entry)
										# if all is good, add this pixel's hash to the 'adopted' list

    
    
##---------------------- loop through valid values, drawing onto image       			
# prints bash commands; pipe this script to bash
# [0]['url'] << this accesses the url of the first pixel in 'valid'

images = glob.glob('../../forbiddenPixels/images/*')
current = '%05d' % len(images)						# counts number of files in images folder to find out latest img filename
new = '%05d' % (int(current) + 1)					# converts to 5 digits. note: this changes type from int to str

print "convert ../../forbiddenPixels/images/00001.png \\"	# starts from original black image, making the image from scratch
for entry in valid:
                print """-fill '""" + entry["color"] + """' -draw 'point """ + entry["xpos"] + "," + entry["ypos"] + "' \\"             	           	  
print "../../forbiddenPixels/images/" + new + ".png"