Advertisement
Guest User

Untitled

a guest
Mar 26th, 2015
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 170.15 KB | None | 0 0
  1. #You can edit these values, but they lack error checking so be careful
  2. def defaults():
  3.  
  4.     #These values will override any given to the script, set any 'force' value to True to use the corresponding settings below
  5.     forceCustomFilename = False
  6.     forceCustomImages = False
  7.     forceUpload = False
  8.     forceOpenImageOnUpload = False
  9.     forceDisableSaving = False
  10.     forceCacheWrite = False
  11.     forceVerify = False
  12.    
  13.     customFilename = "ImageStore.png" #May include a path
  14.     customImage = None #Set to None to disable, or give a path
  15.     shouldUpload = True
  16.     shouldOpenImageOnUpload = False
  17.     shouldDisableSaving = False
  18.     shouldWriteCache = True
  19.        
  20.     #Saving the image
  21.     defaultImageName = "ImageDataStore.png"
  22.     defaultImageDirectory = GlobalValues.userDirectory
  23.    
  24.     #Saving the cache
  25.     defaultCacheName = "ImageStore.cache"
  26.     defaultCacheDirectory = GlobalValues.pythonDirectory
  27.    
  28.     #Displaying a percentage of completion on long calculations
  29.     outputProgressIterations = 2**12 #Check time after this many calculations
  30.     outputProgressTime = 0.25 #Output progress after this many seconds
  31.    
  32.     output = [[defaultImageName, defaultImageDirectory]]
  33.     output.append( [defaultCacheName, defaultCacheDirectory] )
  34.     output.append( [outputProgressTime, outputProgressIterations] )
  35.     disableList = [[forceCustomFilename, customFilename]]
  36.     disableList.append( [forceCustomImages, customImage] )
  37.     disableList.append( [forceUpload, shouldUpload] )
  38.     disableList.append( [forceOpenImageOnUpload, shouldOpenImageOnUpload] )
  39.     disableList.append( [forceDisableSaving, shouldDisableSaving] )
  40.     disableList.append( [forceCacheWrite, shouldWriteCache] )
  41.     output.append( disableList )
  42.     return output
  43.    
  44. try:
  45.     from PIL import Image
  46. except:
  47.     raise ImportError( "Python Imaging Library module was not found" )
  48. from subprocess import call
  49. from time import time, sleep
  50. from datetime import datetime
  51. import cPickle, base64, urllib2, cStringIO, os, webbrowser, zipfile, getpass, zlib, operator, re, math, md5, itertools, inspect, random
  52.  
  53. #Disable upload features if requests and pyimgur are not found
  54. printImportError = True #Set this to false if you want to disable the warning if pyimgur or requests are not found
  55. global overrideUpload
  56. try:
  57.     import pyimgur, requests
  58.     overrideUpload = False
  59. except:
  60.     outputText = "Warning: Error importing pyimgur{0}, disabling the upload features."
  61.     try:
  62.         import requests
  63.         outputText = outputText.format( "" )
  64.     except:
  65.         outputText = outputText.format( " and requests" )
  66.     if printImportError:
  67.         print outputText
  68.     overrideUpload = True
  69.  
  70. #Check if running from Maya
  71. global mayaEnvironment
  72. mayaEnvironment = False
  73. try:
  74.     import pymel.core as py
  75.     import maya.utils as utils
  76.     mayaEnvironment = True
  77. except:
  78.     pass
  79.  
  80. #Other fixed global values
  81. class GlobalValues:
  82.     newLine = os.linesep
  83.     pythonDirectory = os.getcwd().replace( "\\", "/" )
  84.     userDirectory = os.path.expanduser( "~" ).replace( "\\", "/" )
  85.  
  86. class ImageStore:
  87.    
  88.     startTime = time()
  89.     defaultValues = defaults()
  90.     defaultImageName = defaultValues[0][0]
  91.     defaultImageDirectory = defaultValues[0][1]
  92.     defaultCacheName = defaultValues[1][0]
  93.     defaultCacheDirectory = defaultValues[1][1]
  94.     outputProgressTime = defaultValues[2][0]
  95.     outputProgressIterations = defaultValues[2][1]
  96.     forceCustomFilenames = defaultValues[3][0][0]
  97.     useThisCustomFilename = defaultValues[3][0][1]
  98.     forceCustomImages = defaultValues[3][1][0]
  99.     useThisCustomImage = defaultValues[3][1][1]
  100.     forceUpload = defaultValues[3][2][0]
  101.     shouldUpload = defaultValues[3][2][1]
  102.     forceOpenOnUpload = defaultValues[3][3][0]
  103.     shouldOpenOnUpload = defaultValues[3][3][1]
  104.     forceDeleteFile = defaultValues[3][4][0]
  105.     shouldDeleteFile = defaultValues[3][4][1]
  106.     forceCacheWrite = defaultValues[3][5][0]
  107.     shouldWriteCache = defaultValues[3][5][1]
  108.                
  109.     imageDataPadding = [116, 64, 84, 123, 93, 73, 106]
  110.     firstPixelPadding = [92, 101]
  111.     versionNumber = "3.2.2"
  112.     maxCutoffModes = 7
  113.     website = "http://peterhuntvfx.co.uk"
  114.     protocols = ["http://", "https://"]
  115.     debugging = True
  116.     validateWrite = False
  117.    
  118.     #Maya
  119.     renderViewSaveLocation = "{0}/RenderViewTemp".format( defaultCacheDirectory )
  120.     renderViewCaption = "Image Store Output"
  121.    
  122.     #Percent completed
  123.     writeProgress = {}
  124.     writeProgress["CalculatingInputSize"] = 0
  125.     writeProgress["InputSizeIs"] = 2
  126.     writeProgress["CheckingImage"] = 2
  127.     writeProgress["CalculatingCutoffMode"] = 63
  128.     writeProgress["UsingCutoffMode"] = writeProgress["CalculatingCutoffMode"]
  129.     writeProgress["CalculatingMaxImageData"] = 83
  130.     writeProgress["ImageCanStore"] = writeProgress["CalculatingMaxImageData"]
  131.     writeProgress["InputAtMax"] = 84
  132.     writeProgress["MinimumBitsPerPixel"] = 85
  133.     writeProgress["ChooseBitsPerPixel"] = 86
  134.     writeProgress["SetDimensions"] = 88
  135.     writeProgress["CalculatingImage"] = 95
  136.     writeProgress["SavingImage"] = 97
  137.     writeProgress["WritingExtraInformation"] = 98
  138.     writeProgress["Validate"] = 100
  139.     readProgress = {}
  140.     readProgress["ReadingImage"] = 0
  141.     readProgress["ReadingFiles"] = 6
  142.     readProgress["FilesStored"] = 8
  143.     readProgress["StoringPixels"] = 20
  144.     readProgress["FirstPixel"] = 21
  145.     readProgress["StoringCustomPixelInfo"] = 40
  146.     readProgress["ConvertingData"] = 70
  147.     readProgress["ReadingData"] = 85
  148.     readProgress["TruncatingEnd"] = 90
  149.     readProgress["Decoding"] = 100
  150.        
  151.     def __init__( self, *args, **kwargs ):
  152.    
  153.         if len( args ) == 0:
  154.             imageName = self.defaultImageName
  155.         elif args[0]:
  156.             imageName = args[0]
  157.         else:
  158.             imageName = self.defaultImageName
  159.        
  160.         if self.forceCustomFilenames:
  161.             imageName = self.useThisCustomFilename
  162.         self.imageName = imageName
  163.        
  164.         #Extra check to be safe, shouldn't be needed though
  165.         if not self.imageName:
  166.             self.imageName = self.defaultImageName
  167.        
  168.         self.renderViewCheck = checkInputs.capitalLetterCombinations( "Render View" )
  169.        
  170.         self.originalFormat = None
  171.         if "." in self.imageName:
  172.             self.originalFormat = self.imageName.split( "." )[-1]
  173.        
  174.         if ".".join( self.imageName.split( "." )[:-1] ) not in self.renderViewCheck or not mayaEnvironment:
  175.    
  176.             self.imageName = "{0}.png".format( str( imageName ).replace( "\\", "/" ).rsplit( '.', 1 )[0] )
  177.            
  178.             if "/" not in self.imageName:
  179.                 self.imageName = "{0}/{1}".format( self.defaultImageDirectory, self.imageName )
  180.                
  181.             if self.imageName[-1:] == ":":
  182.                 self.imageName += "/"
  183.                
  184.             if self.imageName[-1:] == "/":
  185.                 self.imageName += self.defaultImageName
  186.        
  187.         self.kwargs = kwargs
  188.         self.printProgress = checkInputs.checkBooleanKwargs( kwargs, True, 'p', 'print', 'printProgress', 'printOutput', 'o', 'output', 'outputProgress' )
  189.         self.cleanTemporaryFiles = checkInputs.checkBooleanKwargs( kwargs, True, 'c', 'cleanFiles', 'tempFiles', 'cleanTempFiles', 'temporaryFiles', 'cleanTemporaryFiles' )
  190.        
  191.         #Write image information to cache, can speed up code execution by a lot
  192.         self.writeToINI = checkInputs.checkBooleanKwargs( kwargs, True, 'DB', 'INI', 'cache', 'writeDB', 'writeINI', 'writeCache', 'writeToDB', 'writeDatabase', 'writeToCache', 'self.writeToINI', 'writeToDatabase' )
  193.         if self.forceCacheWrite:
  194.             self.writeToINI = self.shouldWriteCache
  195.        
  196.         #For updating progress
  197.         if mayaEnvironment:
  198.             validArgs = checkInputs.validKwargs( kwargs, 'scrollField', 'scrollFieldToUpdate' )
  199.             self.scrollFieldToUpdate = None
  200.             for i in xrange( len( validArgs ) ):
  201.                 try:
  202.                     py.scrollField( kwargs[validArgs[i]], query = True, text = True )
  203.                     self.scrollFieldToUpdate = kwargs[validArgs[i]]
  204.                     break
  205.                 except:
  206.                     pass
  207.                    
  208.             validArgs = checkInputs.validKwargs( kwargs, 'progressBar', 'progressBarName' )
  209.             self.progressBar = None
  210.             for i in xrange( len( validArgs ) ):
  211.                 try:
  212.                     py.progressBar( kwargs[validArgs[i]], query = True, progress = True )
  213.                     self.progressBar = kwargs[validArgs[i]]
  214.                     break
  215.                 except:
  216.                     pass
  217.                    
  218.             validArgs = checkInputs.validKwargs( kwargs, 'progressBarText' )
  219.             self.progressBarText = None
  220.             for i in xrange( len( validArgs ) ):
  221.                 try:
  222.                     py.text( kwargs[validArgs[i]], query = True, label = True )
  223.                     self.progressBarText = kwargs[validArgs[i]]
  224.                     break
  225.                 except:
  226.                     pass
  227.                    
  228.             validArgs = checkInputs.validKwargs( kwargs, 'callbackWrite', 'callbackWriteCommand', 'deferredWrite', 'deferredWriteCommand' )
  229.             self.callbackWrite = None
  230.             for i in xrange( len( validArgs ) ):
  231.                 try:
  232.                     if inspect.ismethod( kwargs[validArgs[i]] ):
  233.                         self.callbackWrite = kwargs[validArgs[i]]
  234.                         break
  235.                 except:
  236.                     pass
  237.                    
  238.             validArgs = checkInputs.validKwargs( kwargs, 'callbackRead', 'callbackReadCommand', 'deferredRead', 'deferredReadCommand' )
  239.             self.callbackRead = None
  240.             for i in xrange( len( validArgs ) ):
  241.                 try:
  242.                     if inspect.ismethod( kwargs[validArgs[i]] ):
  243.                         self.callbackRead = kwargs[validArgs[i]]
  244.                         break
  245.                 except:
  246.                     pass
  247.        
  248.        
  249.        
  250.     def getImageLocation( self, input ):
  251.        
  252.         if mayaEnvironment and input in self.renderViewCheck:
  253.             self.renderView( True )
  254.             imageLocation = self.renderViewSaveLocation
  255.             self.originalFormat = self.imageFormats()[0][py.getAttr( "defaultRenderGlobals.imageFormat" )][0]
  256.            
  257.         else:
  258.             imageLocation = input
  259.        
  260.         if self.readImage( imageLocation ):
  261.             return imageLocation
  262.         else:
  263.             return None
  264.    
  265.     def updateMayaUI( self, text, display, percentComplete ):
  266.    
  267.         if self.progressBar:
  268.             if not percentComplete:
  269.                 percentComplete = py.progressBar( self.progressBar, query = True, progress = True )
  270.             py.progressBar( self.progressBar, edit = True, progress = percentComplete )
  271.            
  272.         if display:
  273.        
  274.             if self.progressBarText:
  275.                 py.text( self.progressBarText, edit = True, label = text )
  276.                
  277.             if self.scrollFieldToUpdate:
  278.                 currentText = py.scrollField( self.scrollFieldToUpdate, query = True, text = True )
  279.                 currentText = "{0}{1}{2}".format( text, GlobalValues.newLine, currentText )
  280.                 py.scrollField( self.scrollFieldToUpdate, edit = True, text = currentText )
  281.    
  282.     def printCurrentProgress( self, text, display=True, percentComplete=None ):
  283.    
  284.         if not self.validateWrite:
  285.             if mayaEnvironment:
  286.                
  287.                 self.updateMayaUI( text, display, percentComplete )
  288.                
  289.             if self.printProgress:
  290.                 print text
  291.                    
  292.    
  293.     def cleanTempFiles( self ):
  294.    
  295.         if self.cleanTemporaryFiles:
  296.             self.renderView( False )
  297.  
  298.     def write( self, *args, **kwargs ):
  299.        
  300.         if mayaEnvironment:
  301.             if self.progressBarText:
  302.                 py.text( self.progressBarText, edit = True, label = "Setting up variables..." )
  303.             if self.progressBar:
  304.                 py.progressBar( self.progressBar, edit = True, progress = 0 )
  305.                
  306.         results = self.actualWrite( *args, **kwargs )
  307.         self.cleanTempFiles()
  308.        
  309.         return results
  310.  
  311.     def read( self, *args, **kwargs ):
  312.        
  313.         if mayaEnvironment:
  314.             try:
  315.                 if not self.validateWrite:
  316.                     py.progressBar( self.progressBar, edit = True, progress = 0 )
  317.             except:
  318.                 pass
  319.         results = self.actualRead( *args, **kwargs )
  320.         self.cleanTempFiles()
  321.        
  322.         return results
  323.        
  324.     def actualWrite( self, *args, **kwargs ):
  325.    
  326.         #self.printCurrentProgress( "Setting up variables...", True, 0 )
  327.    
  328.         input = None
  329.         if args:
  330.             input = args[0]
  331.         else:
  332.             validArgs = checkInputs.validKwargs( kwargs, 'input', 'inputData' )
  333.             for i in xrange( len( validArgs ) ):
  334.                 try:
  335.                     input = kwargs[validArgs[i]]
  336.                     if input:
  337.                         break
  338.                 except:
  339.                     pass
  340.                    
  341.         #If image should be uploaded
  342.         upload = checkInputs.checkBooleanKwargs( kwargs, False, 'u', 'upload', 'uploadImage' )
  343.         if overrideUpload:
  344.             upload = False
  345.         elif self.forceUpload:
  346.             upload = self.shouldUpload
  347.        
  348.         openImage = checkInputs.checkBooleanKwargs( kwargs, True, 'o', 'open', 'openImage', 'openUpload', 'openUploaded', 'openUploadImage', 'openUploadedImage' )
  349.         if self.forceOpenOnUpload:
  350.             openImage = self.shouldOpenOnUpload
  351.        
  352.         #If information should be disabled from being displayed
  353.         disableInfo = checkInputs.checkBooleanKwargs( kwargs, False, 'd', 'disable', 'disableInfo', 'disableInformation' )
  354.        
  355.         #If custom image data should be returned but nothing else
  356.         returnCustomImageInfoPrefix = ["get", "return", "calculate", "test"]
  357.         returnCustomImageInfoMiddle = ["", "Custom" ]
  358.         returnCustomImageInfoMiddle2 = ["", "Image"]
  359.         returnCustomImageInfoSuffix = ["Info", "Information", "Size"]
  360.         returnCustomImageInfoJoined = checkInputs.joinList( returnCustomImageInfoPrefix, returnCustomImageInfoMiddle, returnCustomImageInfoMiddle2, returnCustomImageInfoSuffix )
  361.         returnCustomImageInfo = checkInputs.checkBooleanKwargs( kwargs, False, *returnCustomImageInfoJoined )
  362.        
  363.         #Final validation to read image that has just been created
  364.         validateOutput = checkInputs.checkBooleanKwargs( kwargs, False, 'v', 'cO', 'vO', 'validate', 'verify', 'verifyOutput', 'checkOutput', 'validateOutput', 'checkImage', 'validateImage', 'verifyImage' )
  365.        
  366.         #Delete file after creation
  367.         deleteImage = checkInputs.checkBooleanKwargs( kwargs, False, 'dI', 'deleteImage', 'removeImage', 'disableSaving', 'noSave', 'noSaving', 'uploadOnly' )
  368.         if self.forceDeleteFile:
  369.             deleteImage = self.shouldDeleteFile
  370.        
  371.         #Output all input data as black to debug
  372.         debugData = checkInputs.checkBooleanKwargs( kwargs, False, 'debug', 'debugData', 'debugResult', 'debugOutput' )
  373.         if debugData:
  374.             padWithRandomData = False
  375.             validateOutput = False
  376.         else:
  377.             padWithRandomData = True
  378.        
  379.         #If a link to the custom image should be returned
  380.         returnCustomImageURL = checkInputs.checkBooleanKwargs( kwargs, False, 'returnURL', 'returnCustomURL', 'returnCustomImageURL' )
  381.        
  382.         #If it should just output the size of input
  383.         outputSizePrefix = ["return", "test", "get", "calculate"]
  384.         outputSizeMiddle = ["Output", "Input"]
  385.         outputSizeSuffix = ["Size"]
  386.         outputSizeJoined = checkInputs.joinList( outputSizePrefix+[""], outputSizeMiddle+[""], outputSizeSuffix )
  387.         outputSizeJoined += checkInputs.joinList( outputSizePrefix, outputSizeMiddle, outputSizeSuffix+[""] )
  388.         outputSizeJoined += checkInputs.joinList( outputSizePrefix, outputSizeSuffix, ["OfInput"] )
  389.         outputSizeJoined = tuple( set( [self.lowercase( word ) for word in outputSizeJoined + ( "s", "iS", "oS" ) if word] ) )
  390.         outputSize = checkInputs.checkBooleanKwargs( kwargs, False, *outputSizeJoined )
  391.        
  392.         #If the custom image option should be dynamically disabled or the code stopped
  393.         revertToDefault = checkInputs.checkBooleanKwargs( kwargs, True, 'revert', 'revertToBasic', 'revertToDefault', 'revertToDefaultImage', 'revertToDefaultStyle' )
  394.        
  395.         #If all URLs should be reuploaded to Imgur
  396.         uploadURLsToImgur = checkInputs.checkBooleanKwargs( kwargs, True, 'uploadURLToImgur', 'uploadURLSToImgur', 'uploadCustomURLToImgur', 'uploadCustomURLsToImgur' )
  397.        
  398.         #[Maya only - not working correctly] Write image to render view, but loses data when it's written so don't use it
  399.         writeToRenderView = checkInputs.checkBooleanKwargs( kwargs, False, 'rV', 'renderView', 'writeRV', 'writeRenderView', 'writeToRV', 'writeToRenderView' )
  400.        
  401.         #Cutoff mode help
  402.         cutoffModeHelp = checkInputs.checkBooleanKwargs( kwargs, False, 'cH', 'cMH', 'cHelp', 'cMHelp', 'cutoffHelp', 'cutoffModeHelp' )
  403.         if cutoffModeHelp:
  404.             cutoffModeHelp = []
  405.             cutoffModeHelp.append( "Cutoff modes:" )
  406.             cutoffModeHelp.append( "These define if the values should be added or subtracted based on the value of the pixel." )
  407.             cutoffModeHelp.append( "0: Move towards 0" )
  408.             cutoffModeHelp.append( "1: Move towards 64" )
  409.             cutoffModeHelp.append( "2: Move towards 128" )
  410.             cutoffModeHelp.append( "3: Move towards 192" )
  411.             cutoffModeHelp.append( "4: Move towards 255" )
  412.             cutoffModeHelp.append( "5: Move away from 64" )
  413.             cutoffModeHelp.append( "6: Move away from 128" )
  414.             cutoffModeHelp.append( "7: Move away from 192" )
  415.             return cutoffModeHelp
  416.        
  417.         #Ratio of width to height
  418.         validArgs = checkInputs.validKwargs( kwargs, 'r', 'ratio', 'sizeRatio', 'widthRatio', 'heightRatio', 'widthToHeightRatio' )
  419.         ratioWidth = math.log( 1920 ) / math.log( 1920*1080 )
  420.        
  421.         for i in xrange( len( validArgs ) ):
  422.        
  423.             try:
  424.                 if 0 < float( str( kwargs[validArgs[i]] ) ) < 1:
  425.                     ratioWidth = float( str( kwargs[validArgs[i]] ) )
  426.                     break
  427.                    
  428.                 else:
  429.                     raise RangeError( "number not in range" )
  430.                    
  431.             except:
  432.                 ratioWidth = math.log( 1920 ) / math.log( 1920*1080 )
  433.        
  434.         allOutputs = []
  435.         usedRenderViewImage = False
  436.         usedRenderView = False
  437.         customImageInputPath = ""
  438.         if not outputSize:
  439.        
  440.             #Check if custom image should be used
  441.             validArgs = checkInputs.validKwargs( kwargs, 'i', 'cI', 'img', 'image', 'URL', 'imgURL', 'imgPath', 'imgLoc', 'imgLocation', 'imageURL', 'imageLoc', 'imagePath', 'imageLocation', 'customImg', 'customURL', 'customImage', 'customImgURL', 'customImageURL', 'customImgPath', 'customImagePath', 'customImgLoc', 'customImageLoc', 'customImgLocation', 'customImageLocation' )
  442.             customImageInput = None
  443.            
  444.             #Force certain custom image
  445.             if self.forceCustomImages:
  446.                 validArgs = ["forceCustomImages"]
  447.                 kwargs["forceCustomImages"] = self.useThisCustomImage
  448.            
  449.             for i in xrange( len( validArgs ) ):
  450.            
  451.                 try:
  452.                     if not kwargs[validArgs[i]]:
  453.                         validArgs = []
  454.                         break
  455.                     customImageInput = self.readImage( kwargs[validArgs[i]] )
  456.                     if customImageInput:
  457.                         customImageInputPath = kwargs[validArgs[i]]
  458.                         break
  459.                    
  460.                     #Read from the Maya Render View window
  461.                     elif mayaEnvironment:
  462.                    
  463.                         #Check all combinations of text for render view
  464.                         if kwargs[validArgs[i]] in self.renderViewCheck:
  465.      
  466.                             #Save file
  467.                             self.renderView( True )
  468.                            
  469.                             #Get image details
  470.                             customImageInputPath = self.renderViewSaveLocation
  471.                             customImageInput = self.readImage( self.renderViewSaveLocation )
  472.                            
  473.                             usedRenderView = True
  474.                             if customImageInput:
  475.                                 usedRenderViewImage = True
  476.                                 #returnCustomImageURL = True
  477.                                 break
  478.                             else:
  479.                                 self.renderView( False )
  480.                        
  481.                 except:
  482.                     customImageInput = None
  483.                    
  484.             #Check image file path isn't URL, and set to custom image if it is
  485.             usedFilenameAsCustom = False
  486.             if any( value in self.imageName for value in self.protocols ):
  487.            
  488.                 outputText = "Error: Can't use URLs when saving an image."
  489.                
  490.                 if not customImageInput and not self.forceCustomImages:
  491.                     outputText = outputText.replace( ".", ", using URL as a custom image." )
  492.                     customImageInput = self.readImage( self.imageName )
  493.                
  494.                 self.printCurrentProgress( outputText )
  495.                    
  496.                 self.imageName = self.defaultImageName
  497.                 usedFilenameAsCustom = True
  498.                
  499.            
  500.             if ( validArgs or usedFilenameAsCustom ) and not customImageInput:
  501.                 self.printCurrentProgress( "Error: Custom image could not be read. Output image will be saved without it." )
  502.            
  503.             if not customImageInput:
  504.                 useCustomImageMethod = False
  505.             else:
  506.                 useCustomImageMethod = True
  507.                
  508.                 sizeOfImage = customImageInput.size
  509.                 #Keep same size ratio if image can't hold all the data
  510.                 ratioWidth = math.log( sizeOfImage[0] ) / math.log( sizeOfImage[0]*sizeOfImage[1] )
  511.                
  512.                 #Cutoff mode prefix
  513.                 validArgs = checkInputs.validKwargs( kwargs, 'cMP', 'cutoffModePrefix', 'cutoffModeName' )
  514.                 cutoffModePrefix = "m"
  515.                 for i in xrange( len( validArgs ) ):
  516.                     try:
  517.                         cutoffModePrefix = str( kwargs[validArgs[i]] )
  518.                         break
  519.                     except:
  520.                         pass
  521.            
  522.                 #Custom cutoff mode
  523.                 validArgs = checkInputs.validKwargs( kwargs, 'cM', 'mode', 'cutoff', 'cutoffMode', 'cutoffModes' )
  524.                 customCutoffMode = None
  525.                 validCustomCutoffModes = []
  526.                 for i in xrange( len( validArgs ) ):
  527.                     try:
  528.                         if "," in str( kwargs[validArgs[i]] ) or type( kwargs[validArgs[i]] ) == tuple:
  529.                        
  530.                             #If provided as tuple
  531.                             if type( kwargs[validArgs[i]] ) == tuple:
  532.                                 customModeList = kwargs[validArgs[i]]
  533.                                        
  534.                             #If provided as string
  535.                             else:
  536.                                 customModeList = kwargs[validArgs[i]].replace( "(", "" ).replace( ")", "" ).split( "," )
  537.                                        
  538.                             #Build list of all values
  539.                             for j in xrange( len( customModeList ) ):
  540.                                 try:
  541.                                     customCutoffMode = int( customModeList[j] )
  542.                                     if 0 < customCutoffMode < self.maxCutoffModes+1:
  543.                                         validCustomCutoffModes.append( customCutoffMode )
  544.                                 except:
  545.                                     customCutoffMode = None
  546.                                    
  547.                             if validCustomCutoffModes:
  548.                                 break
  549.                            
  550.                         else:
  551.                             customCutoffMode = int( kwargs[validArgs[i]] )
  552.                             if 0 < customCutoffMode < self.maxCutoffModes+1:
  553.                                 break
  554.                             else:
  555.                                 customCutoffMode = None
  556.                                
  557.                     except:
  558.                         customCutoffMode = None
  559.                
  560.                 #Run code on final cutoff number
  561.                 if validCustomCutoffModes:
  562.                     customCutoffMode = validCustomCutoffModes[-1]
  563.                
  564.                 #If image should be output with all cutoff modes
  565.                 allCutoffModes = checkInputs.checkBooleanKwargs( kwargs, False, 'a', 'all', 'aCM', 'allCutoff', 'allCutoffs', 'allModes', 'allCutoffMode', 'allCutoffModes' )
  566.                
  567.                 #Automatically set custom cutoff modes to all and disable reverting to the default method if image can't hold data
  568.                 if allCutoffModes:
  569.                     validCustomCutoffModes = range( self.maxCutoffModes+1 )
  570.                     revertToDefault = False
  571.                
  572.                
  573.                 #Avoid running code again if it's already recursive
  574.                 usingCustomModesAlready = checkInputs.checkBooleanKwargs( kwargs, False, 'usingCustomModesAlready' )
  575.                 if not usingCustomModesAlready:
  576.                
  577.                     validCustomCutoffModes.sort()
  578.                     kwargs["usingCustomModesAlready"] = True
  579.                    
  580.                     #Run code again for each cutoff mode
  581.                     for i in xrange( len( validCustomCutoffModes )-1 ):
  582.                    
  583.                         kwargs["useThisInstead"] = validCustomCutoffModes[i]
  584.                        
  585.                         newImageName = "{0}.{1}{2}.png".format( self.imageName.replace( ".png", "" ), cutoffModePrefix, validCustomCutoffModes[i] )
  586.                         otherURLS = ImageStore( newImageName, **self.kwargs ).write( input, **kwargs )
  587.                         if otherURLS:
  588.                             allOutputs += otherURLS
  589.                    
  590.                     if len( validCustomCutoffModes ) > 1:
  591.                    
  592.                         #Set up name and cutoff mode for final run
  593.                         self.imageName = "{0}.{1}{2}.png".format( self.imageName.replace( ".png", "" ), cutoffModePrefix, validCustomCutoffModes[-1] )
  594.                         customCutoffMode = validCustomCutoffModes[-1]
  595.                    
  596.                 else:
  597.                     customCutoffMode = kwargs["useThisInstead"]
  598.            
  599.             #Test custom image to see if it exists, return True or False
  600.             validArgs = checkInputs.validKwargs( kwargs, 't', 'tI', 'tCI', 'testImage', 'testURL', 'testImageURL', 'testImageLocation', 'testCustomImage', 'testCustomImageURL', 'testCustomImageLocation' )
  601.             canReadCustomImage = False
  602.             for i in xrange( len( validArgs ) ):
  603.            
  604.                 try:
  605.                     if kwargs[validArgs[i]]:
  606.                         if not customImageInput:
  607.                             return False
  608.                         else:
  609.                             return True
  610.                            
  611.                     canReadCustomImage = self.readImage( kwargs[validArgs[i]] )
  612.                     if canReadCustomImage:
  613.                         return True
  614.                        
  615.                 except:
  616.                     canReadCustomImage = False
  617.                    
  618.             if validArgs and not canReadCustomImage:
  619.                 return False
  620.            
  621.             if useCustomImageMethod:
  622.                 #Find md5 of image
  623.                 imageHash = md5.new()
  624.                 try:
  625.                     imageHash.update( customImageInput.tostring() )
  626.                 except:
  627.                     pass
  628.                 imageMD5 = imageHash.hexdigest()
  629.                
  630.                 #Open/create text file
  631.                 textFileData = {}
  632.                 successfulRead = False
  633.                 storedImageURL = ""
  634.                
  635.                 #This part allows you to skip iterating through every single pixel each time the code is run
  636.                 if self.writeToINI:
  637.                    
  638.                     cachePath = self.cache( returnPath = True )
  639.                
  640.                     if os.path.exists( cachePath ):
  641.                    
  642.                         try:
  643.                             #Get values from cache
  644.                             with open( cachePath, "r" ) as textFile:
  645.                                 textFileData = self.decodeData( textFile.read(), decode = True )
  646.                                
  647.                                 currentImageData = textFileData[imageMD5]
  648.                                 storedCutoffMode = int( currentImageData[0] )
  649.                                 storedValidPixels = currentImageData[1]
  650.                                 storedImageURL = currentImageData[2]
  651.                                 successfulRead = True
  652.                            
  653.                         except:
  654.                             pass
  655.                            
  656.                         openCacheMethod = "r+"
  657.                     else:
  658.                         openCacheMethod = "w"
  659.                        
  660.                     storedImage = self.readImage( storedImageURL )
  661.                
  662.                 uploadedImageURL = None
  663.                 if successfulRead and storedImage:
  664.                    
  665.                     customImageInputPath = storedImageURL
  666.                     customImageInput = storedImage
  667.                    
  668.                 else:
  669.                     #Upload custom image and switch path to URL
  670.                     uploadCustomImage = checkInputs.checkBooleanKwargs( kwargs, True, 'uI', 'uC', 'uO', 'uCI', 'uploadCustom', 'uploadOriginal', 'uploadCustomImage', 'uploadOriginalImage', 'uploadCustomURL', 'uploadOriginalURL' )
  671.                     if self.forceUpload:
  672.                         uploadCustomImage = self.shouldUpload
  673.                     if uploadCustomImage and customImageInput and not overrideUpload:
  674.                        
  675.                         #If it should upload any non Imgur URL to Imgur
  676.                         originalImageProtocols = self.protocols
  677.                         if uploadURLsToImgur:
  678.                             originalImageProtocols = [str( value ) + "i.imgur" for value in self.protocols]
  679.                        
  680.                         if not any( value in customImageInputPath for value in originalImageProtocols ):
  681.                            
  682.                             self.printCurrentProgress( "Uploading original image..." )
  683.                            
  684.                             uploadedImageURL = self.uploadImage( customImageInputPath, ignoreSize = True )
  685.                            
  686.                             if uploadedImageURL:
  687.                                 self.printCurrentProgress( "Link to original image is {0}.".format( uploadedImageURL ) )
  688.                                 self.stats( uploadedImageURL, False, imageMD5 )
  689.                                    
  690.                                 if not self.writeToINI:
  691.                                     self.printCurrentProgress( "Set this link as the custom image input to avoid re-uploading the same image each time." )
  692.                                
  693.                                 customImageInputPath = str( uploadedImageURL )
  694.                                 customImageInput = self.readImage( uploadedImageURL )
  695.                                                                
  696.                             else:
  697.                                 self.printCurrentProgress( "Original image URL will not be stored within the image." )
  698.                                
  699.                     elif customImageInput == None:
  700.                         customImageInputPath = ""
  701.                        
  702.         else:
  703.             useCustomImageMethod = False
  704.        
  705.         #Get invalid formats
  706.         renderViewFormat, ignoreFormats, uploadFormats = self.imageFormats()
  707.         formatList = dict( [item for key, item in renderViewFormat.iteritems() if len( item ) == 2] )
  708.         ignoreFormats = dict( [renderViewFormat[index] for index in ignoreFormats] ).keys()
  709.        
  710.         if customImageInputPath:
  711.             customImageExtension = customImageInputPath.split( "." )[-1].lower()
  712.         else:
  713.             customImageExtension = None
  714.        
  715.         customImageExtensionDict = formatList.get( customImageExtension, None )
  716.         if customImageExtensionDict and customImageExtension not in ignoreFormats:
  717.            
  718.             try:
  719.                 if mayaEnvironment:
  720.                     imageType = renderViewFormat[py.getAttr( "defaultRenderGlobals.imageFormat" )][1]
  721.                 else:
  722.                     imageType = customImageExtensionDict
  723.             except:
  724.                 imageType = customImageExtension.upper()
  725.                                
  726.             if customImageExtension not in ignoreFormats:
  727.            
  728.                 #Fix for V-Ray
  729.                 if py.getAttr( "defaultRenderGlobals.imageFormat" ) == 52:
  730.                     imageType = "V-Ray " + imageType
  731.                
  732.                 self.printCurrentProgress( "Reason: {0} files not supported.".format( imageType ) )
  733.            
  734.             if mayaEnvironment and usedRenderView:
  735.                 self.printCurrentProgress( "Use 'ImageStore().renderView( <format> )' to change the render image format." )
  736.            
  737.             customImageInput = None
  738.             customImageInputPath = ""
  739.             useCustomImageMethod = False
  740.        
  741.         if input and not returnCustomImageInfo:
  742.             self.printCurrentProgress( "Encoding input data...", True, self.writeProgress["CalculatingInputSize"] )
  743.            
  744.         #Print how large the input data is
  745.         if not input and not returnCustomImageInfo:
  746.             self.printCurrentProgress( "Error: Input data is required" )
  747.             return None
  748.        
  749.         elif not returnCustomImageInfo:
  750.        
  751.             inputData = self.encodeData( input, binary = useCustomImageMethod )
  752.             lengthOfInputData = len( inputData )
  753.            
  754.             if not returnCustomImageInfo:
  755.                 self.printCurrentProgress( "Input data is {0} bytes ({1}kb)". format( lengthOfInputData+3, ( lengthOfInputData+3 )/1024 ), True, self.writeProgress["InputSizeIs"] )
  756.            
  757.             #Return the normal size of input data
  758.             if outputSize:
  759.                 return lengthOfInputData+3
  760.        
  761.         #It shouldn't hit this part
  762.         elif outputSize:
  763.             print "Error: Unable to output the size of input"
  764.             return None
  765.        
  766.         rawData = []
  767.         if useCustomImageMethod:
  768.            
  769.             if not returnCustomImageInfo:
  770.                 self.printCurrentProgress( "Checking image has enough pixels to store the input data.", True, self.writeProgress["CheckingImage"] )
  771.            
  772.             bitsPerPixel = 6
  773.            
  774.             #Get correct range
  775.             cutoffModeAmount = {}
  776.             colourRange = {}
  777.             cutoffModes = xrange( self.maxCutoffModes+1 )
  778.             invalidCutoffMode = len( cutoffModes )
  779.            
  780.             #Set up valid pixels dictionary
  781.             validPixels = {}
  782.             for i in cutoffModes:
  783.                 cutoffModeAmount[i] = 0
  784.                 colourRange[i] = self.validRange( i, bitsPerPixel )
  785.                 validPixels[i] = {}
  786.            
  787.             #Read valid pixels dictionary from cache
  788.             if successfulRead and ( 0 <= storedCutoffMode <= self.maxCutoffModes ):
  789.                 validPixels = storedValidPixels
  790.                 bestCutoffMode = storedCutoffMode
  791.             else:
  792.                 bestCutoffMode = None
  793.                 storedCutoffMode = invalidCutoffMode
  794.                
  795.             #Use custom cutoff mode
  796.             if customCutoffMode:
  797.                 storedCutoffMode = customCutoffMode
  798.                
  799.             if not successfulRead or not validPixels[storedCutoffMode] or not bestCutoffMode:
  800.  
  801.                 #Calculate max data that can be stored
  802.                 if storedCutoffMode == invalidCutoffMode:
  803.                     self.printCurrentProgress( "Calculating the best method to store data...", True, self.writeProgress["CheckingImage"] )
  804.                        
  805.                 totalPixelCount = 0
  806.                 imageDimensions = customImageInput.size
  807.                 imageSize = float( imageDimensions[0]*imageDimensions[1] )
  808.                 pixelCount = 0
  809.                
  810.                 #Set up percentage output
  811.                 nextTime = time()+self.outputProgressTime
  812.                 minPercent = self.writeProgress["CheckingImage"]
  813.                 maxPercent = self.writeProgress["CalculatingCutoffMode"]
  814.                 if returnCustomImageInfo:
  815.                     minPercent = 0
  816.                     maxPercent = 65
  817.                    
  818.                 for pixels in customImageInput.getdata():
  819.                    
  820.                     #Output progress
  821.                     if pixelCount % self.outputProgressIterations == 0:
  822.                         if nextTime < time():
  823.                             nextTime = time()+self.outputProgressTime
  824.                             percentCompleted = round( 100 * totalPixelCount / imageSize, 1 )
  825.                             self.printCurrentProgress( " {0}% completed".format( percentCompleted ), False, int( minPercent+( maxPercent - minPercent )/100.0*percentCompleted ) )
  826.                
  827.                         for rgb in xrange( 3 ):
  828.                             rawData.append( pixels[rgb] )
  829.                             if bestCutoffMode == None:
  830.                                 #Count all valid values to find best cutoff mode
  831.                                 if totalPixelCount:
  832.                                     for i in cutoffModes:
  833.                                         if pixels[rgb] in colourRange[i][0] or pixels[rgb] in colourRange[i][1]:
  834.                                             cutoffModeAmount[i] += 1
  835.                                    
  836.                     totalPixelCount += 1
  837.                  
  838.                 #Select best cutoff mode
  839.                 if not bestCutoffMode:
  840.                     bestCutoffMode = max( cutoffModeAmount.iteritems(), key=operator.itemgetter( 1 ) )[0]
  841.                     cutoffMode = bestCutoffMode
  842.                 else:
  843.                     cutoffMode = storedCutoffMode
  844.                
  845.                 if not returnCustomImageInfo:
  846.                     self.printCurrentProgress( "Using storing mode {0}.".format( cutoffMode ), True, self.writeProgress["UsingCutoffMode"] )
  847.                 self.printCurrentProgress( "Calculating how much data can be stored for different amounts of bits using this mode...", True, self.writeProgress["UsingCutoffMode"] )
  848.                
  849.                 #Find maximum size image can store for bits per colour
  850.                 nextTime = time()+self.outputProgressTime
  851.                
  852.                 pixelCount = 0
  853.                 totalCount = float( 8*len( rawData ) )
  854.                 bitsPerPixel = 0
  855.                
  856.                 minPercent = self.writeProgress["UsingCutoffMode"]
  857.                 maxPercent = self.writeProgress["CalculatingMaxImageData"]
  858.                 if returnCustomImageInfo:
  859.                     minPercent = 65
  860.                     maxPercent = 100
  861.                    
  862.                 for i in xrange( 8 ):
  863.                                            
  864.                     bitsPerPixel = i+1
  865.                     validPixels[cutoffMode][bitsPerPixel] = 0
  866.                     colourIncreaseRange, colourReduceRange = self.validRange( cutoffMode, bitsPerPixel )
  867.                    
  868.                     for j in xrange( len( rawData ) ):
  869.                    
  870.                         if rawData[j] in colourIncreaseRange or rawData[j] in colourReduceRange:
  871.                             validPixels[cutoffMode][bitsPerPixel] += 1
  872.                            
  873.                         #Output progress
  874.                         pixelCount += 1
  875.                         if pixelCount % self.outputProgressIterations == 0:
  876.                             if nextTime < time():
  877.                                 nextTime = time()+self.outputProgressTime
  878.                                 percentCompleted = round( 100 * pixelCount / totalCount, 1 )
  879.                                 self.printCurrentProgress( " {0}% completed".format( percentCompleted ), False, int( minPercent+(maxPercent - minPercent)/100.0*percentCompleted ) )
  880.                        
  881.             else:
  882.            
  883.                 self.printCurrentProgress( "File information read from cache.", True, self.writeProgress["CalculatingMaxImageData"] )
  884.                    
  885.                 #Store custom image information
  886.                 for pixels in customImageInput.getdata():
  887.                     for rgb in xrange( 3 ):
  888.                         rawData.append( pixels[rgb] )
  889.                        
  890.                 #Get stored values
  891.                 cutoffMode = storedCutoffMode
  892.                 if customCutoffMode:
  893.                     cutoffMode = customCutoffMode
  894.                 validPixels = storedValidPixels
  895.                
  896.                 self.printCurrentProgress( "Using storing mode {0}.".format( cutoffMode ), True, self.writeProgress["ImageCanStore"] )
  897.            
  898.             validPixelsTotal = [number*bits for number, bits in validPixels[cutoffMode].iteritems()]
  899.             bitsPerPixelMax = validPixelsTotal.index( max( validPixelsTotal ) )+1
  900.            
  901.             #Write to ini file
  902.             if self.writeToINI:
  903.                 textFileData[imageMD5] = [bestCutoffMode, validPixels, uploadedImageURL]
  904.                 with open( cachePath, openCacheMethod ) as textFile:
  905.                     textFile.write( self.encodeData( textFileData, encode = True ) )
  906.            
  907.             #Get maximum bytes per bits
  908.             imageBytes = validPixels[cutoffMode][ bitsPerPixelMax ]
  909.             imageCanStorePercent = self.writeProgress["ImageCanStore"]
  910.             if returnCustomImageInfo:
  911.                 imageCanStorePercent = 100
  912.             self.printCurrentProgress( "Image can store up to around {0} bytes ({1}kb)".format( imageBytes, imageBytes/1024 ), True, imageCanStorePercent )
  913.            
  914.             if not returnCustomImageInfo:
  915.                 inputBytes = ( len( inputData )*8 )/bitsPerPixelMax+3
  916.                 outputText = "Input data at this level is {0} bytes ({1}kb)".format( inputBytes, inputBytes/1024 )
  917.            
  918.                 if inputBytes > imageBytes:
  919.                     outputText += ", which is currently more than the image can hold."
  920.                     self.printCurrentProgress( outputText, True, self.writeProgress["InputAtMax"] )
  921.                     outputText = "Attempting to find a valid value by calculating the other levels.".format( GlobalValues.newLine )
  922.                    
  923.                 else:
  924.                     self.printCurrentProgress( outputText, True, self.writeProgress["InputAtMax"] )
  925.                     outputText = "Now attempting to find the minumum valid value to store the data."
  926.                
  927.                 self.printCurrentProgress( outputText, True, self.writeProgress["InputAtMax"] )
  928.            
  929.             #Stop here if image information is wanted
  930.             if returnCustomImageInfo:
  931.                 return imageBytes
  932.                
  933.             #Calculate minimum bits per pixel to use
  934.             #Higher does not necessarily mean more, 6 bits seems to be the most efficient one
  935.             bitsPerPixel = 1
  936.             bytesNeeded = ( lengthOfInputData*8 )/bitsPerPixel+3 #Avoids having to actually split the input data
  937.            
  938.             minPercent = self.writeProgress["InputAtMax"]
  939.             maxPercent = self.writeProgress["MinimumBitsPerPixel"]
  940.             while validPixels[cutoffMode][bitsPerPixel] < bytesNeeded:
  941.            
  942.                 if bitsPerPixel > 7:
  943.                    
  944.                     outputText = "Error: Image not big enough to store data."
  945.                        
  946.                     #Stop code here if reverting to default isn't an option
  947.                     if not revertToDefault:
  948.                         self.printCurrentProgress( outputText, True, maxPercent )
  949.                         return None
  950.                     else:
  951.                         outputText += " Disabling the custom image option."
  952.                         self.printCurrentProgress( outputText, True, int( minPercent+(maxPercent-minPercent)/100.0*(bitsPerPixel+1)/8.0  ) )
  953.                    
  954.                     useCustomImageMethod = False
  955.                     inputData = self.encodeData( input, binary = useCustomImageMethod )
  956.                    
  957.                     break
  958.                    
  959.                 bitsPerPixel += 1
  960.                 bytesNeeded = ( lengthOfInputData*8 )/bitsPerPixel+3
  961.            
  962.            
  963.             #Continue if valid, if not pass through
  964.             if bitsPerPixel < 8:
  965.                 if bitsPerPixel > 1:
  966.                     self.printCurrentProgress( "Increased to {0} bits of colour to fit data within the image.".format( bitsPerPixel ), True, self.writeProgress["ChooseBitsPerPixel"] )
  967.                 else:
  968.                     self.printCurrentProgress( "Using 1 bit of colour to fit data within the image.", True, self.writeProgress["ChooseBitsPerPixel"] )
  969.    
  970.                 #Encode input data
  971.                 self.printCurrentProgress( "Splitting input data into separate pixel values...", True, self.writeProgress["ChooseBitsPerPixel"] )
  972.                 joinedData = "".join( inputData )
  973.                 splitData = re.findall( r".{1," + str( bitsPerPixel ) + "}", joinedData, re.DOTALL )
  974.                 colourIncreaseRange, colourReduceRange = self.validRange( cutoffMode, bitsPerPixel )
  975.                 numbersToAdd = [ int( num, 2 ) for num in splitData ]
  976.                
  977.                 #Draw image
  978.                 width, height = customImageInput.size
  979.        
  980.         if not useCustomImageMethod:
  981.            
  982.             #Set image info
  983.             minimumWidth = 3
  984.             height = 2
  985.             currentPixels = len( inputData )/3
  986.            
  987.             #Calculate width and height
  988.             if currentPixels <= minimumWidth*height:
  989.                 #Set to minimum values
  990.                 width = minimumWidth
  991.                
  992.             else:
  993.                 #Calculate based on ratio
  994.                 width = int( round( pow( currentPixels, ratioWidth ), -1 ) )
  995.                 #Make sure it is divisible by 3
  996.                 width /= 3
  997.                 width *= 3
  998.                 if width < minimumWidth:
  999.                     width = minimumWidth
  1000.                    
  1001.                 #Correct size to allow for padding
  1002.                 while currentPixels > height*width:
  1003.                     if width <= height and ratioWidth > 0.5:
  1004.                         width += 1
  1005.                     else:
  1006.                         height += 1
  1007.                        
  1008.             bitsPerPixel = 8
  1009.             cutoffMode = 9
  1010.    
  1011.             self.printCurrentProgress( "Set width to {0} pixels and height to {1} pixels.".format( width, height ), True, self.writeProgress["SetDimensions"] )
  1012.        
  1013.         #Draw image
  1014.         imageOutput = Image.new("RGB", ( width, height ) )
  1015.         imageData = imageOutput.load()
  1016.    
  1017.         #Set range of colours for random filling
  1018.         numbersToAddIncrement = 0
  1019.         if padWithRandomData:
  1020.        
  1021.             if useCustomImageMethod:
  1022.                 maxImageAddition = pow( 2, bitsPerPixel )+bitsPerPixel-8
  1023.                 minImageAddition = 0
  1024.                
  1025.                 #Fix for if it goes under 1
  1026.                 if maxImageAddition < 1:
  1027.                     maxImageAddition = pow( 2, bitsPerPixel )
  1028.                
  1029.             else:
  1030.                 maxImageAddition = 128
  1031.                 minImageAddition = 52
  1032.                
  1033.         else:
  1034.             maxImageAddition = 255
  1035.             minImageAddition = 255
  1036.        
  1037.         #Assign pixel colours
  1038.         self.printCurrentProgress( "Calculating image...", True, self.writeProgress["SetDimensions"] )
  1039.         nextTime = time()+self.outputProgressTime
  1040.         minPercent = self.writeProgress["SetDimensions"]
  1041.         maxPercent = self.writeProgress["CalculatingImage"]
  1042.         for y in xrange( height ):
  1043.             for x in xrange( width ):
  1044.                
  1045.                 isDataFromInput = True
  1046.                 currentProgress = 3*( y*width+x )
  1047.                
  1048.                 #Output progress
  1049.                 if y*width+x % self.outputProgressIterations == 0:
  1050.                     if nextTime < time():
  1051.                         nextTime = time()+self.outputProgressTime
  1052.                         percentCompleted = round( 100*( currentProgress/3 )/( width*height ), 1 )
  1053.                         self.printCurrentProgress( " {0}% completed".format( percentCompleted ), True, int( minPercent+(maxPercent - minPercent)/100.0*percentCompleted ) )
  1054.  
  1055.                
  1056.                 #Assign information to first pixel
  1057.                 if not x and not y:
  1058.                     inputInfo = int( str( bitsPerPixel ) + str( cutoffMode ) )
  1059.                     dataRGB = [inputInfo, self.firstPixelPadding[0], self.firstPixelPadding[1]]
  1060.                     if debugData:
  1061.                         dataRGB = [99, self.firstPixelPadding[0], self.firstPixelPadding[1]]
  1062.                         imageData[x,y] = tuple( dataRGB )
  1063.                         continue
  1064.                
  1065.                 #If an image should be made with the default method
  1066.                 elif not useCustomImageMethod:
  1067.                        
  1068.                     dataRGB = {}
  1069.                     try:
  1070.                         for i in xrange( 3 ):
  1071.                             dataRGB[i] = inputData[numbersToAddIncrement]
  1072.                             numbersToAddIncrement += 1
  1073.                     except:
  1074.                    
  1075.                         if isDataFromInput:
  1076.                             isDataFromInput = False
  1077.                        
  1078.                         #Add random data
  1079.                         for i in xrange( 3 ):
  1080.                             dataRGB[i] = random.randint( minImageAddition, maxImageAddition )
  1081.                    
  1082.                     dataRGB = [number[1] for number in dataRGB.items()]
  1083.                      
  1084.                 #If data should be written over a custom image
  1085.                 else:
  1086.                
  1087.                     if numbersToAddIncrement < len( numbersToAdd )-1:
  1088.                         dataRGB = {}
  1089.                         for i in xrange( 3 ):
  1090.                        
  1091.                             try:
  1092.                                 if rawData[currentProgress+i] in colourIncreaseRange:
  1093.                                     dataRGB[i] = rawData[currentProgress+i] + numbersToAdd[numbersToAddIncrement]
  1094.                                     numbersToAddIncrement += 1
  1095.                                    
  1096.                                 elif rawData[currentProgress+i] in colourReduceRange:
  1097.                                     dataRGB[i] = rawData[currentProgress+i] - numbersToAdd[numbersToAddIncrement]
  1098.                                     numbersToAddIncrement += 1
  1099.                                    
  1100.                                 else:
  1101.                                     dataRGB[i] = rawData[currentProgress+i]
  1102.                                    
  1103.                             except:
  1104.                                 dataRGB[i] = rawData[currentProgress+i]
  1105.                                 isDataFromInput = False
  1106.                                
  1107.                         dataRGB = [ dataRGB[0], dataRGB[1], dataRGB[2] ]
  1108.                        
  1109.                     else:
  1110.                    
  1111.                         if isDataFromInput:
  1112.                             isDataFromInput = False
  1113.                        
  1114.                         #Pad with random values so it's not such a clear line in the image
  1115.                         dataRGB = {}
  1116.                         for i in xrange( 3 ):
  1117.                        
  1118.                             if rawData[currentProgress+i] in colourIncreaseRange:
  1119.                                 dataRGB[i] = rawData[currentProgress+i] + random.randint( minImageAddition, maxImageAddition )
  1120.                                
  1121.                             elif rawData[currentProgress+i] in colourReduceRange:
  1122.                                 dataRGB[i] = rawData[currentProgress+i] - random.randint( minImageAddition, maxImageAddition )
  1123.                                
  1124.                             else:
  1125.                                 dataRGB[i] = rawData[currentProgress+i]
  1126.                                
  1127.                         dataRGB = [dataRGB[0], dataRGB[1], dataRGB[2]]
  1128.                
  1129.                 if debugData and isDataFromInput:
  1130.                     dataRGB = [0,0,0]
  1131.                    
  1132.                 imageData[x,y] = tuple( dataRGB )
  1133.        
  1134.         self.printCurrentProgress( "Saving image...", True, self.writeProgress["SavingImage"] )
  1135.        
  1136.         try:
  1137.             imageOutput.save( self.imageName, "PNG" )
  1138.            
  1139.         except:
  1140.        
  1141.             failText = ["Error: Failed saving file to {0}.".format( self.imageName )]
  1142.             failText.append( "You may have incorrect permissions or the file may be in use." )
  1143.             failText.append( "{0}Attempting to save in new location...".format( GlobalValues.newLine ) )
  1144.             self.printCurrentProgress( " ".join( failText ) )
  1145.             savingFailed = "{0}Failed to save file.".format( GlobalValues.newLine )
  1146.            
  1147.             #If already in default directory
  1148.             if self.imageName.rsplit( '/', 1 )[0] == self.defaultImageDirectory:
  1149.            
  1150.                 if self.imageName.rsplit( '/', 1 )[1] == self.defaultImageName:
  1151.                     self.imageName = None
  1152.                     failText = savingFailed
  1153.                    
  1154.                 else:
  1155.                
  1156.                     try:
  1157.                         self.imageName = "{0}/{1}".format( self.defaultImageDirectory, self.defaultImageName )
  1158.                         imageOutput.save( self.imageName, "PNG" )
  1159.                         failText = None
  1160.                        
  1161.                     except:
  1162.                         self.imageName = None
  1163.                         failText = savingFailed
  1164.            
  1165.             #If not in default directory
  1166.             else:
  1167.            
  1168.                 try:
  1169.                     self.imageName = "{0}/{1}".format( self.defaultImageDirectory, self.imageName.rsplit( '/', 1 )[1] )
  1170.                     imageOutput.save( self.imageName, "PNG" )
  1171.                     failText = None
  1172.                    
  1173.                 except:
  1174.                
  1175.                     try:
  1176.                         self.imageName = "{0}/{1}".format( self.defaultImageDirectory, self.defaultImageName )
  1177.                         imageOutput.save( self.imageName, "PNG" )
  1178.                         failText = None
  1179.                        
  1180.                     except:
  1181.                         failText = savingFailed
  1182.                         self.imageName = None
  1183.        
  1184.        
  1185.         #Make sure image exists first
  1186.         if self.imageName:
  1187.            
  1188.             #Find md5 of image
  1189.             imageHash = md5.new()
  1190.             try:
  1191.                 imageHash.update( self.readImage( self.imageName ).tostring() )
  1192.             except:
  1193.                 pass
  1194.             imageMD5 = imageHash.hexdigest()
  1195.            
  1196.             self.printCurrentProgress( "Saved image.", True, self.writeProgress["WritingExtraInformation"] )
  1197.            
  1198.             outputList = [( self.imageName ).replace( "\\", "/" )]
  1199.            
  1200.             #Zip extra information inside image
  1201.             self.printCurrentProgress( "Writing extra information into image file.", True, self.writeProgress["WritingExtraInformation"] )
  1202.                
  1203.             infoText = ["Date created: {0}{1}".format( self.dateFormat( time() ), GlobalValues.newLine )]
  1204.             try:
  1205.                 infoText = ["Username: {0}{1}".format( getpass.getuser(), GlobalValues.newLine )] + infoText
  1206.             except:
  1207.                 pass
  1208.             infoText.append( "Visit {0} to get a working version of the code.".format( self.website ) )
  1209.            
  1210.             #Write to zip file
  1211.             if not disableInfo:
  1212.                 ImageStoreZip.write( "".join( infoText ), "information.txt", reset = True )
  1213.                 ImageStoreZip.write( str( getpass.getuser() ) + "@" + str( time() ), "creationtime" )
  1214.                 ImageStoreZip.write( customImageInputPath, "url" )
  1215.             else:
  1216.                 ImageStoreZip.write( infoText[-1], "information.txt", reset = True )
  1217.             ImageStoreZip.write( str( self.versionNumber ), "version" )
  1218.            
  1219.             zipSuccess = ImageStoreZip.combine( image = self.imageName )
  1220.            
  1221.             if not zipSuccess:
  1222.                 self.printCurrentProgress( "Error: Unable to write extra information." )
  1223.            
  1224.             #Upload image
  1225.             uploadedImageURL = None
  1226.             if upload and not overrideUpload:
  1227.                 self.printCurrentProgress( "Uploading image..." )
  1228.                    
  1229.                 uploadedImageURL = self.uploadImage( self.imageName, openImage )
  1230.                 if uploadedImageURL:
  1231.                     outputList.append( str( uploadedImageURL ) )
  1232.                    
  1233.                     self.printCurrentProgress( "Uploaded to {0}.".format( uploadedImageURL ), True, self.writeProgress["Validate"] )
  1234.                 else:
  1235.                     self.printCurrentProgress( "Error: Failed to upload image.", True, self.writeProgress["Validate"] )
  1236.            
  1237.             #Check the output
  1238.             self.validateWrite = True
  1239.             if validateOutput:
  1240.                
  1241.                 self.printCurrentProgress( "Validating saved image...", True, self.writeProgress["Validate"] )
  1242.            
  1243.                 #Stop reading printing anything
  1244.                    
  1245.                 try:
  1246.                     if self.read() != input:
  1247.                    
  1248.                         raise ImageStoreError( "data failed to validate" )
  1249.                        
  1250.                     else:
  1251.                    
  1252.                         self.validateWrite = False
  1253.                         self.printCurrentProgress( "Successfully validated the data.", True, self.writeProgress["Validate"] )
  1254.                        
  1255.                 except:
  1256.                
  1257.                     self.validateWrite = False
  1258.                     self.printCurrentProgress( "Error: Failed to validate the data. Image appears to be corrupt." )
  1259.                     return None
  1260.            
  1261.            
  1262.             #Write to render view window for Maya
  1263.             if mayaEnvironment:
  1264.                 if writeToRenderView:
  1265.                     try:
  1266.                         py.renderWindowEditor( 'renderView', edit = True, loadImage = self.imageName )
  1267.                     except:
  1268.                         self.printCurrentProgress( "Error: Failed to write image into the renderView window." )
  1269.            
  1270.             #Remove the image
  1271.             if deleteImage:
  1272.                 self.printCurrentProgress( "Deleting image..." )
  1273.                 try:
  1274.                     os.remove( self.imageName )
  1275.                     outputList.pop( 0 )
  1276.                 except:
  1277.                     pass
  1278.                 if not outputList :
  1279.                     return None
  1280.            
  1281.             self.stats( uploadedImageURL, lengthOfInputData+3, imageMD5 )
  1282.            
  1283.             returningCustomURL = False
  1284.             if returnCustomImageURL and any( value in customImageInputPath for value in self.protocols ):
  1285.                 outputList.append( customImageInputPath )
  1286.                 returningCustomURL = True
  1287.            
  1288.             #Return output
  1289.             allOutputs += [outputList]
  1290.            
  1291.             returnValue = allOutputs
  1292.            
  1293.         else:
  1294.             returnValue = None
  1295.        
  1296.         if mayaEnvironment:
  1297.             self.printCurrentProgress( "Done." )
  1298.             if self.callbackWrite:
  1299.                 self.callbackWrite( returnValue, returningCustomURL )
  1300.                
  1301.         return returnValue
  1302.  
  1303.  
  1304.     def actualRead( self, *args, **kwargs ):
  1305.    
  1306.         useCustomImageMethod = False
  1307.         debugDataDefaultAmount = 100 #How many characters to display by default
  1308.        
  1309.         #If it should just debug the data
  1310.         validArgs = checkInputs.validKwargs( kwargs, 'debug', 'debugData', 'debugResult', 'debugOutput' )
  1311.         debugData = False
  1312.         for i in xrange( len( validArgs ) ):
  1313.             try:
  1314.                 if kwargs[validArgs[i]]:
  1315.                     debugData = debugDataDefaultAmount
  1316.                     break
  1317.                 elif 0 < int( kwargs[validArgs[i]] ):
  1318.                     debugData = int( kwargs[validArgs[i]] )
  1319.             except:
  1320.                 debugData = False
  1321.         if not debugData and self.debugging:
  1322.             debugData = debugDataDefaultAmount
  1323.  
  1324.         #Read renderView window in Maya      
  1325.         if mayaEnvironment:
  1326.             if self.imageName in self.renderViewCheck:
  1327.                 self.renderView( True )
  1328.                 try:
  1329.                     originalMayaFormat = py.getAttr( "defaultRenderGlobals.imageFormat" )
  1330.                     py.setAttr( "defaultRenderGlobals.imageFormat", 32 )
  1331.                 except:
  1332.                     pass
  1333.                 self.imageName = self.renderViewSaveLocation
  1334.                 try:
  1335.                     py.setAttr( "defaultRenderGlobals.imageFormat", originalMayaFormat )
  1336.                 except:
  1337.                     pass
  1338.        
  1339.         #Get image, try from args first then use the main image location value
  1340.         #Avoids the default location overriding the args value
  1341.         self.printCurrentProgress( "Reading image...", True, self.readProgress["ReadingImage"] )
  1342.         useArgsForImageRead = True
  1343.         try:
  1344.             if args and useArgsForImageRead:
  1345.                 imageInput = self.readImage( args[0] )
  1346.                 self.imageName = args[0]
  1347.             else:
  1348.                 imageInput = None
  1349.                
  1350.             if not imageInput:
  1351.                 raise ImageStoreError()
  1352.                
  1353.         except:
  1354.             imageInput = self.readImage( self.imageName )
  1355.            
  1356.         if not imageInput:
  1357.             self.printCurrentProgress( "Error: Unable to read image." )
  1358.             return None
  1359.            
  1360.         #Output stored zip information
  1361.         outputInfo = checkInputs.checkBooleanKwargs( kwargs, debugData, 'o', 'output', 'outputInfo', 'outputInformation' )
  1362.        
  1363.         try:
  1364.             self.printCurrentProgress( "Reading files in image...", True, self.readProgress["ReadingFiles"] )
  1365.             originalVersionNumber, originalCreationTime, originalCreationName, customImageURL, fileList = ImageStoreZip.read( imageLocation = self.imageName )
  1366.             if debugData:
  1367.                 self.printCurrentProgress( "Files stored in image: {0}".format( ", ".join( fileList ) ), True, self.readProgress["FilesStored"] )
  1368.        
  1369.         except:
  1370.             outputInfo = False
  1371.             customImageURL = ""
  1372.            
  1373.         if outputInfo:
  1374.             if originalVersionNumber:
  1375.                 self.printCurrentProgress( "Version number: {0}".format( originalVersionNumber ), True, self.readProgress["FilesStored"] )
  1376.             if originalCreationTime:
  1377.                 self.printCurrentProgress( "Date created: {0}".format( self.dateFormat( originalCreationTime ) ), True, self.readProgress["FilesStored"] )
  1378.        
  1379.         self.printCurrentProgress( "Storing the pixel data...", True )
  1380.         #Store pixel info
  1381.         rawData = []
  1382.         for pixels in imageInput.getdata():
  1383.             for rgb in xrange( 3 ):
  1384.                 rawData.append( pixels[rgb] )
  1385.        
  1386.         #Get important image info
  1387.         if len( str( rawData[0] ) ) > 1 and rawData[1] == self.firstPixelPadding[0] and rawData[2] == self.firstPixelPadding[1]:
  1388.             imageInfo = [int( num ) for num in list( str( rawData[0] ) )]
  1389.             bitsPerPixel = imageInfo[0]
  1390.             cutoffMode = imageInfo[1]
  1391.            
  1392.         else:
  1393.             self.printCurrentProgress( "Error: Invalid image." )
  1394.             return None
  1395.        
  1396.         if debugData:
  1397.             self.printCurrentProgress( "Bits per pixel: {0}".format( bitsPerPixel ), True, self.readProgress["FirstPixel"] )
  1398.             self.printCurrentProgress( "Cutoff mode: {0}".format( cutoffMode ), True, self.readProgress["FirstPixel"] )
  1399.        
  1400.         #Find how the image was made
  1401.         if bitsPerPixel == 9 and cutoffMode == 9:
  1402.             self.printCurrentProgress( "Error: Image had debug data set to true. Unable to read." )
  1403.             return None
  1404.            
  1405.         elif len( imageInfo ) > 2:
  1406.             outputText = "Stored data {0}."
  1407.             if str( originalVersionNumber ) != str( self.versionNumber ):
  1408.                 outputText.format( "is from an older version {0}" )
  1409.             else:
  1410.                 outputText.format( "appears to be invalid {0} anyway" )
  1411.             outputText.format( ", attempting to continue." )
  1412.             self.printCurrentProgress( outputText )
  1413.             useCustomImageMethod = False
  1414.        
  1415.         elif bitsPerPixel == 8:
  1416.             useCustomImageMethod = False
  1417.         else:
  1418.             useCustomImageMethod = True
  1419.            
  1420.         usedDifferentOriginalImage = False
  1421.         if useCustomImageMethod:
  1422.        
  1423.            
  1424.             #Use other custom image
  1425.             validArgs = checkInputs.validKwargs( kwargs, 'i', 'cI', 'img', 'image', 'URL', 'imgURL', 'imgPath', 'imgLoc', 'imgLocation', 'imageURL', 'imageLoc', 'imagePath', 'imageLocation', 'customImg', 'customImage', 'customImgURL', 'customImageURL', 'customImgPath', 'customImagePath', 'customImgLoc', 'customImageLoc', 'customImgLocation', 'customImageLocation' )
  1426.             originalImage = None
  1427.             for i in xrange( len( validArgs ) ):
  1428.                 try:
  1429.                     originalImage = self.readImage( kwargs[validArgs[i]] )
  1430.                 except:
  1431.                     originalImage = None
  1432.                        
  1433.             if validArgs and not originalImage:
  1434.            
  1435.                 outputText = "Error: Could not read the custom input image."
  1436.                 if customImageURL:
  1437.                     outputText.replace( ".", ", reverting to the stored URL." )
  1438.                 self.printCurrentProgress( outputText )
  1439.                    
  1440.                 originalImage = self.readImage( customImageURL )
  1441.                
  1442.             elif not originalImage:
  1443.                 originalImage = self.readImage( customImageURL )
  1444.                
  1445.             else:
  1446.                 usedDifferentOriginalImage = True
  1447.            
  1448.             #If both attempts haven't worked
  1449.             if not originalImage:
  1450.                 if customImageURL:
  1451.                     self.printCurrentProgress( "Error: Invalid custom image." )
  1452.                 else:
  1453.                     self.printCurrentProgress( "Error: Something has gone wrong." )
  1454.                        
  1455.                 return None
  1456.                
  1457.             self.printCurrentProgress( "Storing the custom image pixel data", True, self.readProgress["FirstPixel"] )
  1458.             #Store original pixel info
  1459.             originalImageData = []
  1460.             for pixels in originalImage.getdata():
  1461.                 for rgb in xrange( 3 ):
  1462.                     originalImageData.append( pixels[rgb] )
  1463.                    
  1464.             #For cutoff mode, 0 is move colours down towards black, 1 is move towards middle, 2 is move towards white
  1465.             bitsPerColour, cutoffMode = [int( x ) for x in list( str( rawData[0] ) )]
  1466.             colourIncreaseRange, colourReduceRange = self.validRange( cutoffMode, bitsPerColour )
  1467.            
  1468.             #Get difference in data
  1469.             comparisonData = []
  1470.             self.printCurrentProgress( "Retrieving data from image...", True, self.readProgress["StoringCustomPixelInfo"] )
  1471.             nextTime = time()+self.outputProgressTime
  1472.             totalPixels = len( originalImageData )
  1473.             minPercent = self.readProgress["StoringCustomPixelInfo"]
  1474.             maxPercent = self.readProgress["ConvertingData"]
  1475.             for i in xrange( 3, totalPixels ):
  1476.                
  1477.                 #Output progress
  1478.                 if i % self.outputProgressIterations == 0:
  1479.                     if nextTime < time():
  1480.                         nextTime = time()+self.outputProgressTime
  1481.                         percentCompleted = round( 100 * i / totalPixels, 1 )
  1482.                         self.printCurrentProgress( " {0}% completed".format( percentCompleted ), False, int( minPercent+(maxPercent - minPercent)/100.0*percentCompleted ) )
  1483.                        
  1484.                 if originalImageData[i] in colourIncreaseRange:
  1485.                     comparisonData.append( rawData[i] - originalImageData[i] )
  1486.                    
  1487.                 elif originalImageData[i] in colourReduceRange:
  1488.                     comparisonData.append( originalImageData[i] - rawData[i] )
  1489.                    
  1490.             self.printCurrentProgress( "Converting data to readable format...", True, self.readProgress["ConvertingData"] )
  1491.             bitData = "".join( [ format( x, "b" ).zfill( bitsPerColour ) for x in comparisonData ] )
  1492.             byteData = re.findall( r".{1,8}", bitData )
  1493.            
  1494.             for i in xrange( len( byteData ) ):
  1495.                 if "-" in byteData[i]:
  1496.                     byteData[i] = "00000000"
  1497.                    
  1498.             numberData = [int( number, 2 ) for number in byteData]
  1499.            
  1500.         else:
  1501.             numberData = rawData[3:]
  1502.        
  1503.         #Truncate end of file
  1504.         self.printCurrentProgress( "Removing excess data from end of file...", True, self.readProgress["ReadingData"] )
  1505.         try:
  1506.        
  1507.             for i in xrange( len( numberData ) ):
  1508.                 j = 0
  1509.                
  1510.                 while numberData[i+j] == self.imageDataPadding[j]:
  1511.                     j += 1
  1512.                    
  1513.                     if j == len( self.imageDataPadding ):
  1514.                         numberData = numberData[0:i]
  1515.                         break
  1516.                        
  1517.                 if j == len( self.imageDataPadding ):
  1518.                     break
  1519.                    
  1520.         except:
  1521.             self.printCurrentProgress( "Error: File is corrupted." )
  1522.        
  1523.         try:
  1524.        
  1525.             self.printCurrentProgress( "Decoding data...", True, self.readProgress["TruncatingEnd"] )
  1526.             decodedData = self.decodeData( numberData )
  1527.            
  1528.         except:
  1529.        
  1530.             if usedDifferentOriginalImage:
  1531.                 self.printCurrentProgress( "Failed to decode data, the custom original image specified may not be the original one used." )
  1532.                
  1533.                 if customImageURL:
  1534.                     self.printCurrentProgress( "Failed to decode data, however here is a URL to the correct image contained within the file." )
  1535.                     self.printCurrentProgress( "If you are using the original image stored on your computer, it may have resized after being uploaded to Imgur." )
  1536.                
  1537.                 else:
  1538.                     self.printCurrentProgress( "No URL was found stored in the image, you may have linked to the wrong image." )
  1539.            
  1540.             elif customImageURL:
  1541.                 self.printCurrentProgress( "Failed to decode data from the stored URL ({0}), check the image still exists.".format( customImageURL ) )
  1542.            
  1543.             else:
  1544.                 self.printCurrentProgress( "Failed to decode data from the image." )
  1545.                    
  1546.             decodedData = None
  1547.        
  1548.         if debugData and decodedData:
  1549.             self.printCurrentProgress( "Length of stored data: {0}".format( len( decodedData ) ) )
  1550.             self.printCurrentProgress( "Type of data: {0}".format( str( type( decodedData ) ).replace( "<type '", "" ).replace( "'>", "" ) ) )
  1551.             self.printCurrentProgress( "Writing data to user interface...", True )
  1552.             if len( str( decodedData ) ) > debugData:
  1553.                 self.printCurrentProgress( "First {0} characters of data: {1}".format( debugData, str( decodedData )[0:debugData] ), False )
  1554.             else:
  1555.                 self.printCurrentProgress( "Stored data: {0}".format( decodedData ), False )
  1556.                
  1557.             self.printCurrentProgress( "Successfully decoded the image.", True, self.readProgress["Decoding"] )
  1558.            
  1559.         if mayaEnvironment:
  1560.             if self.callbackRead:
  1561.                 self.callbackRead( decodedData )
  1562.            
  1563.         return decodedData
  1564.  
  1565.     def decodeData( self, numberData, **kwargs ):
  1566.        
  1567.         #Only decode the data without converting numbers into characters
  1568.         if checkInputs.checkBooleanKwargs( kwargs, False, 'd', 'decode', 'decodeOnly' ):
  1569.             encodedData = numberData
  1570.        
  1571.         #Convert numbers into characters
  1572.         else:
  1573.             encodedData = "".join( [chr( pixel ) for pixel in numberData] )
  1574.         outputData = cPickle.loads( zlib.decompress( base64.b64decode( encodedData ) ) )
  1575.        
  1576.         return outputData
  1577.    
  1578.     def encodeData( self, input, **kwargs ):
  1579.        
  1580.         encodedData = base64.b64encode( zlib.compress( cPickle.dumps( input ) ) )
  1581.         if checkInputs.checkBooleanKwargs( kwargs, False, 'e', 'encode', 'encodeOnly' ):
  1582.             return encodedData
  1583.        
  1584.         #Format into numbers
  1585.         pixelData = [int( format( ord( letter ) ) ) for letter in encodedData]
  1586.         pixelData += self.imageDataPadding
  1587.        
  1588.         #Pad to end with multiple of 3
  1589.         for i in xrange( 3-len( pixelData )%3 ):
  1590.             pixelData += [random.randint( 52, 128 )]
  1591.        
  1592.         #Get binary info
  1593.         binary = checkInputs.checkBooleanKwargs( kwargs, False, 'b', 'binary', 'useCustomImageMethod' )
  1594.         if binary:
  1595.             pixelData = [ format( number, "b" ).zfill( 8 ) for number in pixelData ]
  1596.            
  1597.         return pixelData      
  1598.  
  1599.        
  1600.     #This is my only way of finding the stats as imgur doesn't say, this won't be available to view anywhere
  1601.     #However, if you are against this, just disable the urllib2.urlopen() command
  1602.     def stats( self, imageURL, numBytes, imageMD5 ):
  1603.    
  1604.         #Check if md5 value is valid
  1605.         if md5.new().hexdigest() == imageMD5:
  1606.             imageMD5 = "".join("0" for x in xrange( 32 ))
  1607.             return #No point storing it currently, means something has gone wrong or something
  1608.            
  1609.         #Set user agent and URL
  1610.         userAgent = "ImageStore/" + str( self.versionNumber )
  1611.         siteAddress = "{0}/code/imagestore?url={1}&b={2}&m={3}".format( self.website, imageURL, int( numBytes ), imageMD5 )
  1612.        
  1613.         #Send a request to the website
  1614.         try:
  1615.             if not self.debugging:
  1616.                 urllib2.urlopen( urllib2.Request( siteAddress, headers = { 'User-Agent': userAgent } ) )
  1617.         except:
  1618.             pass
  1619.        
  1620.        
  1621.     def uploadImage( self, imageLocation, openImage=False, **kwargs ):
  1622.        
  1623.         ignoreSize = checkInputs.checkBooleanKwargs( kwargs, False, 'i', 'iS', 'ignoreSize' )
  1624.         imageTitle = "Image Data"
  1625.        
  1626.         #Get valid formats to upload
  1627.         renderViewFormat, ignoreFormats, uploadFormats = self.imageFormats()
  1628.         validFormats = dict( [renderViewFormat[int( index )] for index in uploadFormats] )
  1629.         allFormats = dict( [value for key, value in renderViewFormat.iteritems() if len( value ) == 2] )
  1630.        
  1631.         if self.validPath( imageLocation ) and not overrideUpload:
  1632.        
  1633.             #Check format is valid
  1634.             fileExtension = imageLocation.split( "." )[-1].lower()
  1635.            
  1636.             if fileExtension == "gif":
  1637.                 return None
  1638.            
  1639.             if not validFormats.get( fileExtension, None ):
  1640.                
  1641.                 fileExtensionDict = allFormats.get( fileExtension, None )
  1642.                 if fileExtensionDict:
  1643.                     fileExtension = fileExtensionDict
  1644.                 else:
  1645.                     fileExtension = fileExtension.upper()
  1646.                 self.printCurrentProgress( "Error: {0} files not supported by Imgur.".format( fileExtension ) )
  1647.                
  1648.                 return None
  1649.        
  1650.             #Save if from a URL
  1651.             saved = False
  1652.             if any( value in imageLocation for value in self.protocols ):
  1653.            
  1654.                 try:
  1655.                     inputImage = Image.open( cStringIO.StringIO( urllib2.urlopen( imageLocation ).read() ) )
  1656.                     imageFormat = str( inputImage.format )
  1657.                     imageSaveLocation = "{0}/{1}.{2}".format( self.defaultCacheDirectory, self.defaultCacheName, imageFormat.lower() ).replace( ".cache", "" )
  1658.                     inputImage.save( imageSaveLocation, imageFormat )
  1659.                     imageLocation = imageSaveLocation
  1660.                     saved = True
  1661.                    
  1662.                 except:
  1663.                     pass
  1664.                
  1665.             #Upload image
  1666.             try:
  1667.                 uploadedImage = pyimgur.Imgur( "0d10882abf66dec" ).upload_image( imageLocation, title=imageTitle )
  1668.            
  1669.             except:
  1670.                 self.printCurrentProgress( "Error: Failed uploading image, trying once more." )
  1671.                    
  1672.                 #Once it didn't upload the first time, no idea why, but I guess this just makes sure your internet didn't temporarily cut out
  1673.                 try:
  1674.                     uploadedImage = pyimgur.Imgur( "0d10882abf66dec" ).upload_image( imageLocation, title=imageTitle )
  1675.                
  1676.                 except:
  1677.                     self.printCurrentProgress( "Failed to upload image." )
  1678.                     return None
  1679.            
  1680.             #Find out image size
  1681.             originalImageSize = os.path.getsize( imageLocation )
  1682.             uploadedImageSize = uploadedImage.size
  1683.            
  1684.             #Check it's not been converted, not needed if it's acting as the original image
  1685.             if originalImageSize != uploadedImageSize and not ignoreSize:
  1686.            
  1687.                 self.printCurrentProgress( "Error: File is too large for Imgur." )
  1688.                 return None
  1689.                
  1690.             else:
  1691.            
  1692.                 #Open image in browser
  1693.                 if openImage:
  1694.                     webbrowser.open( uploadedImage.link )
  1695.                                
  1696.                 #Return the link
  1697.                 return uploadedImage.link
  1698.  
  1699.             if saved:
  1700.            
  1701.                 try:
  1702.                     os.remove( imageSaveLocation )
  1703.                    
  1704.                 except:
  1705.                     pass
  1706.        
  1707.         else:
  1708.             return None
  1709.    
  1710.  
  1711.     def imageFormats( self ):
  1712.    
  1713.         #Use True to exclude from any lists to avoid overlaps of the same extension
  1714.         renderViewFormat = {}
  1715.         renderViewFormat[0] = ["gif", "GIF"]
  1716.         renderViewFormat[1] = ["pic", "SoftImage"]
  1717.         renderViewFormat[2] = ["rla", "Wavefront"]
  1718.         renderViewFormat[3] = ["tif", "Tiff"]
  1719.         renderViewFormat[4] = ["tif", "Tiff16", True]
  1720.         renderViewFormat[5] = ["sgi", "SGI"]
  1721.         renderViewFormat[6] = ["als", "Alias PIX"]
  1722.         renderViewFormat[7] = ["iff", "Maya IFF"]
  1723.         renderViewFormat[8] = ["jpg", "JPEG"]
  1724.         renderViewFormat[9] = ["eps", "EPS"]
  1725.         renderViewFormat[10] = ["iff", "Maya16 IFF", True]
  1726.         renderViewFormat[11] = ["cin", "Cineon"]
  1727.         renderViewFormat[12] = ["yuv", "Quantel PAL"]
  1728.         renderViewFormat[13] = ["sgi", "SGI16", True]
  1729.         renderViewFormat[19] = ["tga", "Targa"]
  1730.         renderViewFormat[20] = ["bmp", "Windows Bitmap"]
  1731.         renderViewFormat[23] = ["avi", "AVI"]
  1732.         renderViewFormat[31] = ["psd", "Photoshop Document"]
  1733.         renderViewFormat[32] = ["png", "PNG"]
  1734.         renderViewFormat[35] = ["dds", "DirectDraw Surface"]
  1735.         renderViewFormat[36] = ["psd", "PSD Layered", True]
  1736.         renderViewFormat[51] = ["mr", "Mental Ray", True] #Mental Ray groups lots of formats under 51
  1737.         renderViewFormat[52] = ["vr", "V-Ray", True] #V-Ray uses it's own formats so this is a placeholder
  1738.        
  1739.         #Add any extra after here, only useful for the errors
  1740.         renderViewFormat[100] = ["jpeg", "JPEG"]
  1741.         renderViewFormat[101] = ["psb", "Large Document Format"]
  1742.         renderViewFormat[102] = ["3ds","3D Studio"]
  1743.         renderViewFormat[103] = ["ma", "Maya Ascii"]
  1744.         renderViewFormat[104] = ["mb", "Maya Binary"]
  1745.         renderViewFormat[105] = ["dea", "Collada"]
  1746.         renderViewFormat[109] = ["dcm", "Dicom"]
  1747.         renderViewFormat[110] = ["dc3", "Dicom"]
  1748.         renderViewFormat[111] = ["dic", "Dicom"]
  1749.         renderViewFormat[112] = ["eps", "Photoshop EPS"]
  1750.         renderViewFormat[113] = ["fl3", "Flash 3D"]
  1751.         renderViewFormat[114] = ["jpf", "JPEG 2000"]
  1752.         renderViewFormat[115] = ["jpx", "JPEG 2000"]
  1753.         renderViewFormat[116] = ["jp2", "JPEG 2000"]
  1754.         renderViewFormat[117] = ["j2c", "JPEG 2000"]
  1755.         renderViewFormat[118] = ["j2k", "JPEG 2000"]
  1756.         renderViewFormat[119] = ["jpc", "JPEG 2000"]
  1757.         renderViewFormat[120] = ["jps", "JPEG Stereo"]
  1758.         renderViewFormat[121] = ["mxi", "Maxwell Image"]
  1759.         renderViewFormat[122] = ["mpo", "Multi-Picture Format"]
  1760.         renderViewFormat[123] = ["exr", "OpenEXR"]
  1761.         renderViewFormat[124] = ["pxr", "Pixar"]
  1762.         renderViewFormat[125] = ["pbm", "Portable Bit Map"]
  1763.         renderViewFormat[126] = ["hdr", "Radiance"]
  1764.         renderViewFormat[127] = ["rgbe", "Radiance"]
  1765.         renderViewFormat[128] = ["xyze", "Radiance"]
  1766.         renderViewFormat[129] = ["sct", "Scitex CT"]
  1767.         renderViewFormat[130] = ["tiff", "Tiff"]
  1768.         renderViewFormat[131] = ["img", "V-Ray Image"]
  1769.         renderViewFormat[200] = ["3fr", "Hasselblad Raw"]
  1770.         renderViewFormat[201] = ["fff", "Hasselblad Raw"]
  1771.         renderViewFormat[202] = ["ari", "ARRIFLEX Raw"]
  1772.         renderViewFormat[203] = ["arw", "Sony Raw"]
  1773.         renderViewFormat[204] = ["srf", "Sony Raw"]
  1774.         renderViewFormat[205] = ["sr2", "Sony Raw"]
  1775.         renderViewFormat[206] = ["bay", "Casio Raw"]
  1776.         renderViewFormat[207] = ["crw", "Canon Raw"]
  1777.         renderViewFormat[208] = ["cr2", "Canon Raw"]
  1778.         renderViewFormat[209] = ["cap", "Phase_One Raw"]
  1779.         renderViewFormat[210] = ["liq", "Phase_One Raw"]
  1780.         renderViewFormat[211] = ["eip", "Phase_One Raw"]
  1781.         renderViewFormat[212] = ["dcs", "Kodak Raw"]
  1782.         renderViewFormat[213] = ["dcr", "Kodak Raw"]
  1783.         renderViewFormat[214] = ["drf", "Kodak Raw"]
  1784.         renderViewFormat[215] = ["k25", "Kodak Raw"]
  1785.         renderViewFormat[216] = ["kdc", "Kodak Raw"]
  1786.         renderViewFormat[217] = ["dng", "Adobe Raw"]
  1787.         renderViewFormat[218] = ["erf", "Epson Raw"]
  1788.         renderViewFormat[219] = ["mef", "Mamiya Raw"]
  1789.         renderViewFormat[220] = ["mdc", "Minolta Raw"]
  1790.         renderViewFormat[221] = ["mrw", "Minolta Raw"]
  1791.         renderViewFormat[222] = ["mos", "Leaf Raw"]
  1792.         renderViewFormat[223] = ["nef", "Nikon Raw"]
  1793.         renderViewFormat[224] = ["nrw", "Nikon Raw"]
  1794.         renderViewFormat[225] = ["orf", "Olympus Raw"]
  1795.         renderViewFormat[226] = ["pef", "Pentax Raw"]
  1796.         renderViewFormat[227] = ["ptx", "Pentax Raw"]
  1797.         renderViewFormat[228] = ["pxn", "Logitech Raw"]
  1798.         renderViewFormat[229] = ["r3d", "Red Raw"]
  1799.         renderViewFormat[230] = ["raf", "Fuji Raw"]
  1800.         renderViewFormat[231] = ["rw2", "Panasonic Raw"]
  1801.         renderViewFormat[232] = ["rwl", "Leica Raw"]
  1802.         renderViewFormat[233] = ["rwz", "Rawzor Raw"]
  1803.         renderViewFormat[234] = ["srw", "Samsung Raw"]
  1804.         renderViewFormat[235] = ["x3f", "Sigma Raw"]
  1805.        
  1806.         mentalRayFormats = {}
  1807.         mentalRayFormats["tifu"] = ["TIFF uncompressed"]
  1808.         mentalRayFormats["hdr"] = ["HDR"]
  1809.         mentalRayFormats["exr"] = [renderViewFormat[123][1], True]
  1810.         mentalRayFormats["picture"] = ["Dassault"]
  1811.         mentalRayFormats["ppm"] = ["Portable Pixmap"]
  1812.         mentalRayFormats["ps"] = ["PostScript"]
  1813.         mentalRayFormats["qntntsc"] = ["Quantel NTSC"]
  1814.         mentalRayFormats["ct"] = ["mentalray Color"]
  1815.         mentalRayFormats["st"] = ["mentalray Alpha"]
  1816.         mentalRayFormats["nt"] = ["mentalray Normal"]
  1817.         mentalRayFormats["mt"] = ["mentalray Motion"]
  1818.         mentalRayFormats["zt"] = ["mentalray Depth"]
  1819.         mentalRayFormats["tt"] = ["mentalray Tag"]
  1820.         mentalRayFormats["bit"] = ["mentalray Bit"]
  1821.         mentalRayFormats["cth"] = ["mentalray HDR"]
  1822.        
  1823.         VRayFormats = {}
  1824.         VRayFormats[1] = renderViewFormat[8]
  1825.         VRayFormats[2] = renderViewFormat[32]
  1826.         VRayFormats[3] = ["vrimg", "V-Ray Image"]
  1827.         VRayFormats[4] = renderViewFormat[123]
  1828.         VRayFormats[5] = ["exr", "OpenEXR (multichannel)", True]
  1829.         VRayFormats[6] = renderViewFormat[19]
  1830.         VRayFormats[7] = renderViewFormat[20]
  1831.         VRayFormats[8] = renderViewFormat[5]
  1832.         VRayFormats[9] = renderViewFormat[3]
  1833.        
  1834.         #Find current renderer
  1835.         try:
  1836.             allRenderers = py.renderer( q=True, namesOfAvailableRenderers=True ) #Not needed but leaving here in case it comes in useful
  1837.             currentRenderer = py.getAttr( "defaultRenderGlobals.currentRenderer") #mayaSoftware/mayaHardware/mayaHardware2/mentalRay/vray
  1838.         except:
  1839.             currentRenderer = None
  1840.        
  1841.         #Assign MR setting to index 51
  1842.         if currentRenderer == "mentalRay":
  1843.             try:
  1844.                 sceneExtension = py.getAttr( "defaultRenderGlobals.imfkey" ).lower()
  1845.                 sceneExtensionDict = mentalRayFormats.get( sceneExtension, None )
  1846.                 if py.getAttr( "defaultRenderGlobals.imageFormat" ) == 51 and sceneExtensionDict:
  1847.                     renderViewFormat[51] = [[sceneExtension] + sceneExtensionDict]
  1848.             except:
  1849.                 pass
  1850.        
  1851.         #Assign V-Ray setting to index 52
  1852.         if currentRenderer == "vray":
  1853.             try:
  1854.                 py.setAttr( "defaultRenderGlobals.imageFormat", 52 )
  1855.                 vRayFormat = py.getAttr( "vraySettings.imageFormatStr" )
  1856.                 vRayFormatList = dict( [[value[0],value] for key, value in VRayFormats.iteritems()] )
  1857.                 renderViewFormat[52] = vRayFormatList[ py.getAttr( "vraySettings.imageFormatStr" ) ]
  1858.                
  1859.             except:
  1860.                 pass
  1861.        
  1862.        
  1863.         ignoreFormats = [8, 20, 31, 32, 100]
  1864.         uploadFormats = [0, 8, 20, 32, 100]
  1865.        
  1866.         return renderViewFormat, ignoreFormats, uploadFormats
  1867.    
  1868.     #Format the time float into a date
  1869.     def dateFormat( self, input ):
  1870.         return datetime.fromtimestamp( float( input ) ).strftime( '%d/%m/%Y %H:%M' )
  1871.  
  1872.     #Find if path/file exists
  1873.     def validPath( self, path, **kwargs ):
  1874.        
  1875.         #This will truncate the final slash, to make sure the directory exists
  1876.         includeFile = checkInputs.checkBooleanKwargs( kwargs, False, 'f', 'iF', 'iI', 'file', 'image', 'include', 'isFile', 'isImage', 'includeFile', 'includeImage', 'includesFile', 'includesImage' )
  1877.        
  1878.         path = str( path )
  1879.        
  1880.         #Check URL and local paths separately
  1881.         if any( value in path for value in self.protocols ):
  1882.             try:
  1883.                 Image.open( cStringIO.StringIO( urllib2.urlopen( path ).read() ) )
  1884.                 isValid = True
  1885.             except:
  1886.                 isValid = False
  1887.                
  1888.         else:
  1889.             if includeFile and "." in path.rsplit( '/', 1 )[1]:
  1890.                 path = path.rsplit( '/', 1 )[0]
  1891.                
  1892.             isValid = os.path.exists( path )
  1893.        
  1894.        
  1895.         return isValid
  1896.  
  1897.     #Work out pixel values to affect
  1898.     def validRange( self, cutoffMode, bitsPerColour ):
  1899.        
  1900.         cutoffRange = pow( 2, bitsPerColour )
  1901.        
  1902.         if cutoffMode < 5:
  1903.             colourMinIncrease = 0
  1904.             colourMaxIncrease = cutoffMode*64-cutoffRange-1
  1905.             colourMaxReduce = 255
  1906.             colourMinReduce = cutoffMode*64+cutoffRange
  1907.         elif cutoffMode < 8:
  1908.             cutoffMode -= 4
  1909.             colourMinIncrease = cutoffMode*64
  1910.             colourMaxIncrease = 255-cutoffRange
  1911.             colourMinReduce = cutoffRange
  1912.             colourMaxReduce = cutoffMode*64-1
  1913.         else:
  1914.             colourMinIncrease = 0
  1915.             colourMaxIncrease = -1
  1916.             colourMinReduce = 255
  1917.             colourMaxReduce = 254
  1918.        
  1919.         colourIncreaseRange = xrange( colourMinIncrease, colourMaxIncrease+1 )
  1920.         colourReduceRange = xrange( colourMinReduce, colourMaxReduce+1 )
  1921.        
  1922.         return colourIncreaseRange, colourReduceRange
  1923.        
  1924.     def cache( self, *args, **kwargs ):
  1925.        
  1926.         #Read file
  1927.         cachePath = "{0}/{1}".format( self.defaultCacheDirectory, self.defaultCacheName )
  1928.         try:
  1929.             with open( cachePath, "r" ) as textFile:
  1930.                 content = textFile.read()
  1931.         except:
  1932.             with open( cachePath, "w" ) as textFile:
  1933.                 content = self.encodeData( {}, encode = True )
  1934.                 textFile.write( content )
  1935.        
  1936.         #If it should be formatted        
  1937.         returnRawValues = checkInputs.checkBooleanKwargs( kwargs, False, 'raw', 'rawValue' )
  1938.  
  1939.         #Return the path
  1940.         returnPath = checkInputs.checkBooleanKwargs( kwargs, False, 'path', 'cachePath', 'loc', 'location', 'cacheLocation', 'returnPath', 'returnLoc', 'returnLocation' )
  1941.         if returnPath:
  1942.             return cachePath
  1943.        
  1944.         #Decode data
  1945.         try:
  1946.             outputData = self.decodeData( content, decode = True )
  1947.         except:
  1948.             outputData = None
  1949.        
  1950.         #Delete the cache file
  1951.         validArgs = checkInputs.validKwargs( kwargs, 'c', 'clear', 'clean', 'clearCache', 'cleanCache', 'delete', 'delCache', 'deleteCache' )
  1952.         for i in xrange( len( validArgs ) ):
  1953.             try:
  1954.                 if kwargs[validArgs[i]]:
  1955.                     try:
  1956.                         os.remove( cachePath )
  1957.                         break
  1958.                     except:
  1959.                         pass
  1960.                 #Only remove individual record instead
  1961.                 elif type( kwargs[validArgs[i]] ) == str and outputData:
  1962.                     outputData.pop( kwargs[validArgs[i]], None )
  1963.             except:
  1964.                 pass
  1965.        
  1966.         #Delete individual value
  1967.         if outputData:
  1968.             validArgs = checkInputs.validKwargs( kwargs, 'delValue', 'delKey', 'deleteValue', 'deleteKey', 'clearValue', 'clearKey', 'removeValue', 'removeKey' )
  1969.             deleteValue = None
  1970.             for i in xrange( len( validArgs ) ):
  1971.                 outputData.pop( kwargs[validArgs[i]], None )
  1972.                
  1973.             #Write back to cache
  1974.             try:
  1975.                 with open( cachePath, "w") as textFile:
  1976.                     textFile.write( self.encodeData( outputData, encode = True ) )
  1977.             except:
  1978.                 pass
  1979.            
  1980.             #Return single value
  1981.             validArgs = checkInputs.validKwargs( kwargs, 'k', 'v', 'key', 'value' )
  1982.             keyValue = None
  1983.             for i in xrange( len( validArgs ) ):
  1984.                 try:
  1985.                     keyValue = outputData[kwargs[validArgs[i]]]
  1986.                     break
  1987.                 except:
  1988.                     keyValue = None
  1989.                    
  1990.             if validArgs:
  1991.                 if keyValue:
  1992.                     return self.formatCache( {kwargs[validArgs[i]]: keyValue}, returnRawValues )
  1993.                 else:
  1994.                     return None
  1995.  
  1996.            
  1997.         #If the hash should be calculated
  1998.         validArgs = checkInputs.validKwargs( kwargs, 'h', 'hash', 'returnHash', 'calculateHash', 'imageHash', 'MD5', 'imageMD5', 'image' )
  1999.         returnHash = None
  2000.        
  2001.         for i in xrange( len( validArgs ) ):
  2002.             try:
  2003.                 if kwargs[validArgs[i]]:
  2004.                     returnHash = self.imageName
  2005.                     break
  2006.                 elif self.readImage( str( kwargs[validArgs[i]] ) ):
  2007.                     returnHash = str( kwargs[validArgs[i]] )
  2008.                     break
  2009.                 else:
  2010.                     raise ImageStoreError( "can't read image" )
  2011.             except:
  2012.                 returnHash = None
  2013.                
  2014.         #If the hash should be returned
  2015.         if returnHash:
  2016.        
  2017.             customImage = self.readImage( returnHash )
  2018.            
  2019.             if not customImage:
  2020.                 return None
  2021.            
  2022.             else:
  2023.        
  2024.                 #Find md5 of image
  2025.                 imageHash = md5.new()
  2026.                 try:
  2027.                     imageHash.update( customImage.tostring() )
  2028.                 except:
  2029.                     pass
  2030.                 imageMD5 = imageHash.hexdigest()
  2031.                
  2032.                 return imageMD5
  2033.                
  2034.         elif validArgs:
  2035.             return None
  2036.        
  2037.         #If the hash has been input as an arg
  2038.         if args:
  2039.             try:
  2040.                 #Make sure outputData is a dictionary, and not None
  2041.                 if outputData.get( args[0], None ):
  2042.                     imageHash = args[0]
  2043.                 else:
  2044.                     #Double check it's not an image link
  2045.                     newMD5 = self.cache( ImageMD5 = args[0] )
  2046.                     if outputData.get( newMD5, None ):
  2047.                         imageHash = newMD5
  2048.                     else:
  2049.                         raise ImageStoreError()
  2050.             except:
  2051.                 imageHash = ImageStore().cache( MD5 = args[0] )
  2052.                
  2053.             try:
  2054.                 if outputData.get( imageHash, None ):
  2055.                     outputData = ImageStore().cache( key = imageHash, raw = True )
  2056.                 else:
  2057.                     raise ImageStoreError()
  2058.             except:
  2059.                 return None
  2060.        
  2061.         #Return the stored data
  2062.         if outputData:
  2063.             return self.formatCache( outputData, returnRawValues )
  2064.         else:
  2065.             return None
  2066.  
  2067.     def formatCache( self, outputData, returnRawValues=False ):  
  2068.    
  2069.         if returnRawValues:
  2070.             return outputData
  2071.        
  2072.         cacheOutput = []
  2073.         if outputData:
  2074.             for imageHash in outputData.keys():
  2075.                 cacheOutput.append( "Hash: {0}".format( imageHash ) )
  2076.                
  2077.                 if outputData[imageHash][2]:
  2078.                     cacheOutput.append( "   URL: {0}".format( outputData[imageHash][2] ) )
  2079.                 cacheOutput.append( "   Best cutoff mode: {0}".format( outputData[imageHash][0] ) )
  2080.                
  2081.                 for cutoffMode in outputData[imageHash][1].keys():
  2082.                     if outputData[imageHash][1][cutoffMode]:
  2083.                         cacheOutput.append( "      Cutoff mode {0}:".format( cutoffMode ) )
  2084.                         for bitsPerPixel in outputData[imageHash][1][cutoffMode].keys():
  2085.                             cacheOutput.append( "         Storage with {0} bits per pixel: {1}".format( bitsPerPixel, outputData[imageHash][1][cutoffMode][bitsPerPixel]*bitsPerPixel ) )
  2086.         else:
  2087.             cacheOutput.append( "Cache file was corrupted, it has now been reset" )
  2088.             self.cache( cleanCache = True )
  2089.        
  2090.         return GlobalValues.newLine.join( cacheOutput )
  2091.        
  2092.     def readImage( self, location ):
  2093.        
  2094.         location = str( location )
  2095.        
  2096.         #Load from URL
  2097.         if any( value in location for value in self.protocols ):
  2098.                        
  2099.             try:
  2100.                 location = cStringIO.StringIO( urllib2.urlopen( location ).read() )
  2101.                
  2102.             except:
  2103.                 return None
  2104.                
  2105.         #Open image
  2106.         try:
  2107.             return Image.open( location ).convert( "RGB" )
  2108.            
  2109.         except:
  2110.             return None
  2111.  
  2112.     def lowercase( self, input=None ):
  2113.        
  2114.         if input != None: #Allows false to be used
  2115.             input = str( input )
  2116.         else:
  2117.             return None
  2118.            
  2119.         if len( input ) == 0:
  2120.             return input
  2121.         elif len( input ) == 1:
  2122.             return input.lower()
  2123.         else:
  2124.             return input[0].lower() + input[1:]
  2125.            
  2126.     def renderView( self, save=True ):
  2127.        
  2128.         renderViewFormat, ignoreFormats, uploadFormats = self.imageFormats()
  2129.         formatList = dict( [[item[0], key] for key, item in renderViewFormat.iteritems() if len( item ) == 2] )
  2130.        
  2131.         #To get around True = 1 and False = 0
  2132.         valueType = type( save )
  2133.        
  2134.         #Save file
  2135.         if valueType == bool:
  2136.        
  2137.             if save:
  2138.                 try:
  2139.                     self.renderViewSaveLocation = py.renderWindowEditor( 'renderView', edit = True, writeImage = self.renderViewSaveLocation )[1]
  2140.                 except:
  2141.                     pass
  2142.                    
  2143.             #Delete file
  2144.             else:
  2145.                 try:
  2146.                     os.remove( self.renderViewSaveLocation )
  2147.                 except:
  2148.                     try:
  2149.                         os.remove( "{0}.{1}".format( self.renderViewSaveLocation, self.imageFormats()[0][py.getAttr( "defaultRenderGlobals.imageFormat" )][0] ) )
  2150.                     except:
  2151.                         pass
  2152.        
  2153.         #Set scene format to index value
  2154.         elif valueType == int or ( valueType == str and save.isdigit() ):
  2155.             try:
  2156.                 if 0 <= int( save ) < 64:
  2157.                     py.setAttr( "defaultRenderGlobals.imageFormat", int( save ) )
  2158.                     py.setAttr( "defaultRenderGlobals.imfkey", renderViewFormat[int( save )] )
  2159.                 else:
  2160.                     raise RangeError( "value must be between 0 and 63" )
  2161.             except:
  2162.                 self.printCurrentProgress( "Error: Index must be between 0 and 63." )
  2163.        
  2164.         #Set scene format to filetype
  2165.         elif valueType == str:
  2166.            
  2167.             formatDict = formatList.get( save.lower(), None )
  2168.             if formatDict:
  2169.            
  2170.                 try:
  2171.                     py.setAttr( "defaultRenderGlobals.imageFormat", formatDict )
  2172.                     py.setAttr( "defaultRenderGlobals.imfkey", save.lower() )
  2173.                 except:
  2174.                     self.printCurrentProgress( "Error: Can't update scene settings." )
  2175.            
  2176.            
  2177.  
  2178. #Compress into zip file
  2179. class ImageStoreZip:
  2180.    
  2181.     zipName = "ImageInfo.zip"
  2182.        
  2183.     @classmethod
  2184.     def write( self, input, fileName, **kwargs ):
  2185.        
  2186.         #Reset if already exists
  2187.         resetZip = checkInputs.checkBooleanKwargs( kwargs, False, 'r', 'd', 'reset', 'delete', 'resetZip', 'deleteZip', 'resetFile', 'deleteFile', 'resetZipFile', 'deleteZipFile' )
  2188.        
  2189.         #Get location to store zip file
  2190.         path = ImageStore.defaultImageDirectory
  2191.            
  2192.         #Remove final slash
  2193.         path.replace( "\\", "/" )
  2194.         while path[-1] == "/":
  2195.             path = path[:-1]
  2196.        
  2197.         if not ImageStore().validPath( path ):
  2198.             return False
  2199.            
  2200.         else:
  2201.             zipLocation = "{0}/{1}".format( path, self.zipName )
  2202.             if resetZip:
  2203.                 try:
  2204.                     os.remove( zipLocation )
  2205.                 except:
  2206.                     pass
  2207.                    
  2208.             zip = zipfile.ZipFile( zipLocation, mode='a', compression=zipfile.ZIP_DEFLATED )
  2209.            
  2210.             try:
  2211.                 zip.writestr( fileName, input )
  2212.             except:
  2213.                 self.printCurrentProgress( "Error: Failed to write zip file.", True )
  2214.             zip.close()
  2215.    
  2216.     @classmethod
  2217.     def read( self, **kwargs ):
  2218.        
  2219.         #Get image location
  2220.         validArgs = checkInputs.validKwargs( kwargs, 'i', 'iL', 'iN', 'image', 'imageLoc', 'imageLocation', 'imageName' )
  2221.         imageLocation = None
  2222.        
  2223.         for i in xrange( len( validArgs ) ):
  2224.        
  2225.             try:
  2226.                 imageLocation = kwargs[validArgs[i]]
  2227.                
  2228.                 if ImageStore().validPath( imageLocation ):
  2229.                     break
  2230.                 else:
  2231.                     raise IOError( "image doesn't exist" )
  2232.                    
  2233.             except:
  2234.                 imageLocation = None
  2235.                
  2236.         #Read if zip file
  2237.         if any( value in imageLocation for value in ImageStore.protocols ):
  2238.        
  2239.             imageLocation = cStringIO.StringIO( urllib2.urlopen( imageLocation ).read() )
  2240.            
  2241.             if zipfile.is_zipfile( imageLocation ):
  2242.                 zip = zipfile.ZipFile( imageLocation )
  2243.             else:
  2244.                 zip = None
  2245.                
  2246.         elif zipfile.is_zipfile( imageLocation ):
  2247.             zip = zipfile.ZipFile( imageLocation )
  2248.            
  2249.         else:
  2250.             zip = None
  2251.            
  2252.         #Read zip data
  2253.         if zip:
  2254.             nameList = zip.namelist()
  2255.                        
  2256.             if 'creationtime' in nameList:
  2257.            
  2258.                 if 'version' in nameList:
  2259.                     versionNumber = zip.read( 'version' )
  2260.                    
  2261.                 else:
  2262.                     versionNumber = "pre-2.0"
  2263.                    
  2264.                 creation = zip.read( 'creationtime' )
  2265.                    
  2266.                 if "@" in creation:
  2267.                     creationName = creation.split( "@" )[0]
  2268.                     creationTime = creation.split( "@" )[1]
  2269.                 else:
  2270.                     creationName = None
  2271.                     creationTime = None
  2272.                    
  2273.             else:
  2274.                 versionNumber = None
  2275.                 creationName = None
  2276.                 creationTime = None
  2277.                
  2278.             if 'url' in nameList:
  2279.                 customURL = zip.read( 'url' )
  2280.             else:
  2281.                 customURL = None
  2282.        
  2283.         else:
  2284.             versionNumber = "pre-2.0"
  2285.             creationName = None
  2286.             creationTime = None
  2287.             customURL = None
  2288.        
  2289.         return [versionNumber, creationTime, creationName, customURL, nameList]
  2290.    
  2291.     @classmethod
  2292.     def combine( self, **kwargs ):
  2293.        
  2294.         #Get location to read zip file
  2295.         path = "{0}/{1}".format( ImageStore.defaultImageDirectory, self.zipName )
  2296.            
  2297.         if not ImageStore().validPath( path ):
  2298.             return False
  2299.        
  2300.         #Get image location
  2301.         validArgs = checkInputs.validKwargs( kwargs, 'i', 'iL', 'iN', 'image', 'imageLoc', 'imageLocation', 'imageName' )
  2302.         imageLocation = None
  2303.        
  2304.         for i in xrange( len( validArgs ) ):
  2305.        
  2306.             try:
  2307.                 imageLocation = kwargs[validArgs[i]]
  2308.                 if ImageStore().validPath( imageLocation ):
  2309.                     break
  2310.                 else:
  2311.                     imageLocation = None
  2312.                     raise IOError( "image doesn't exist" )
  2313.                    
  2314.             except:
  2315.                 imageLocation = None
  2316.        
  2317.         #Get zip location        
  2318.         validArgs = checkInputs.validKwargs( kwargs, 'z', 'zL', 'zN', 'zip', 'zipLoc', 'zipLocation', 'zipName' )
  2319.         zipLocation = path
  2320.         for i in xrange( len( validArgs ) ):
  2321.        
  2322.             try:
  2323.                 zipLocation = kwargs[validArgs[i]]
  2324.                 if ImageStore().validPath( zipLocation ):
  2325.                     break
  2326.                 else:
  2327.                     zipLocation = path
  2328.                     raise IOError( "zip file doesn't exist" )
  2329.                    
  2330.             except:
  2331.                 zipLocation = path
  2332.        
  2333.         if imageLocation:
  2334.        
  2335.             locationOfImage = imageLocation.replace( "/", "\\\\" )
  2336.             locationOfZip = zipLocation.replace( "/", "\\\\" )
  2337.            
  2338.             #Copy zip file into picture
  2339.             call( 'copy /b "{0}" + "{1}" "{0}"'.format( locationOfImage, locationOfZip ), shell=True)
  2340.            
  2341.             os.remove( zipLocation )
  2342.            
  2343.             return True
  2344.            
  2345.         else:
  2346.             return False
  2347.  
  2348. class checkInputs:
  2349.    
  2350.     @classmethod
  2351.     def capitalLetterCombinations( self, *args ):
  2352.    
  2353.         returnList = []
  2354.         args = list( args )
  2355.        
  2356.         #Deal with spaces
  2357.         joinedArg = {}
  2358.         for arg in args:
  2359.             if " " in str( arg ):
  2360.                 splitArg = str( arg ).split( " " )
  2361.                 for i in xrange( len( splitArg ) ):
  2362.                     joinedArg[i] = self.capitalLetterCombinations( splitArg[i] )
  2363.        
  2364.         #Put together all combinations
  2365.         newArgs = ["".join( list( tupleValue ) ) for tupleValue in list( itertools.product( *[item for key, item in joinedArg.iteritems()] ) )]
  2366.         newArgs += [" ".join( list( tupleValue ) ) for tupleValue in list( itertools.product( *[item for key, item in joinedArg.iteritems()] ) )]
  2367.            
  2368.         #Check they don't exist
  2369.         for newArg in newArgs:
  2370.             if newArg not in args:
  2371.                 args.append( newArg )
  2372.                
  2373.         #Find different upper and lower case combinations
  2374.         for arg in args :
  2375.            
  2376.             returnList.append( arg )
  2377.            
  2378.             if any( map( str.isupper, arg ) ):
  2379.            
  2380.                 #If capital in text but not first letter
  2381.                 if not map( str.isupper, arg[0] )[0]:
  2382.                     returnList.append( ''.join( word[0].upper() + word[1:] for word in arg.split() ) )
  2383.                     returnList.append( arg.capitalize() )
  2384.                    
  2385.                 #If capital is anywhere in the name as well as also first letter
  2386.                 elif any( map( str.isupper, arg[1:] ) ):
  2387.                     returnList.append( arg.capitalize() )
  2388.                    
  2389.                 returnList.append( arg.lower() )
  2390.                
  2391.             else:
  2392.            
  2393.                 #If no capital letter is in at all
  2394.                 returnList.append( ''.join( word[0].upper() + word[1:] for word in arg.split() ) )
  2395.        
  2396.        
  2397.         return sorted( set( filter( len, returnList ) ) )
  2398.    
  2399.     @classmethod
  2400.     def validKwargs( self, kwargs, *args ):
  2401.    
  2402.         valid = []
  2403.        
  2404.         for i in xrange( len( args ) ):
  2405.             newArgs = checkInputs.capitalLetterCombinations( args[i] )
  2406.            
  2407.             for value in newArgs:
  2408.            
  2409.                 try:
  2410.                     kwargs[ value ]
  2411.                     if value not in valid:
  2412.                         valid.append( value )
  2413.                        
  2414.                 except:
  2415.                     pass
  2416.                    
  2417.         return valid
  2418.    
  2419.     @classmethod    
  2420.     def checkBooleanKwargs( self, kwargs, default, *args ):
  2421.        
  2422.         opposite = not default
  2423.         validArgs = []
  2424.        
  2425.         for i in xrange( len( args ) ):
  2426.             validArgs += checkInputs.validKwargs( kwargs, args[i] )
  2427.        
  2428.         try:
  2429.             if kwargs[validArgs[0]] == opposite:
  2430.                 return opposite
  2431.             else:
  2432.                 return default
  2433.         except:
  2434.             return default
  2435.    
  2436.     @classmethod
  2437.     def joinList( self, *args ):
  2438.        
  2439.         allCombinations = list( itertools.product( *args ) )
  2440.         joinedValues = ["".join( list( tupleValue ) ) for tupleValue in allCombinations]
  2441.        
  2442.         return tuple( joinedValues )
  2443.  
  2444. class RangeError( Exception ):
  2445.     pass
  2446. class ImageStoreError( Exception ):
  2447.     pass
  2448.  
  2449.  
  2450. class MayaUserInterface:
  2451.    
  2452.     windowName = "ImageStore"
  2453.     windowWidth = 550.0
  2454.    
  2455.     buttonList = {}
  2456.     textList = {}
  2457.     textFieldList = {}
  2458.     checkBoxList = {}
  2459.     radioButtonList = {}
  2460.     floatSliderGrpList = {}
  2461.     scrollFieldList = {}
  2462.     frameLayoutList = {}
  2463.     progressBarList = {}
  2464.    
  2465.     #Function to refresh a few values
  2466.     @classmethod
  2467.     def setFinalValues( self ):
  2468.    
  2469.         mainImageCheck = py.button( self.buttonList['ValidateMainImage'], query = True, command = True )
  2470.         customImageCheck = py.button( self.buttonList['ValidateCustomImage'], query = True, command = True )
  2471.         py.textField( self.textFieldList["MainImagePath"], edit = True, changeCommand = py.Callback( mainImageCheck ), enterCommand = py.Callback( mainImageCheck ) )
  2472.         py.textField( self.textFieldList["CustomImagePath"], edit = True, changeCommand = py.Callback( customImageCheck ), enterCommand = py.Callback( customImageCheck ) )
  2473.         self.saveOutputAsFile()
  2474.         self.uploadCheckBox()
  2475.         self.checkPathToImage( False )
  2476.    
  2477.     #Build the user interface
  2478.     @classmethod
  2479.     def display( self ):
  2480.  
  2481.         #Delete window
  2482.         if py.window( self.windowName + "UI", exists = True ):
  2483.             py.deleteUI( self.windowName + "UI", window = True )
  2484.        
  2485.         #Create window
  2486.         mainWindow = py.window( self.windowName + "UI", title = self.windowName, resizeToFitChildren = True, minimizeButton = True, maximizeButton = False, sizeable = False, width = self.windowWidth, restoreCommand = py.Callback( self.changeSceneSettings ) )
  2487.        
  2488.         with py.rowColumnLayout( numberOfColumns = 1 ):
  2489.             py.text( label = "Use this to store or read information within images. They can be uploaded anywhere and read from other computers.", align = "left" )
  2490.             py.text( label = "" )
  2491.        
  2492.         with py.rowColumnLayout( numberOfColumns = 7 ):
  2493.             py.text( label = "", width = self.windowWidth/100*1 )
  2494.             py.text( label = " Path to image:", width = self.windowWidth/100*50, align = "left" )
  2495.             py.text( label = "", width = self.windowWidth/100*1 )
  2496.             py.text( label = "", width = self.windowWidth/100*25 )
  2497.             py.text( label = "", width = self.windowWidth/100*1 )
  2498.             self.textList["ValidateMainImage"] = py.text( label = "0", width = self.windowWidth/100*21, visible = False )
  2499.             py.text( label = "", width = self.windowWidth/100*1 )
  2500.             py.text( label = "" )
  2501.             self.textFieldList["MainImagePath"] = py.textField( text = "{0}/{1}".format( ImageStore.defaultImageDirectory, ImageStore.defaultImageName ), annotation = "Choose a path to save the file to, or a path or URL to read a file from" )
  2502.             py.text( label = "" )
  2503.            
  2504.             with py.rowColumnLayout( numberOfColumns = 2 ):
  2505.                 self.buttonList["NewImage"] = py.button( label = "New Image", width = self.windowWidth/100*12.5, command = py.Callback( self.fileReading, True, True, "textField", "MainImagePath", "ValidateMainImage" ), annotation = "Save a new image" )
  2506.                 self.buttonList["BrowseImage"] = py.button( label = "Browse", width = self.windowWidth/100*12.5, command = py.Callback( self.fileReading, False, True, "textField", "MainImagePath", "ValidateMainImage" ), annotation = "Open an existing image" )
  2507.                
  2508.             py.text( label = "" )
  2509.             self.buttonList["ValidateMainImage"] = py.button( label = "Check if valid", command = py.Callback( self.checkPathToImage ), annotation = "Check if the image exists or if it's possible to write to the location" )
  2510.             py.text( label = "" )
  2511.             py.text( label = "" )
  2512.             py.text( label = "" )
  2513.             py.text( label = "" )
  2514.             py.text( label = "" )
  2515.             py.text( label = "" )
  2516.            
  2517.             with py.rowColumnLayout( numberOfColumns = 2 ):
  2518.                 self.checkBoxList["ImagePathExists"] = py.checkBox( label = "Image", editable = False )
  2519.                 self.checkBoxList["ImagePathWriteable"] = py.checkBox( label = "Writeable", editable = False )
  2520.                
  2521.             py.text( label = "" )
  2522.             py.text( label = "" )
  2523.            
  2524.             self.textList["CustomImagePath"] = py.text( label = " Path to custom image (optional):", align = "left" )
  2525.             py.text( label = "" )
  2526.             py.text( label = "" )
  2527.             py.text( label = "" )
  2528.             self.textList["ValidateCustomImage"] = py.text( label = "0", visible = False )
  2529.             py.text( label = "" )
  2530.             py.text( label = "" )
  2531.             self.textFieldList["CustomImagePath"] = py.textField( annotation = "Choose a path or URL to an image (optional)" )
  2532.             py.text( label = "" )
  2533.            
  2534.             with py.rowColumnLayout( numberOfColumns = 2 ):
  2535.                 self.buttonList["BrowseCustomImage"] = py.button( label = "Browse", command = py.Callback( self.fileReading, False, True, "textField", "CustomImagePath", "ValidateCustomImage" ), annotation = "Open an image" )
  2536.                 self.buttonList["UseRenderView"] = py.button( label = "Use Render View", command = py.Callback( self.useRenderView ), annotation = "Use the image currently in the Render View window" )
  2537.                
  2538.             py.text( label = "" )
  2539.             self.buttonList["ValidateCustomImage"] = py.button( label = "Check if valid", command = py.Callback( self.checkPathToCustomImage ), annotation = "Check if the file can be read as an image, and if any information exists in the cache" )
  2540.            
  2541.             py.text( label = "" )
  2542.             py.text( label = "" )
  2543.             self.checkBoxList["DisableCustomImage"] = py.checkBox( label = "Disable custom image", changeCommand = py.Callback( self.disableCustomImage ), annotation = "Disable the custom image features" )
  2544.            
  2545.             py.text( label = "" )
  2546.             with py.rowColumnLayout( numberOfColumns = 2 ):
  2547.                
  2548.                 py.button( label = "Browse", visible = False )
  2549.                
  2550.                 with py.rowColumnLayout( numberOfColumns = 3 ):
  2551.                     self.buttonList["RenderView"] = {}
  2552.                     self.renderViewFormats = ["jpg", "png", "bmp"]
  2553.                     imageFormatsDict = dict( [[item[0], item[1]] for key, item in ImageStore().imageFormats()[0].iteritems() if len( item ) == 2] )
  2554.                     for i in xrange( 3 ):
  2555.                        
  2556.                         self.buttonList["RenderView"][self.renderViewFormats[i]] = py.button( label = self.renderViewFormats[i].upper(), command = py.Callback( self.changeSceneSettings, self.renderViewFormats[i].lower() ), annotation = "Set the scene to use {0} files".format( imageFormatsDict[self.renderViewFormats[i].lower()] ) )
  2557.                    
  2558.                     self.changeSceneSettings()
  2559.                    
  2560.             py.text( label = "" )
  2561.            
  2562.             with py.rowColumnLayout( numberOfColumns = 2 ):
  2563.                 self.checkBoxList["CustomImageIsImage"] = py.checkBox( label = "Image", editable = False )
  2564.                 self.checkBoxList["CustomImageIsCached"] = py.checkBox( label = "Cached", editable = False )
  2565.                
  2566.             py.text( label = "" )
  2567.        
  2568.         with py.tabLayout( width = self.windowWidth ):
  2569.    
  2570.             with py.columnLayout( "Main" ):
  2571.                
  2572.                 with py.frameLayout( label = "Write", collapsable = True, collapse = False, width = self.windowWidth/100*101 ) as self.frameLayoutList["MainWrite"]:
  2573.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2574.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*50 ):
  2575.                            
  2576.                             py.text( label = "   Input data:", align = "left", width = self.windowWidth/100*45.2 )
  2577.                             self.textFieldList["InputData"] = py.textField( text = "Store this text in an image", changeCommand = py.Callback( self.validateInput ), annotation = "Write anything to store in an image" )
  2578.                            
  2579.                             inputRadioAnnotation = "Choose how to treat the input data"
  2580.                            
  2581.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2582.                                 py.radioCollection()
  2583.                                 self.radioButtonList["InputIsText"] = py.radioButton( label = "Convert input to string or integer", width = self.windowWidth/100*35.2, select = True, annotation = inputRadioAnnotation )
  2584.                                 py.text( label = "" )
  2585.                                 self.buttonList["ValidateInputHidden"] = py.button( label = "Validate", visible = False ) #Just for the spacing
  2586.                            
  2587.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2588.                                 self.radioButtonList["InputIsCode"] = py.radioButton( label = "Use input as code", width = self.windowWidth/100*35.9, onCommand = py.Callback( self.validateInput, "code" ), annotation = inputRadioAnnotation )
  2589.                                 py.text( label = "" )
  2590.                                 self.buttonList["ValidateInputCode"] = py.button( label = "Validate", command = py.Callback( self.validateInput, "code" ), annotation = "Check if the input can be parsed as code", width = self.windowWidth/100*9 )
  2591.                            
  2592.                             with py.rowColumnLayout( numberOfColumns = 5 ):
  2593.                                 self.radioButtonList["InputIsFile"] = py.radioButton( label = "Input is file path", width = self.windowWidth/100*26, onCommand = py.Callback( self.validateInput, "file" ), annotation = inputRadioAnnotation )
  2594.                                 py.text( label = "" )
  2595.                                 py.button( label = "Browse", command = py.Callback( self.validateInput, "browse" ), annotation = "Choose a file to store", width = self.windowWidth/100*9 )
  2596.                                 py.text( label = "" )
  2597.                                 self.buttonList["ValidateInputFile"] = py.button( label = "Validate", command = py.Callback( self.validateInput, "file" ), annotation = "Check if the file can be read", width = self.windowWidth/100*9 )
  2598.        
  2599.                         py.text( label = "", width = self.windowWidth/100*1 )
  2600.                        
  2601.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*50 ):
  2602.                             py.text( label = "   Upload:", align="left" )
  2603.                             self.checkBoxList["UploadMainImage"] = py.checkBox( label = "Upload output image", changeCommand = py.Callback( self.uploadCheckBox ), annotation = "Upload the encoded image" )
  2604.                             self.checkBoxList["OpenMainImage"] = py.checkBox( label = "Open uploaded image in browser", annotation = "Open the URL in a browser" )
  2605.                             self.checkBoxList["UploadCustomImage"] = py.checkBox( label = "Upload custom image (recommended)", value = True, annotation = "Upload the original custom image" )
  2606.                             py.text( label = "" )
  2607.                             py.text( label = "   Set ratio of width to height:", align="left" )
  2608.                             self.floatSliderGrpList["Ratio"] = py.floatSliderGrp( field = True, minValue = 0.2, maxValue = 0.8, fieldMinValue = 0.0001, fieldMaxValue = 0.9999, precision = 4, value = math.log( 1920 ) / math.log( 1920*1080 ), annotation = "Set width to height ratio for when not using custom images" )
  2609.        
  2610.                
  2611.                 with py.frameLayout( label = "Read", collapsable = True, collapse = False, width = self.windowWidth/100*101 ) as self.frameLayoutList["MainRead"]:
  2612.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2613.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*50 ):
  2614.                            
  2615.                             py.radioCollection()
  2616.                            
  2617.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2618.                                 self.radioButtonList["ReturnAll"] = py.radioButton( label = "Return all data", annotation = "Output all data" )
  2619.                                 py.textField( width = self.windowWidth/100*10, visible = False )
  2620.                                 py.text( label = "" )
  2621.                            
  2622.                             with py.rowColumnLayout( numberOfColumns = 3, annotation = "Output up to a maximum amount of data" ):
  2623.                                 returnSomeDataCommand = py.Callback( self.returnSomeData )
  2624.                                 self.radioButtonList["ReturnSome"] = py.radioButton( label = "Return ", select = True  )
  2625.                                 self.textFieldList["ReturnSome"] = py.textField( text = 100000, width = self.windowWidth/100*10, receiveFocusCommand = returnSomeDataCommand, changeCommand = returnSomeDataCommand, enterCommand = returnSomeDataCommand )
  2626.                                 py.text( label = " characters of data" )
  2627.                        
  2628.                         py.text( label = "", width = self.windowWidth/100*1 )
  2629.                        
  2630.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*50 ):
  2631.                             self.checkBoxList["SaveAsFile"] = py.checkBox( label = "Save as file", changeCommand = py.Callback( self.saveOutputAsFile ), annotation = "Save the output data as a file" )
  2632.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2633.                                 self.textFieldList["SaveAsFile"] = py.textField( width = self.windowWidth/100*38, annotation = "Choose a location to save to" )
  2634.                                 py.text( label = "" )
  2635.                                 self.buttonList["SaveAsFile"] = py.button( label = "Browse", command = py.Callback( self.fileReading, True, False, "textField", "SaveAsFile" ), annotation = "Save a new file" )
  2636.                                
  2637.                     with py.rowColumnLayout( numberOfColumns = 3, width = self.windowWidth/100*99.5 ):
  2638.                         py.text( label = "", width = self.windowWidth/100*1 )
  2639.                         self.checkBoxList["UseCustomURL"] = py.checkBox( label = "Use custom image path instead of stored URL (enable if custom image URL was not saved to the image)", annotation = "Override stored URL and use the image chosen in the custom image path" )
  2640.                         py.text( label = "", width = self.windowWidth/100*1 )
  2641.  
  2642.            
  2643.             with py.columnLayout( "Advanced" ):
  2644.                
  2645.                 with py.frameLayout( label = "Write", collapsable = True, collapse = False, width = self.windowWidth/100*101 ):
  2646.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2647.                         py.text( label = "", width = self.windowWidth/100*1 )
  2648.                        
  2649.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*99.5 ):
  2650.                             self.checkBoxList["Validate"] = py.checkBox( label = "Validate output image", value = True, annotation = "Check image can be read after creation" )
  2651.                             self.checkBoxList["Revert"] = py.checkBox( label = "Cancel if custom image is too small (otherwise the custom image will just be disabled)", annotation = "Disable reverting back to the default method if the custom image is too small" )
  2652.                             self.checkBoxList["SaveInformation"] = py.checkBox( label = "Save extra information into file (recommended)", value = True, annotation = "Save a few small files into the image to do with how the image was created" )
  2653.                        
  2654.                         py.text( label = "", width = self.windowWidth/100*1 )
  2655.                        
  2656.                 with py.frameLayout( label = "Cutoff Modes", collapsable = True, collapse = True, width = self.windowWidth/100*101 ):
  2657.                    
  2658.                     with py.rowColumnLayout( numberOfColumns = 1 ):
  2659.                         py.text( label = "   Cutoff modes define if the values should be added or subtracted based on the brightness of the pixel.", align = "left" )
  2660.                        
  2661.                     with py.rowColumnLayout( numberOfColumns = 5 ):
  2662.                         py.text( label="", width = self.windowWidth/100*1 )
  2663.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25 ):
  2664.                             self.checkBoxList["AllCutoffModes"] = py.checkBox( label = "Use all cutoff modes", changeCommand = py.Callback( self.addNewCutoffMode, *range( 8 ) ), annotation = "Save an image with every one of the cutoff modes" )
  2665.                            
  2666.                             with py.rowColumnLayout( numberOfColumns = 2 ):
  2667.                                 self.textList["CutoffModesTemporary"] = py.text( label = "", visible = False )
  2668.                                 self.checkBoxList["RevertTemporary"] = py.checkBox( label = "", visible = False )
  2669.                            
  2670.                             py.text( label="   Select cutoff mode(s):", align="left", width = self.windowWidth/100*45.2 )
  2671.                             self.textFieldList["CutoffModes"] = py.textField( enterCommand = py.Callback( self.addNewCutoffMode ), changeCommand = py.Callback( self.addNewCutoffMode ), annotation = "Enter multiple numbers separated by a comma or space" )
  2672.                            
  2673.                             with py.rowColumnLayout( numberOfColumns = 16, annotation = "Select cutoff modes to use" ):
  2674.                                 self.checkBoxList["CutoffMode"] = {}
  2675.                                 self.textList["CutoffMode"] = {}
  2676.                                 for i in xrange( 8 ):
  2677.                                     textLabel = "  {0} ".format( i )
  2678.                                     if i == 0:
  2679.                                         textLabel = textLabel[1:]
  2680.                                     self.textList["CutoffMode"][i] = py.text( label = textLabel )
  2681.                                     self.checkBoxList["CutoffMode"][i] = py.checkBox( label = "", changeCommand = py.Callback( self.addNewCutoffMode, i ) )
  2682.                                    
  2683.                             py.text( label = "" )
  2684.                             py.text( label="   File suffix used for saving multiple images:", align="left" )
  2685.                            
  2686.                             with py.rowColumnLayout( numberOfColumns = 3, width = self.windowWidth/100*45.2, annotation = "How to name multiple images" ):
  2687.                                 self.textFieldList["MultipleImagesName"] = py.textField( text = "{0}/{1}.".format( ImageStore().defaultImageDirectory, ".".join( ImageStore().defaultImageName.split( "." )[:-1] ) ), editable=False, width = self.windowWidth/100*31 )
  2688.                                 self.textFieldList["MultipleImagesPrefix"] = py.textField( text = "m", width = self.windowWidth/100*8.7 )
  2689.                                 self.textFieldList["MultipleImagesSuffix"] = py.textField( text = ".png", editable=False, width = self.windowWidth/100*5.5 )                
  2690.                            
  2691.                         py.text( label="", width = self.windowWidth/100*1 )
  2692.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25 ):
  2693.                            
  2694.                             py.scrollField( wordWrap = True, height = 135, width = self.windowWidth/100*48, enable = False, text = "<br>".join( ImageStore().write( cutoffModeHelp = True )[2:] ), annotation = "How each cutoff mode works" )
  2695.        
  2696.                 with py.frameLayout( label = "Cache", collapsable = True, collapse = True, width = self.windowWidth/100*101 ):
  2697.                    
  2698.                     with py.rowColumnLayout( numberOfColumns = 5 ):
  2699.                         py.text( label="", width = self.windowWidth/100*1 )
  2700.                        
  2701.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25):
  2702.                            
  2703.                             self.checkBoxList["WriteCache"] = py.checkBox( label="Use cache file (recommended)", value = True, annotation = "Write image data to a cache for faster subsequent runs" )
  2704.                             py.text( label = "   Custom Image:", align = "left" )
  2705.                            
  2706.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2707.                                 py.button( label = "Get MD5 hash", width = self.windowWidth/100*23, command = py.Callback( self.getImageMD5 ) )
  2708.                                 py.text( label = "" )
  2709.                                 py.button( label = "Return Cache Contents", width = self.windowWidth/100*23, command = py.Callback( self.getImageMD5, True ) )
  2710.                            
  2711.                             self.textFieldList["CustomImageHash"] = py.textField( editable = False )
  2712.                             py.text( label = "", height = 10 )
  2713.                             py.button( label = "Return Entire Cache Contents", width = self.windowWidth/100*47, command = py.Callback( self.getAllCacheInfo ) )
  2714.                            
  2715.                         py.text( label="", width = self.windowWidth/100*1 )
  2716.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25):
  2717.                            
  2718.                             py.text( label = "", height = 8 )
  2719.                            
  2720.                             py.text( label = "   Delete MD5 hash from cache:", align = "left" )
  2721.                             py.text( label = "      Type 'all' to delete everything", align = "left", enable = False )
  2722.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2723.                                 self.textFieldList["ImageMD5Delete"] = py.textField( width = self.windowWidth/100*38, annotation = "Enter value to remove from cache" )
  2724.                                 py.text( label = "" )
  2725.                                 py.button( label = "Delete", width = self.windowWidth/100*8, command = py.Callback( self.deleteCacheKey ), annotation = "Delete value" )
  2726.                             py.text( label = "" )
  2727.                            
  2728.                             py.text( label = "   Return information for MD5 hash:", align = "left" )
  2729.                             with py.rowColumnLayout( numberOfColumns = 3 ):
  2730.                                 self.textFieldList["ImageMD5Return"] = py.textField( width = self.windowWidth/100*38, annotation = "Enter value to search for" )
  2731.                                 py.text( label = "" )
  2732.                                 py.button( label = "Return", width = self.windowWidth/100*8, command = py.Callback( self.getImageMD5Info ), annotation = "Search cache" )
  2733.                                
  2734.                                
  2735.                         py.text( label="", width = self.windowWidth/100*1 )
  2736.                                            
  2737.                     with py.frameLayout( label = "Cache Output", collapsable = True, collapse = True, width = self.windowWidth/100*99 ) as self.frameLayoutList["CacheOutput"]:
  2738.                         self.scrollFieldList["CacheOutput"] = py.scrollField( height = 200 )
  2739.            
  2740.                 with py.frameLayout( label = "Other", collapsable = True, collapse = True, width = self.windowWidth/100*101 ):
  2741.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2742.                        
  2743.                         py.text( label = "", width = self.windowWidth/100*1 )
  2744.                        
  2745.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*99.5 ):
  2746.                             py.checkBox( label = "Upload non Imgur URLs to Imgur", value = True )
  2747.                        
  2748.                         py.text( label = "", width = self.windowWidth/100*1 )
  2749.            
  2750.             with py.columnLayout( "Debug" ):
  2751.                
  2752.                 with py.frameLayout( label = "Write", collapsable = True, collapse = True, width = self.windowWidth/100*101 ):
  2753.                     with py.rowColumnLayout( numberOfColumns = 5 ):
  2754.                        
  2755.                         py.text( label="", width = self.windowWidth/100*1 )
  2756.                        
  2757.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25):
  2758.                             self.checkBoxList["ReturnCustomURL"] = py.checkBox( label="Return URL to custom image after uploading", value = True )
  2759.                        
  2760.                         py.text( label="", width = self.windowWidth/100*1 )
  2761.                        
  2762.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*49.25):
  2763.                             self.checkBoxList["DebugData"] = py.checkBox( label="Enable debug write mode" )
  2764.                        
  2765.                         py.text( label="", width = self.windowWidth/100*1 )
  2766.                
  2767.                 with py.frameLayout( label = "Size", collapsable = True, collapse = False, width = self.windowWidth/100*101 ):
  2768.                     with py.rowColumnLayout( numberOfColumns = 5 ):
  2769.                        
  2770.                         py.text( label="", width = self.windowWidth/100*1 )
  2771.                        
  2772.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*30):
  2773.                             py.text( label = "" )
  2774.                             py.button( label = "Calculate size of input value", width = self.windowWidth/100*30, command = py.Callback( self.calculateSizeOfInput ) )
  2775.                        
  2776.                         py.text( label="", width = self.windowWidth/100*1 )
  2777.                        
  2778.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*68):
  2779.                            
  2780.                             py.text( label = "   Calculate how much data an image can hold:", align = "left" )
  2781.                             with py.rowColumnLayout( numberOfColumns = 5 ):
  2782.                                
  2783.                                 self.textFieldList["CalculateImageSize"] = py.textField( width = self.windowWidth/100*49.25 )
  2784.                                 py.text( label = "" )
  2785.                                 py.button( label = "Browse", width = self.windowWidth/100*8, command = py.Callback( self.fileReading, False, True, "textField", "CalculateImageSize" ), annotation = "Open an image" )
  2786.                                 py.text( label = "" )
  2787.                                 py.button( label = "Read", width = self.windowWidth/100*8, command = py.Callback( self.calculateSizeOfImage ) )
  2788.                        
  2789.                         py.text( label="", width = self.windowWidth/100*1 )
  2790.                    
  2791.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2792.                        
  2793.                         py.text( label = "", width = self.windowWidth/100*1 )
  2794.                         self.textFieldList["DebugSizeInput"] = py.textField( width = self.windowWidth/100*98.5, editable = False )
  2795.                         py.text( label = "", width = self.windowWidth/100*1 )
  2796.                         py.text( label = "", width = self.windowWidth/100*1 )
  2797.                         self.textFieldList["DebugSizeImage"] = py.textField( width = self.windowWidth/100*98.5, editable = False )
  2798.                         py.text( label = "", width = self.windowWidth/100*1 )
  2799.                        
  2800.                 with py.frameLayout( label = "Other", collapsable = True, collapse = True, width = self.windowWidth/100*101 ):
  2801.                     py.button( label = "Reload User Interface", command = py.Callback( self.display ) )
  2802.        
  2803.         with py.rowColumnLayout( numberOfColumns = 5 ):
  2804.            
  2805.             py.text( label="", width = self.windowWidth/100*1 )
  2806.             self.buttonList["MainWriteImage"] = py.button( label = "Write Image", width = self.windowWidth/100*49.5, command = py.Callback( self.writeImage ), annotation = "Write a new image using the current settings" )
  2807.             py.text( label = "", width = self.windowWidth/100*1 )
  2808.             self.buttonList["MainReadImage"] = py.button( label = "Read Image", width = self.windowWidth/100*49.5, command = py.Callback( self.readImage ), annotation = "Read an existing image using the current settings" )
  2809.             py.text( label = "", width = self.windowWidth/100*1 )
  2810.                
  2811.         with py.rowColumnLayout( numberOfColumns = 3 ):
  2812.            
  2813.             py.text( label="", width = self.windowWidth/100*1 )
  2814.             self.textList["ProgressBar"] = py.text( label = "Waiting for input...", width = self.windowWidth/100*99.5, annotation = "Current progress" )
  2815.             py.text( label="", width = self.windowWidth/100*1 )
  2816.             py.text( label = "" )
  2817.             self.progressBarList["ProgressBar"] = py.progressBar( progress = 0, annotation = "Overall progress" )
  2818.             py.text( label = "" )
  2819.            
  2820.         with py.rowColumnLayout( numberOfColumns = 1 ):
  2821.             with py.rowColumnLayout( numberOfColumns = 1 ):
  2822.                 with py.frameLayout( label = "Progress", collapsable = True, collapse = True, visible = True, width = self.windowWidth/100*101.5 ) as self.frameLayoutList["OutputProgress"]:
  2823.                     self.scrollFieldList["OutputProgress"] = py.scrollField( height = 160, editable = False, annotation = "Progress history" )
  2824.                    
  2825.                 with py.frameLayout( label = "Write Output", collapsable = True, collapse = True, visible = True, width = self.windowWidth/100*101 ) as self.frameLayoutList["OutputWrite"]:
  2826.                    
  2827.                     with py.rowColumnLayout( numberOfColumns = 3 ):
  2828.                        
  2829.                         py.text( label="", width = self.windowWidth/100*1 )
  2830.                        
  2831.                         with py.rowColumnLayout( numberOfColumns = 1, width = self.windowWidth/100*99 ):
  2832.                            
  2833.                             py.text( label="   Path(s):", align = "left", width = self.windowWidth/100*45.2 )
  2834.                             self.scrollFieldList["OutputPath"] = py.scrollField( height = 60, width = self.windowWidth/100*99, editable = False, annotation = "Path to saved image" )
  2835.                            
  2836.                             py.text( label="   URL(s):", align = "left", width = self.windowWidth/100*45.2 )
  2837.                             self.scrollFieldList["OutputURL"] = py.scrollField( height = 60, width = self.windowWidth/100*99, editable = False, annotation = "URL to uploaded image" )
  2838.                            
  2839.                             py.text( label="   Custom Image URL:", align = "left", width = self.windowWidth/100*45.2 )
  2840.                             self.scrollFieldList["OutputCustomURL"] = py.scrollField( height = 27, width = self.windowWidth/100*99, editable = False, annotation = "URL to original custom image" )
  2841.                        
  2842.                         py.text( label="", width = self.windowWidth/100*1 )
  2843.                        
  2844.                 with py.frameLayout( label = "Read Output", collapsable = True, collapse = True, visible = True, width = self.windowWidth/100*101 ) as self.frameLayoutList["OutputRead"]:
  2845.                     self.scrollFieldList["OutputRead"] = py.scrollField( height = 260, editable = False, wordWrap = True, annotation = "Data read from image" )
  2846.          
  2847.         self.setFinalValues()
  2848.         py.showWindow()
  2849.    
  2850.     @classmethod
  2851.     def readImage( self ):
  2852.        
  2853.         kwargs = {}
  2854.         imagePath = py.textField( self.textFieldList["MainImagePath"], query = True, text = True )
  2855.         customImagePath = py.textField( self.textFieldList["CustomImagePath"], query = True, text = True )
  2856.         disableCustomImage = not py.checkBox( self.checkBoxList["UseCustomURL"], query = True, value = True )
  2857.        
  2858.         if customImagePath and not disableCustomImage:
  2859.             #Make sure custom image is valid
  2860.             if py.text( self.textList["ValidateCustomImage"], query = True, label = True ) != "1":
  2861.                 py.button( self.buttonList["ValidateCustomImage"], query = True, command = True )()
  2862.             if py.text( self.textList["ValidateCustomImage"], query = True, label = True ) == "1":
  2863.                 kwargs["CustomImagePath"] = customImagePath
  2864.        
  2865.         self.returnSomeData = None
  2866.         returnAllData = py.radioButton( self.radioButtonList["ReturnAll"], query = True, select = True )
  2867.         if not returnAllData:
  2868.             self.returnSomeData = py.textField( self.textFieldList["ReturnSome"], query = True, text = True ).replace( ",", "" ).replace( " ", "" )
  2869.             if not self.returnSomeData.isdigit():
  2870.                 self.returnSomeData = 100000
  2871.             else:
  2872.                 self.returnSomeData = int( self.returnSomeData )
  2873.         kwargs["OutputInformation"] = True
  2874.        
  2875.         mainKwargs = {}
  2876.         mainKwargs["ScrollField"] = self.scrollFieldList["OutputProgress"]
  2877.         mainKwargs["ProgressBarName"] = self.progressBarList["ProgressBar"]
  2878.         mainKwargs["progressBarText"] = self.textList["ProgressBar"]
  2879.         mainKwargs["DeferredReadCommand"] = self.deferredRead
  2880.         mainKwargs["WriteToCache"] = py.checkBox( self.checkBoxList["WriteCache"], query = True, value = True )
  2881.        
  2882.         outputData = None
  2883.         if py.text( self.textList["ValidateMainImage"], query = True, label = True ) != "1":
  2884.             py.button( self.buttonList["ValidateMainImage"], query = True, command = True )()
  2885.         if py.checkBox( self.checkBoxList["ImagePathExists"], query = True, value = True ):
  2886.             utils.executeDeferred( ImageStore( imagePath, **mainKwargs ).read, **kwargs )
  2887.        
  2888.    
  2889.     @classmethod
  2890.     def deferredRead( self, outputData=None ):
  2891.        
  2892.         if not outputData:
  2893.             outputData = "Unable to read image"
  2894.             self.returnSomeData = len( outputData )
  2895.        
  2896.         truncatedData = str( outputData )[0:self.returnSomeData]
  2897.         if len( outputData ) > self.returnSomeData and self.returnSomeData:
  2898.             lineBreaks = 0
  2899.             truncatedData += "... " + "".join( [GlobalValues.newLine for i in xrange( lineBreaks )] ) + "[{0} characters truncated]".format( len( outputData )-self.returnSomeData )
  2900.        
  2901.         py.scrollField( self.scrollFieldList["OutputRead"], edit = True, text = truncatedData )
  2902.         py.frameLayout( self.frameLayoutList["OutputRead"], edit = True, collapse = False )
  2903.         self.setFinalValues()
  2904.        
  2905.         saveAsFile = py.checkBox( self.checkBoxList["SaveAsFile"], query = True, value = True )
  2906.         if saveAsFile and outputData:
  2907.             saveToLocation = py.textField( self.textFieldList["SaveAsFile"], query = True, text = True )
  2908.             try:
  2909.                 with open( saveToLocation, "w" ) as fileName:
  2910.                     fileName.write( outputData )
  2911.             except:
  2912.                 print "Error: Unable to save file."
  2913.    
  2914.     @classmethod
  2915.     def writeImage( self ):
  2916.        
  2917.         kwargs = {}
  2918.         imagePath = py.textField( self.textFieldList["MainImagePath"], query = True, text = True )
  2919.         customImagePath = py.textField( self.textFieldList["CustomImagePath"], query = True, text = True )
  2920.         disableCustomImage = py.checkBox( self.checkBoxList["DisableCustomImage"], query = True, value = True )
  2921.         if disableCustomImage:
  2922.             customImagePath = None
  2923.        
  2924.         #Make sure custom image is valid
  2925.         if customImagePath:
  2926.             if py.text( self.textList["ValidateCustomImage"], query = True, label = True ) != "1":
  2927.                 py.button( self.buttonList["ValidateCustomImage"], query = True, command = True )()
  2928.         if py.text( self.textList["ValidateCustomImage"], query = True, label = True ) == "1" or not customImagePath:
  2929.             kwargs["CustomImagePath"] = customImagePath
  2930.        
  2931.         kwargs["Input"] = self.validateInput( None, True )
  2932.        
  2933.         kwargs["Upload"] = py.checkBox( self.checkBoxList["UploadMainImage"], query = True, value = True )
  2934.         kwargs["OpenUploadedImage"] = py.checkBox( self.checkBoxList["OpenMainImage"], query = True, value = True )
  2935.         kwargs["UploadCustomImage"] = py.checkBox( self.checkBoxList["UploadCustomImage"], query = True, value = True )
  2936.        
  2937.         kwargs["SizeRatio"] = py.floatSliderGrp( self.floatSliderGrpList["Ratio"], query = True, value = True )
  2938.        
  2939.         kwargs["ValidateOutput"] = py.checkBox( self.checkBoxList["Validate"], query = True, value = True )
  2940.         kwargs["Revert"] = not py.checkBox( self.checkBoxList["Revert"], query = True, value = True )
  2941.         kwargs["DisableInformation"] = not py.checkBox( self.checkBoxList["SaveInformation"], query = True, value = True )
  2942.        
  2943.         cutoffModes = py.textField( self.textFieldList["CutoffModes"], query = True, text = True )
  2944.         if cutoffModes:
  2945.             kwargs["CutoffModes"] = tuple( cutoffModes )
  2946.        
  2947.         cutoffPrefix = py.textField( self.textFieldList["MultipleImagesPrefix"], query = True, text = True )
  2948.         if cutoffPrefix:
  2949.             kwargs["CutoffModePrefix"] = cutoffPrefix
  2950.            
  2951.        
  2952.         kwargs["returnCustomImageURL"] = py.checkBox( self.checkBoxList["ReturnCustomURL"], query = True, value = True )
  2953.         kwargs["debugOutput"] = py.checkBox( self.checkBoxList["DebugData"], query = True, value = True )
  2954.        
  2955.         mainKwargs = {}
  2956.         mainKwargs["ScrollField"] = self.scrollFieldList["OutputProgress"]
  2957.         mainKwargs["ProgressBarName"] = self.progressBarList["ProgressBar"]
  2958.         mainKwargs["progressBarText"] = self.textList["ProgressBar"]
  2959.         mainKwargs["DeferredWriteCommand"] = self.deferredWrite
  2960.         mainKwargs["WriteToCache"] = py.checkBox( self.checkBoxList["WriteCache"], query = True, value = True )
  2961.        
  2962.         utils.executeDeferred( ImageStore( imagePath, **mainKwargs ).write, **kwargs )
  2963.        
  2964.     @classmethod
  2965.     def deferredWrite( self, outputLocations, returningCustomURL=False ):
  2966.        
  2967.         imagePaths = []
  2968.         imageURLs = []
  2969.         customURL = []
  2970.         if outputLocations:
  2971.             for i in xrange( len( outputLocations ) ):
  2972.                 currentImagePath = outputLocations[i]
  2973.                 imagePaths.append( currentImagePath[0] )
  2974.                 if len( currentImagePath ) > 1:
  2975.                     if returningCustomURL:
  2976.                         customURL.append( currentImagePath[-1] )
  2977.                     if len( currentImagePath ) - int( returningCustomURL ) == 2:
  2978.                         imageURLs.append( currentImagePath[1] )
  2979.                        
  2980.         if not imagePaths:
  2981.             imagePaths.append( "Image wasn't saved" )
  2982.        
  2983.         py.scrollField( self.scrollFieldList["OutputPath"], edit = True, text = "<br>".join( imagePaths ) )
  2984.         py.scrollField( self.scrollFieldList["OutputURL"], edit = True, text = "<br>".join( imageURLs ) )
  2985.         py.scrollField( self.scrollFieldList["OutputCustomURL"], edit = True, text = "<br>".join( list( set( customURL ) ) ) )
  2986.         py.frameLayout( self.frameLayoutList["OutputWrite"], edit = True, collapse = False )
  2987.         self.setFinalValues()
  2988.    
  2989.     @classmethod
  2990.     def calculateSizeOfInput( self ):
  2991.        
  2992.         input = self.validateInput( None, True )
  2993.        
  2994.         if input:
  2995.             inputSize = ImageStore().write( input, inputSize = True )
  2996.         else:
  2997.             inputSize = 0
  2998.        
  2999.         if inputSize:
  3000.             content = "Input data is {0} bytes ({1}kb), going up to {2} bytes ({3}kb) when using 1 bit per colour".format( inputSize, int( inputSize )/1024, inputSize*8, int( inputSize*8 )/1024 )
  3001.         else:
  3002.             content = "Input data is invalid"
  3003.        
  3004.         py.textField( self.textFieldList["DebugSizeInput"], edit = True, text = content )
  3005.        
  3006.        
  3007.     @classmethod
  3008.     def calculateSizeOfImage( self ):
  3009.        
  3010.         imageLocation = ImageStore().getImageLocation( py.textField( self.textFieldList["CalculateImageSize"], query = True, text = True ) )
  3011.         content = None
  3012.         if imageLocation:
  3013.            
  3014.             imageSize = ImageStore( imageLocation, scrollField = self.scrollFieldList["OutputProgress"], progressBarName = self.progressBarList["ProgressBar"], progressBarText = self.textList["ProgressBar"] ).write( customImage = imageLocation, getImageSize = True )
  3015.            
  3016.             if imageSize:
  3017.                 content = "Image can store up to around {0} bytes ({1}kb)".format( imageSize, int( imageSize )/1024 )
  3018.                
  3019.         if not content:
  3020.             content = "Unable to read image"
  3021.         py.textField( self.textFieldList["DebugSizeImage"], edit = True, text = content )
  3022.         ImageStore().renderView( False )
  3023.        
  3024.     @classmethod
  3025.     def deleteCacheKey( self ):
  3026.        
  3027.         imageHash = py.textField( self.textFieldList["ImageMD5Delete"], query = True, text = True )
  3028.         if imageHash:
  3029.             if imageHash.lower().replace( " ", "" ) == "all":
  3030.                 ImageStore().cache( cleanCache = True )
  3031.             else:
  3032.                 ImageStore().cache( deleteKey = imageHash )
  3033.        
  3034.     @classmethod
  3035.     def updateCacheOutput( self, cacheContents, individualValue=False ):
  3036.        
  3037.         #Format text for html
  3038.         if cacheContents:
  3039.             newReplace = cacheContents.replace( "\r\n", "<br>" ).replace( "<br> ", "<br>&nbsp;" )
  3040.             while cacheContents != newReplace:
  3041.                 cacheContents = newReplace
  3042.                 newReplace = cacheContents.replace( "&nbsp; ", "&nbsp;&nbsp;" )
  3043.         else:
  3044.             newReplace = "No cache data found"
  3045.        
  3046.         #Write to the scroll field
  3047.         py.frameLayout( self.frameLayoutList["CacheOutput"], edit = True, collapse = False )
  3048.         py.scrollField( self.scrollFieldList["CacheOutput"], edit = True, text = newReplace )
  3049.    
  3050.     @classmethod
  3051.     def getAllCacheInfo( self ):
  3052.        
  3053.         #Return all values to cache output
  3054.         self.updateCacheOutput( ImageStore().cache() )
  3055.    
  3056.     @classmethod
  3057.     def getImageMD5Info( self ):
  3058.        
  3059.         #Return a single image to the cache output
  3060.         imageHash = py.textField( self.textFieldList["ImageMD5Return"], query = True, text = True )
  3061.         self.updateCacheOutput( ImageStore().cache( key = imageHash ), True )
  3062.    
  3063.    
  3064.     @classmethod
  3065.     def getImageMD5( self, getContents=False ):
  3066.        
  3067.         #Get hash of currently selected image
  3068.         imageLocation = ImageStore().getImageLocation( py.textField( self.textFieldList["CustomImagePath"], query = True, text = True ) )
  3069.         imageHash = ImageStore().cache( MD5 = imageLocation )
  3070.        
  3071.         if not imageHash:
  3072.             imageHash = "Unable to read image"
  3073.         else:
  3074.            
  3075.             if getContents:
  3076.                 self.updateCacheOutput( ImageStore().cache( key = imageHash ), True )
  3077.                 return
  3078.            
  3079.             deleteHash = py.textField( self.textFieldList["ImageMD5Delete"], query = True, text = True )
  3080.             returnHash = py.textField( self.textFieldList["ImageMD5Return"], query = True, text = True )
  3081.             if not deleteHash:
  3082.                 py.textField( self.textFieldList["ImageMD5Delete"], edit = True, text = imageHash )
  3083.             if not returnHash:
  3084.                 py.textField( self.textFieldList["ImageMD5Return"], edit = True, text = imageHash )
  3085.         py.textField( self.textFieldList["CustomImageHash"], edit = True, text = imageHash )
  3086.         ImageStore().renderView( False )
  3087.    
  3088.     @classmethod
  3089.     def addNewCutoffMode( self, *args ):
  3090.        
  3091.         #Sort out text
  3092.         newArgs = []
  3093.         currentText = py.textField( self.textFieldList["CutoffModes"], query = True, text = True )
  3094.         splitText = currentText.replace( " ", ";" ).replace( ",", ";" ).replace( ".", ";" ).replace( ":", ";" ).split( ";" )
  3095.         allNumbers = [int( num ) for num in splitText if num.isdigit()]
  3096.        
  3097.         #If returning from deselecting the cutoff modes
  3098.         if args:
  3099.             if args[0] == "return":
  3100.                 args = tuple( list( args )[1:] )
  3101.                
  3102.                 for i in xrange( 8 ):
  3103.                     if i in args:
  3104.                         enabled = True
  3105.                     else:
  3106.                         enabled = False
  3107.                        
  3108.                     py.checkBox( self.checkBoxList["CutoffMode"][i], edit = True, enable = True, value = enabled )
  3109.                
  3110.         #If checkbox is ticked
  3111.         enableValue = True
  3112.         if len( args ) == 1:
  3113.             enableValue = py.checkBox( self.checkBoxList["CutoffMode"][args[0]], query = True, value = True )
  3114.             allNumbers = [num for num in allNumbers if num != args[0]]
  3115.        
  3116.         #If all cutoff modes is ticked
  3117.         if len( args ) == 8:
  3118.             enableValue = py.checkBox( self.checkBoxList["AllCutoffModes"], query = True, value = True )
  3119.            
  3120.             py.checkBox( self.checkBoxList["Revert"], edit = True, enable = not enableValue )
  3121.            
  3122.             #Store values in hidden text field
  3123.             if enableValue:
  3124.                 py.text( self.textList["CutoffModesTemporary"], edit = True, label = ",".join( [str( num ) for num in allNumbers] ) )
  3125.                 py.checkBox( self.checkBoxList["RevertTemporary"], edit = True, value = py.checkBox( self.checkBoxList["Revert"], query = True, value = True ) )
  3126.                 py.checkBox( self.checkBoxList["Revert"], edit = True, value = True )
  3127.             else:
  3128.                 newArgs = ["return"] + [int( num ) for num in py.text( self.textList["CutoffModesTemporary"], query = True, label = True ).split( "," ) if num.isdigit()]
  3129.                 py.checkBox( self.checkBoxList["Revert"], edit = True, value = py.checkBox( self.checkBoxList["RevertTemporary"], query = True, value = True ) )
  3130.                
  3131.             py.textField( self.textFieldList["CutoffModes"], edit = True, enable = not enableValue )
  3132.            
  3133.             for i in xrange( 8 ):
  3134.                 py.checkBox( self.checkBoxList["CutoffMode"][i], edit = True, editable = not enableValue )
  3135.                 py.text( self.textList["CutoffMode"][i], edit = True, enable = not enableValue )
  3136.                
  3137.             allNumbers = []
  3138.        
  3139.         #Add number to list
  3140.         for i in xrange( len( args ) ):
  3141.             py.checkBox( self.checkBoxList["CutoffMode"][args[i]], edit = True, value = enableValue )
  3142.             if int( args[i] ) not in allNumbers and enableValue:
  3143.                 allNumbers.append( args[i] )
  3144.        
  3145.         allNumbers = list( set( allNumbers ) )
  3146.         allNumbers.sort()
  3147.        
  3148.         py.textField( self.textFieldList["CutoffModes"], edit = True, text = ", ".join( [str( num ) for num in allNumbers if num in xrange( 8 )] ) )
  3149.        
  3150.         for number in allNumbers:
  3151.             if str( number ).isdigit():
  3152.                 if number in xrange( 8 ):
  3153.                     py.checkBox( self.checkBoxList["CutoffMode"][number], edit = True, value = True )
  3154.        
  3155.         if newArgs:
  3156.             try:
  3157.                 self.addNewCutoffMode( *newArgs )
  3158.             except:
  3159.                 pass
  3160.            
  3161.    
  3162.     @classmethod
  3163.     def saveOutputAsFile( self ):
  3164.        
  3165.         #Enable controls if checkbox is ticked
  3166.         enableSaveFile = py.checkBox( self.checkBoxList["SaveAsFile"], query = True, value = True )
  3167.         py.textField( self.textFieldList["SaveAsFile"], edit = True, editable = enableSaveFile )
  3168.         py.button( self.buttonList["SaveAsFile"], edit = True, enable = enableSaveFile )
  3169.    
  3170.     @classmethod
  3171.     def returnSomeData( self ):
  3172.        
  3173.         #Select radio button if text or textField is clicked on
  3174.         py.radioButton( self.radioButtonList["ReturnSome"], edit = True, select = True )
  3175.    
  3176.     @classmethod
  3177.     def uploadCheckBox( self ):
  3178.        
  3179.         #Disable open image in browser checkbox if upload is not selected
  3180.         uploadImage = py.checkBox( self.checkBoxList["UploadMainImage"], query = True, value = True )
  3181.         py.checkBox( self.checkBoxList["OpenMainImage"], edit = True, editable = uploadImage )
  3182.  
  3183.     @classmethod
  3184.     def validButton( self, buttonName, valid ):
  3185.        
  3186.         try:
  3187.             if valid:
  3188.                 py.button( self.buttonList[buttonName], edit = True, backgroundColor = ( 0, 1, 0 ), label = "Valid" )
  3189.                 try:
  3190.                     py.text( self.textList[buttonName], edit = True, label = "1" )
  3191.                 except:
  3192.                     pass
  3193.             else:
  3194.                 py.button( self.buttonList[buttonName], edit = True, backgroundColor = ( 1, 0, 0 ), label = "Invalid" )
  3195.                 try:
  3196.                     py.text( self.textList[buttonName], edit = True, label = "0" )
  3197.                 except:
  3198.                     pass
  3199.        
  3200.         except:
  3201.             pass
  3202.  
  3203.     @classmethod
  3204.     def validateInput( self, inputType=None, returnOnly=False ):
  3205.        
  3206.         input = py.textField( self.textFieldList["InputData"], query = True, text = True )
  3207.        
  3208.         #If the string is changed, validate based on current radio button selection
  3209.         if not inputType:
  3210.             radioButtonList = {}
  3211.             radioButtonList[None] = py.radioButton( self.radioButtonList["InputIsText"], query = True, select = True )
  3212.             radioButtonList["code"] = py.radioButton( self.radioButtonList["InputIsCode"], query = True, select = True )
  3213.             radioButtonList["file"] = py.radioButton( self.radioButtonList["InputIsFile"], query = True, select = True )
  3214.             inputType = [key for key, value in radioButtonList.iteritems() if value][0]
  3215.        
  3216.         if not inputType:
  3217.             input = str( input )
  3218.        
  3219.         #Check if it can be executed as code
  3220.         if inputType == "code":
  3221.        
  3222.             if not returnOnly:
  3223.                 py.radioButton( self.radioButtonList["InputIsCode"], edit = True, select = True )
  3224.             try:
  3225.                 input = eval( input )
  3226.                 self.validButton( "ValidateInputCode", True )
  3227.             except:
  3228.                 self.validButton( "ValidateInputCode", False )
  3229.                 input = None
  3230.        
  3231.         #Check if it can be read
  3232.         if inputType in ["browse", "file"]:
  3233.        
  3234.             if inputType == "browse":
  3235.                 inputType = self.fileReading( False, False, "textField", "InputData", "ValidateInputFile" )
  3236.                
  3237.             if inputType == "file":
  3238.                 try:
  3239.                     with open( input ) as fileName:
  3240.                         content = fileName.read()
  3241.                     self.validButton( "ValidateInputFile", True )
  3242.                     input = content
  3243.                 except:
  3244.                     self.validButton( "ValidateInputFile", False )
  3245.                     input = None
  3246.            
  3247.             if inputType and not returnOnly:
  3248.                 py.radioButton( self.radioButtonList["InputIsFile"], edit = True, select = True )
  3249.        
  3250.         return input
  3251.            
  3252.    
  3253.     @classmethod
  3254.     def disableCustomImage( self ):
  3255.        
  3256.         #Fix due to an error happening on the first run of the code when the checkbox doesn't exist
  3257.         try:
  3258.             disabled = py.checkBox( self.checkBoxList["DisableCustomImage"], query = True, value = True )
  3259.         except:
  3260.             disabled = False
  3261.            
  3262.         py.textField( self.textFieldList["CustomImagePath"], edit = True, enable = not disabled )
  3263.         py.button( self.buttonList["BrowseCustomImage"], edit = True, enable = not disabled )
  3264.         py.button( self.buttonList["UseRenderView"], edit = True, enable = not disabled )
  3265.         py.button( self.buttonList["ValidateCustomImage"], edit = True, enable = not disabled )
  3266.         py.text( self.textList["CustomImagePath"], edit = True, enable = not disabled )
  3267.         validateBackgroundColour = py.button( self.buttonList["ValidateCustomImage"], query = True, backgroundColor = True )
  3268.         newBackgroundColour = []
  3269.        
  3270.         for i in xrange( 3 ):
  3271.        
  3272.             #Calculate new background color
  3273.             if sum( validateBackgroundColour ):
  3274.                 if disabled:
  3275.                     newBackgroundColour.append( validateBackgroundColour[i]/2 )
  3276.                 else:
  3277.                     newBackgroundColour.append( validateBackgroundColour[i]*2 )
  3278.                    
  3279.             py.button( self.buttonList["RenderView"][self.renderViewFormats[i]], edit = True, enable = not disabled )  
  3280.        
  3281.         if sum( validateBackgroundColour ):
  3282.             py.button( self.buttonList["ValidateCustomImage"], edit = True, backgroundColor = newBackgroundColour )
  3283.  
  3284.  
  3285.     @classmethod
  3286.     def checkPathToCustomImage( self ):
  3287.        
  3288.         #Get image information
  3289.         rawImageLocation = py.textField( self.textFieldList["CustomImagePath"], query = True, text = True )
  3290.         imageLocation = ImageStore().getImageLocation( rawImageLocation )
  3291.         imageHash = ImageStore( imageLocation ).cache( MD5 = True )
  3292.         disableCustomImage = py.checkBox( self.checkBoxList["DisableCustomImage"], query = True, value = True )
  3293.         if disableCustomImage:
  3294.             imageLocation = None
  3295.        
  3296.         #Test custom image
  3297.         valid = ImageStore( cleanTemporaryFiles = False ).write( testCustomImage = True, customImageLocation = imageLocation )
  3298.        
  3299.         #Don't automatically say valid if nothing is there and image is written to
  3300.         if rawImageLocation or py.button( self.buttonList["ValidateCustomImage"], query = True, label = True ) == "Invalid":
  3301.             if valid or py.textField( self.textFieldList["CustomImagePath"], query = True, text = True ) == "":
  3302.                 self.validButton( "ValidateCustomImage", True )
  3303.             else:
  3304.                 self.validButton( "ValidateCustomImage", False )
  3305.        
  3306.         #Read image
  3307.         if ImageStore().readImage( imageLocation ):
  3308.             py.checkBox( self.checkBoxList["CustomImageIsImage"], edit = True, value = True )
  3309.         else:
  3310.             py.checkBox( self.checkBoxList["CustomImageIsCached"], edit = True, value = False )
  3311.        
  3312.         #Read cache
  3313.         if ImageStore().cache( imageLocation ):
  3314.             py.checkBox( self.checkBoxList["CustomImageIsCached"], edit = True, value = True )
  3315.         else:
  3316.             py.checkBox( self.checkBoxList["CustomImageIsCached"], edit = True, value = False )
  3317.        
  3318.         ImageStore().renderView( False )
  3319.  
  3320.    
  3321.     @classmethod
  3322.     def useRenderView( self ):
  3323.         py.textField( self.textFieldList["CustomImagePath"], edit = True, text = "RenderView" )
  3324.         py.button( self.buttonList["ValidateCustomImage"], query = True, command = True )()
  3325.  
  3326.  
  3327.     @classmethod
  3328.     def changeSceneSettings( self, imageFormat=None ):
  3329.        
  3330.         if imageFormat:
  3331.             ImageStore().renderView( imageFormat )
  3332.         renderViewFormat, ignoreFormats, uploadFormats = ImageStore().imageFormats()
  3333.         currentFormat = renderViewFormat[py.getAttr( "defaultRenderGlobals.imageFormat" )][0]
  3334.        
  3335.         lightBackground = 0.3
  3336.         darkBackground = 0.2
  3337.         for i in xrange( 3 ):
  3338.             if currentFormat == self.renderViewFormats[i]:
  3339.                 py.button( self.buttonList["RenderView"][currentFormat], edit = True, backgroundColor = ( lightBackground, lightBackground, lightBackground ) )
  3340.             else:
  3341.                 py.button( self.buttonList["RenderView"][self.renderViewFormats[i]], edit = True, backgroundColor = ( darkBackground, darkBackground, darkBackground ) )
  3342.  
  3343.        
  3344.     @classmethod
  3345.     def checkPathToImage( self, changeButtonColour=True ):
  3346.        
  3347.        
  3348.         valid = False
  3349.         imageLocation = py.textField( self.textFieldList["MainImagePath"], query = True, text = True )
  3350.        
  3351.         #Update multiple images text box
  3352.         imageLocationPrefix = imageLocation
  3353.         if len( imageLocationPrefix ) > 4:
  3354.             if "." in imageLocationPrefix[-5:]:
  3355.                 imageLocationPrefix = ".".join( imageLocationPrefix.split( "." )[:-1] )
  3356.            
  3357.         py.textField( self.textFieldList["MultipleImagesName"], edit = True, text = imageLocationPrefix + "." )
  3358.        
  3359.         #Check if image can be read
  3360.         if ImageStore().readImage( imageLocation ):
  3361.             py.checkBox( self.checkBoxList["ImagePathExists"], edit = True, value = True )
  3362.             py.button( self.buttonList["MainReadImage"], edit = True, enable = True )
  3363.             py.frameLayout( self.frameLayoutList["MainRead"], edit = True, collapse = False )
  3364.             valid = True
  3365.         else:
  3366.             py.checkBox( self.checkBoxList["ImagePathExists"], edit = True, value = False )
  3367.             py.frameLayout( self.frameLayoutList["MainRead"], edit = True, collapse = True )
  3368.             py.button( self.buttonList["MainReadImage"], edit = True, enable = False )
  3369.        
  3370.         #Check if image location can be written to
  3371.         content = None
  3372.        
  3373.         #Attempt to read
  3374.         try:
  3375.             with open( imageLocation ) as fileName:
  3376.                 content = fileName.read()
  3377.         except:
  3378.             pass
  3379.        
  3380.         try:
  3381.             with open( imageLocation, "w" ) as fileName:
  3382.                 if content:
  3383.                     fileName.write( content )
  3384.                 else:
  3385.                     fileName.write( "test" )
  3386.            
  3387.             #Remove if it didn't exist to start with
  3388.             if not content:
  3389.                 try:
  3390.                     os.remove( imageLocation )
  3391.                 except:
  3392.                     pass
  3393.                
  3394.                
  3395.             py.checkBox( self.checkBoxList["ImagePathWriteable"], edit = True, value = True )
  3396.             py.button( self.buttonList["MainWriteImage"], edit = True, enable = True )
  3397.             py.frameLayout( self.frameLayoutList["MainWrite"], edit = True, collapse = False )
  3398.             valid = True
  3399.            
  3400.         except:
  3401.             py.checkBox( self.checkBoxList["ImagePathWriteable"], edit = True, value = False )
  3402.             py.frameLayout( self.frameLayoutList["MainWrite"], edit = True, collapse = True )
  3403.             py.button( self.buttonList["MainWriteImage"], edit = True, enable = False )
  3404.        
  3405.         if changeButtonColour:
  3406.             if valid:
  3407.                 self.validButton( "ValidateMainImage", True )
  3408.             else:
  3409.                 self.validButton( "ValidateMainImage", False )
  3410.            
  3411.  
  3412.     @classmethod
  3413.     def fileReading( self, save=False, readImage=False, fieldType=None, fieldName=None, correspondingButton=None, updateIfNone=False ):
  3414.        
  3415.         #Set filter options
  3416.         filetypeFilter = "All Files (*.*)"
  3417.         if readImage:
  3418.             filetypeFilter = "PNG Files (*.png)"
  3419.             if not save:
  3420.                 filetypeFilter = "All Image Files (*.png *.jpg *.bmp *.psd *.jpeg);;PNG Files(*.png);;JPG Files(*.jpg *.jpeg);;BMP Files (*.bmp);;PSD Files (*.psd)"
  3421.        
  3422.         filePath = py.fileDialog2( fileFilter = filetypeFilter, fileMode = not save )
  3423.        
  3424.         #Send path to text box
  3425.         if filePath:
  3426.             command = "py.{0}( self.{1}, edit = True, text = '{2}' )".format( fieldType, "{0}List['{1}']".format( fieldType, fieldName ), filePath[0] )
  3427.             try:
  3428.                 exec( command )
  3429.             except:
  3430.                 pass
  3431.  
  3432.         #Check if image is valid
  3433.         if correspondingButton and ( updateIfNone or filePath ):
  3434.             command = "py.button( self.buttonList['{0}'], query = True, command = True )()".format( correspondingButton )
  3435.             try:
  3436.                 exec( command )
  3437.             except:
  3438.                 pass
  3439.        
  3440.         return filePath
  3441.  
  3442. class ISEncrypt:
  3443.    
  3444.     def __init__( self, key="hidden", keyLength=128 ):
  3445.        
  3446.         #Set the random seed
  3447.         m = md5.new()
  3448.         m.update( key )
  3449.         random.seed( m.digest() )
  3450.        
  3451.         #Generate new key from the random seed
  3452.         newKey = ""
  3453.         newKeyLength = keyLength
  3454.         i = 0
  3455.         while len( newKey ) < newKeyLength:
  3456.             newKey += random.choice( str( abs( zlib.crc32( key[i%len( key )] ) ) ) )
  3457.             i += 1
  3458.         self.newKeyList = [( int( x )*random.randint( 0, 255 ) )%255 for x in list( newKey )]
  3459.         self.newKeyListLength = len( self.newKeyList )
  3460.         random.shuffle( self.newKeyList )
  3461.        
  3462.         #Decide how many extra characters to add for each character
  3463.         originalKeyLength = len( key )
  3464.         self.extraCharacters = [random.randint( 0, max( 1, int( originalKeyLength**0.5 ) ) ) for x in xrange( originalKeyLength+1 )]
  3465.         self.charactersToAdd = [random.randint( 0, 255 ) for x in xrange( sum( self.extraCharacters ) + len( self.extraCharacters ) )]
  3466.         self.extraCharactersLength = len( self.extraCharacters )
  3467.         self.charactersToAddLength = len( self.charactersToAdd )
  3468.        
  3469.     def encode( self, input ):
  3470.        
  3471.         #Change letters based on values calculated from the key
  3472.         i = 0
  3473.         encodedString = ""
  3474.         for j in range( len( input ) ):
  3475.            
  3476.             letterToChange = input[j]
  3477.             characterNumber = ord( letterToChange )
  3478.            
  3479.             #Add extra letters so the word size is not so obvious
  3480.             for k in xrange( self.extraCharacters[j%self.extraCharactersLength]+1 ):
  3481.                 encodedString += chr( ( characterNumber+self.newKeyList[i%self.newKeyListLength]+self.charactersToAdd[i%self.charactersToAddLength] )%255 )
  3482.                 i += 1
  3483.        
  3484.         return encodedString
  3485.        
  3486.     def decode( self, input=None ):
  3487.        
  3488.         if input == None:
  3489.             return None
  3490.         encodedString = input
  3491.            
  3492.         #Find the indexes where the original letters should be
  3493.         extraCharactersIncrement = [self.extraCharacters[0]]
  3494.         i = 0
  3495.         while extraCharactersIncrement[-1] < len( encodedString ):
  3496.             i += 1
  3497.             extraCharactersIncrement.append( extraCharactersIncrement[-1]+self.extraCharacters[i%self.extraCharactersLength]+1 )
  3498.         extraCharactersIncrement = extraCharactersIncrement[:-1]
  3499.        
  3500.         #Decode the string
  3501.         decodedString = "".join( chr( ( ord( encodedString[i] )-self.newKeyList[i%self.newKeyListLength]-self.charactersToAdd[i%self.charactersToAddLength] )%255 ) for i in extraCharactersIncrement )
  3502.         return decodedString
  3503.        
  3504. if mayaEnvironment:
  3505.     UI = MayaUserInterface.display
  3506.    
  3507. if __name__ == '__main__':
  3508.     if mayaEnvironment:
  3509.         UI()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement