From 1ca405414e722bb9f6b9364041a6fe557da091d0 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 10 Aug 2008 02:26:12 -0400 Subject: [PATCH] Initial commit. --- .gitignore | 1 + Configuration/CmdLineOptions.py | 0 Configuration/ConfigFile.py | 0 Configuration/Defaults.py | 9 +++ Configuration/__init__.py | 94 +++++++++++++++++++++++++ Mime/SupportedType.py | 76 ++++++++++++++++++++ Mime/XmlDataParser.py | 119 ++++++++++++++++++++++++++++++++ Mime/__init__.py | 0 Pictar.py | 103 +++++++++++++++++++++++++++ TemplateParser.py | 16 +++++ default_page_template.html | 20 ++++++ default_stylesheet.css | 42 +++++++++++ mimetypes.xml | 37 ++++++++++ pictar | 25 +++++++ templates/img.html | 8 +++ templates/object.html | 11 +++ test_cases/.gif.fail | 0 test_cases/.jpeg.fail | 0 test_cases/.jpg.fail | 0 test_cases/.pass.gif | 0 test_cases/.pass.jpeg | 0 test_cases/.pass.jpg | 0 test_cases/.pass.png | 0 test_cases/.pass.svg | 0 test_cases/.pass.svgz | 0 test_cases/.png.fail | 0 test_cases/.svg.fail | 0 test_cases/.svgz.fail | 0 test_cases/fail.gif.s | 0 test_cases/fail.jpeg.s | 0 test_cases/fail.jpg.s | 0 test_cases/fail.png.s | 0 test_cases/fail.svg.s | 0 test_cases/fail.svgz.s | 0 test_cases/failjpeg | 0 test_cases/failjpg | 0 test_cases/failpng | 0 test_cases/failsvg | 0 test_cases/failsvgz | 0 test_cases/pass.GIF | 0 test_cases/pass.JPG | 0 test_cases/pass.gif | 0 test_cases/pass.jpEg | 0 test_cases/pass.jpeg | 0 test_cases/pass.jpg | 0 test_cases/pass.png | 0 test_cases/pass.svG | 0 test_cases/pass.svg | 0 48 files changed, 561 insertions(+) create mode 100644 .gitignore create mode 100644 Configuration/CmdLineOptions.py create mode 100644 Configuration/ConfigFile.py create mode 100644 Configuration/Defaults.py create mode 100644 Configuration/__init__.py create mode 100644 Mime/SupportedType.py create mode 100644 Mime/XmlDataParser.py create mode 100644 Mime/__init__.py create mode 100644 Pictar.py create mode 100644 TemplateParser.py create mode 100644 default_page_template.html create mode 100644 default_stylesheet.css create mode 100644 mimetypes.xml create mode 100755 pictar create mode 100644 templates/img.html create mode 100644 templates/object.html create mode 100644 test_cases/.gif.fail create mode 100644 test_cases/.jpeg.fail create mode 100644 test_cases/.jpg.fail create mode 100644 test_cases/.pass.gif create mode 100644 test_cases/.pass.jpeg create mode 100644 test_cases/.pass.jpg create mode 100644 test_cases/.pass.png create mode 100644 test_cases/.pass.svg create mode 100644 test_cases/.pass.svgz create mode 100644 test_cases/.png.fail create mode 100644 test_cases/.svg.fail create mode 100644 test_cases/.svgz.fail create mode 100644 test_cases/fail.gif.s create mode 100644 test_cases/fail.jpeg.s create mode 100644 test_cases/fail.jpg.s create mode 100644 test_cases/fail.png.s create mode 100644 test_cases/fail.svg.s create mode 100644 test_cases/fail.svgz.s create mode 100644 test_cases/failjpeg create mode 100644 test_cases/failjpg create mode 100644 test_cases/failpng create mode 100644 test_cases/failsvg create mode 100644 test_cases/failsvgz create mode 100644 test_cases/pass.GIF create mode 100644 test_cases/pass.JPG create mode 100644 test_cases/pass.gif create mode 100644 test_cases/pass.jpEg create mode 100644 test_cases/pass.jpeg create mode 100644 test_cases/pass.jpg create mode 100644 test_cases/pass.png create mode 100644 test_cases/pass.svG create mode 100644 test_cases/pass.svg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/Configuration/CmdLineOptions.py b/Configuration/CmdLineOptions.py new file mode 100644 index 0000000..e69de29 diff --git a/Configuration/ConfigFile.py b/Configuration/ConfigFile.py new file mode 100644 index 0000000..e69de29 diff --git a/Configuration/Defaults.py b/Configuration/Defaults.py new file mode 100644 index 0000000..8e6bfc9 --- /dev/null +++ b/Configuration/Defaults.py @@ -0,0 +1,9 @@ +import os, sys + +MIMETYPES_FILE_NAME = os.path.realpath(sys.path[0]) + '/mimetypes.xml' +PAGE_TEMPLATE_FILE_NAME = os.path.realpath(sys.path[0]) + '/default_page_template.html' +STYLESHEET_FILE_NAME = os.path.realpath(sys.path[0]) + '/default_stylesheet.css' +BROWSER_COMMAND = '/usr/bin/firefox' + +ITEM_WIDTH = 800 +ITEM_HEIGHT = 600 diff --git a/Configuration/__init__.py b/Configuration/__init__.py new file mode 100644 index 0000000..62912b9 --- /dev/null +++ b/Configuration/__init__.py @@ -0,0 +1,94 @@ +import os +import sys +import time +import md5 +import tempfile +import Defaults + + +def GetPictarDir(): + rel_script_path = sys.argv[0] + abs_script_path = os.path.abspath(rel_script_path) + abs_script_dir = os.path.dirname(abs_script_path) + + return abs_script_dir + + +def GetBrowserCommand(): + # Get the command used to execute the user's browser. + return Defaults.BROWSER_COMMAND + + +def GetAbsTargetDir(): + rel_target_dir = os.getcwd() + argc = len(sys.argv) + + if (argc > 1): + # If no directory was passed to the program, + # use the current working directory as the target. + # Otherwise, use the passed directory. + rel_target_dir = sys.argv[1] + + # Convert a relative path into an absolute one. + # It will be important to have an absolute path + # later when we are constructing URLs. + __abs_target_dir = os.path.abspath(rel_target_dir) + + return __abs_target_dir + + + + +def GetPageTemplatePath(): + script_dir = GetPictarDir() + page_template_path = os.path.join(script_dir, Defaults.PAGE_TEMPLATE_FILE_NAME) + + return page_template_path + + + +def GetRecursive(): + __recursive = False + return __recursive + + + +def GetOutfilePath(): + unique_string = str(time.time()) + md5hash = md5.new(unique_string) + outfile_name = md5hash.hexdigest() + outfile_path = os.path.join(tempfile.gettempdir(), outfile_name) + + return outfile_path + + + + + + +def GetItemTemplatePath(): + script_dir = GetPictarDir() + item_template_path = os.path.join(script_dir, Defaults.ITEM_TEMPLATE_FILE_NAME) + + return item_template_path + + + +def GetStyleSheetPath(): + script_dir = GetPictarDir() + stylesheet_path = os.path.join(script_dir, Defaults.STYLESHEET_FILE_NAME) + + return stylesheet_path + + + +def GetVerbose(): + return True + + +def GetMimetypesFilePath(): + script_dir = GetPictarDir() + mimetypes_file_path = os.path.join(script_dir, Defaults.MIMETYPES_FILE_NAME) + + return mimetypes_file_path + diff --git a/Mime/SupportedType.py b/Mime/SupportedType.py new file mode 100644 index 0000000..9ab2f3e --- /dev/null +++ b/Mime/SupportedType.py @@ -0,0 +1,76 @@ + +""" +Wrapper class for the 'filetype' elements in the config file. Nothing +tricky here, except that the accessor for the template should +intelligently determine which of the two fields (template_file, +template_data) is used as the template source. +""" + +class SupportedType: + + def __init__(self, + name = "", + description = "", + extensions = [], + template_file = "", + template_data = ""): + + self.__name = name + self.__description = description + self.__extensions = extensions + self.__template_file = template_file + self.__template_data = template_data + + return + + + + def GetName(self): + return self.__name + + + def GetDescription(self): + return self.__description + + + def GetExtensions(self): + return self.__extensions + + + def GetTemplate(self): + if (self.__template_data == None or self.__template_data == ""): + # The data is not given explicitly, so rely on the + # template file to provide it. + template_file = open(self.__template_file, "r") + template = template_file.read() + template_file.close() + return template + else: + return self.__template_data + + + + def SetName(self, name): + self.__name = name + return + + + def SetDescription(self, description): + self.__description = description + return + + + def SetExtensions(self, extensions): + self.__extensions = extensions + return + + + def SetTemplateData(self, template_data): + self.__template_data = template_data + return + + + def SetTemplateFile(self, template_file): + self.__template_file = template_file + return + diff --git a/Mime/XmlDataParser.py b/Mime/XmlDataParser.py new file mode 100644 index 0000000..4cd3bec --- /dev/null +++ b/Mime/XmlDataParser.py @@ -0,0 +1,119 @@ +import os +from SupportedType import SupportedType +from xml.dom import Node +from xml.dom.ext.reader.Sax import FromXmlFile + +""" +This class parses all of the information in the config file, and makes +it available through various methods. +""" + +class XmlDataParser: + + def __init__(self, xml_file_path): + self.__supported_types = [] + + xml_doc = FromXmlFile(xml_file_path) + + supported_type_elements = xml_doc.getElementsByTagName('supported_type') + + for current_node in supported_type_elements: + name = self.GetChildrenText(current_node, 'name')[0] + descriptions = self.GetChildrenText(current_node, 'description') + extensions = self.GetChildrenText(current_node, 'extension') + template_files = self.GetChildrenText(current_node, 'template_file') + template_data = self.GetChildrenText(current_node, 'template_data') + + current_type = SupportedType() + current_type.SetName(name) + current_type.SetExtensions(extensions) + + if (len(descriptions) > 0): + current_type.SetDescription(descriptions[0]) + + + if (len(template_files) > 0): + # Allow for relative paths in the template field + root_dir = os.path.dirname(xml_file_path) + template_file_path = os.path.join(root_dir, template_files[0]) + current_type.SetTemplateFile(template_file_path) + + + if (len(template_data) > 0): + current_type.SetTemplateData(template_data[0]) + + self.__supported_types.append(current_type) + + return + + + + def GetAllExtensions(self): + all_extensions = [] + + for current_type in self.__supported_types: + current_type_extensions = current_type.GetExtensions() + for extension in current_type_extensions: + all_extensions.append(extension) + + return all_extensions + + + + def GetTemplateByExtension(self, extension): + # Get the (x)html template which corresponds to a mimetype + # having the supplied extension. + for current_type in self.__supported_types: + current_type_extensions = current_type.GetExtensions() + + for current_extension in current_type_extensions: + if (current_extension.lower() == extension.lower()): + return current_type.GetTemplate() + + return None + + + + def GetNameByExtension(self, extension): + # Get the name of the mimetype that a particular extension + # belongs to. + for current_type in self.__supported_types: + current_type_extensions = current_type.GetExtensions() + + for current_extension in current_type_extensions: + if (current_extension.lower() == extension.lower()): + return current_type.GetName() + + return None + + + + def GetChildNodesByTagName(self, node, tag_name): + found_children = [] + + for child in node.childNodes: + if (child.nodeName == tag_name): + found_children.append(child) + + return found_children + + + + + def GetChildrenText(self, node, child_tag_name): + children_text = [] + + children = self.GetChildNodesByTagName(node, child_tag_name) + + for child_node in children: + for sub_child in child_node.childNodes: + if (sub_child.nodeType == Node.TEXT_NODE): + children_text.append(sub_child.nodeValue) + break + + + return children_text + + + + diff --git a/Mime/__init__.py b/Mime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Pictar.py b/Pictar.py new file mode 100644 index 0000000..67a056f --- /dev/null +++ b/Pictar.py @@ -0,0 +1,103 @@ +import re +import os +import sys +import urllib + +import Configuration + +from string import Template +from TemplateParser import * +from Mime.XmlDataParser import XmlDataParser + + +class Pictar: + + def __init__(self): + self.template_parser = TemplateParser() + self.__data_parser = XmlDataParser(Configuration.GetMimetypesFilePath()) + + + # Compile the regular expressions only once + self.item_regexes = [] + + extensions = self.__data_parser.GetAllExtensions() + + for extension in extensions: + pattern = '\\' + extension + '$' + self.item_regexes.append(re.compile(pattern, re.IGNORECASE)) + + return + + + + def GetItemPaths(self): + # Create a list of the item paths based on which + # of the files in the target directory match at least + # one of the item regular expressions. + target_dir = Configuration.GetAbsTargetDir() + + item_paths = [] + + dir_contents = os.listdir(target_dir) + + for file_name in dir_contents: + for regex_obj in self.item_regexes: + if (regex_obj.search(file_name) != None): + absolute_item_path = os.path.join(target_dir, file_name) + encoded_path = urllib.quote(absolute_item_path) + item_paths.append(encoded_path) + + return item_paths + + + + def GetItemData(self, item_paths): + # Build the pictar markup + item_data = "" + current_item_number = 0 + + for item_path in item_paths: + current_item_number += 1 + item_extension = os.path.splitext(item_path)[1] + item_template = Template(self.__data_parser.GetTemplateByExtension(item_extension)) + item_mimetype = self.__data_parser.GetNameByExtension(item_extension) + + current_item_data = item_template.substitute(header=item_path, + image_path=item_path, + item_number=current_item_number, + height=Configuration.Defaults.ITEM_HEIGHT, + width=Configuration.Defaults.ITEM_WIDTH, + mimetype=item_mimetype); + + item_data += current_item_data + + return item_data + + + + def GetPageData(self, item_data): + # Fill in the template with our markup + stylesheet_file_name = Configuration.GetStyleSheetPath() + page_template = self.template_parser.GetPageTemplate() + page_data = page_template.substitute(stylesheet=stylesheet_file_name, + pictar_markup=item_data) + + return page_data + + + + def LaunchBrowser(self, url='about:blank'): + launch_result = os.spawnl(os.P_WAIT, Configuration.GetBrowserCommand(), Configuration.GetBrowserCommand(), url) + return launch_result + + + + def WritePage(self, page_data): + # Write the output file + outfile_path = Configuration.GetOutfilePath() + + outfile = open(outfile_path, "w") + outfile.write(page_data) + outfile.close() + + return outfile_path diff --git a/TemplateParser.py b/TemplateParser.py new file mode 100644 index 0000000..fcf044c --- /dev/null +++ b/TemplateParser.py @@ -0,0 +1,16 @@ +import Configuration +from string import Template + + +class TemplateParser: + + def GetPageTemplate(self): + # Read the page template file into a string + page_template_path = Configuration.GetPageTemplatePath() + page_template_file = open(page_template_path, "r") + page_template = Template(page_template_file.read()) + page_template_file.close() + + return page_template + + diff --git a/default_page_template.html b/default_page_template.html new file mode 100644 index 0000000..a4386a4 --- /dev/null +++ b/default_page_template.html @@ -0,0 +1,20 @@ + + + + + + + + PICTAR + + + + + + + + ${pictar_markup} + + + + diff --git a/default_stylesheet.css b/default_stylesheet.css new file mode 100644 index 0000000..93e3667 --- /dev/null +++ b/default_stylesheet.css @@ -0,0 +1,42 @@ +/************/ +/* ELEMENTS */ +/************/ + +body { + margin: 0em; + padding: 0em; + background-color: #ebebae; +} + + +img { + border: 0em; + border-top: 1px #000000 dashed; + padding: 20px; +} + + +/***********/ +/* CLASSES */ +/***********/ + +.image_container { + display: table; + background-color: #f0ead8; + border: 1px #000000 dashed; + margin-left: 5px; + margin-top: 20px; + margin-bottom: 20px; +} + + +.image_header { + background-color: #bf3e18; + color: #ffffff; + font-weight: bold; + text-align: center; + padding: .2em; + font-family: fixed, monospace; +} + + diff --git a/mimetypes.xml b/mimetypes.xml new file mode 100644 index 0000000..4fa1099 --- /dev/null +++ b/mimetypes.xml @@ -0,0 +1,37 @@ + + + + + + + + image/gif + Graphics Interchange Format (GIF) Image + .gif + templates/img.html + + + + image/jpeg + Joint Photographic Experts Group (JPEG) Image + .jpg + .jpe + .jpeg + templates/img.html + + + + image/png + Portable Network Graphic + .png + templates/img.html + + + + image/svg+xml + Scalable Vector Graphic + .svg + templates/object.html + + + \ No newline at end of file diff --git a/pictar b/pictar new file mode 100755 index 0000000..e4a3e8e --- /dev/null +++ b/pictar @@ -0,0 +1,25 @@ +#!/usr/bin/python + +from Pictar import * + +the_pictar = Pictar() + + +""" +if (os.path.isdir(target_dir) == False): + print "Error: The given directory, \"" + target_dir + "\", is invalid.\n" + sys.exit(FAILURE) +""" + + + +image_paths = the_pictar.GetItemPaths() + +image_data = the_pictar.GetItemData(image_paths) + +page_data = the_pictar.GetPageData(image_data) + +outfile = the_pictar.WritePage(page_data) + +the_pictar.LaunchBrowser(outfile) + diff --git a/templates/img.html b/templates/img.html new file mode 100644 index 0000000..0a0d315 --- /dev/null +++ b/templates/img.html @@ -0,0 +1,8 @@ +
+
+ ${header} +
+ + Pictar Image ${item_number} +
diff --git a/templates/object.html b/templates/object.html new file mode 100644 index 0000000..c69a543 --- /dev/null +++ b/templates/object.html @@ -0,0 +1,11 @@ +
+
+ ${header} +
+ + + + \ No newline at end of file diff --git a/test_cases/.gif.fail b/test_cases/.gif.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.jpeg.fail b/test_cases/.jpeg.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.jpg.fail b/test_cases/.jpg.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.gif b/test_cases/.pass.gif new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.jpeg b/test_cases/.pass.jpeg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.jpg b/test_cases/.pass.jpg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.png b/test_cases/.pass.png new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.svg b/test_cases/.pass.svg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.pass.svgz b/test_cases/.pass.svgz new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.png.fail b/test_cases/.png.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.svg.fail b/test_cases/.svg.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/.svgz.fail b/test_cases/.svgz.fail new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.gif.s b/test_cases/fail.gif.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.jpeg.s b/test_cases/fail.jpeg.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.jpg.s b/test_cases/fail.jpg.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.png.s b/test_cases/fail.png.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.svg.s b/test_cases/fail.svg.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/fail.svgz.s b/test_cases/fail.svgz.s new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/failjpeg b/test_cases/failjpeg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/failjpg b/test_cases/failjpg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/failpng b/test_cases/failpng new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/failsvg b/test_cases/failsvg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/failsvgz b/test_cases/failsvgz new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.GIF b/test_cases/pass.GIF new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.JPG b/test_cases/pass.JPG new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.gif b/test_cases/pass.gif new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.jpEg b/test_cases/pass.jpEg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.jpeg b/test_cases/pass.jpeg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.jpg b/test_cases/pass.jpg new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.png b/test_cases/pass.png new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.svG b/test_cases/pass.svG new file mode 100644 index 0000000..e69de29 diff --git a/test_cases/pass.svg b/test_cases/pass.svg new file mode 100644 index 0000000..e69de29 -- 2.43.2