def _extract_photoshop_thumbnail(self): """ Extract a thumbnail from the current doc in Photoshop :returns str: The path to the thumbnail on disk """ import photoshop MAX_THUMB_SIZE = 512 # set unit system to pixels: original_ruler_units = photoshop.app.preferences.rulerUnits pixel_units = photoshop.StaticObject('com.adobe.photoshop.Units', 'PIXELS') photoshop.app.preferences.rulerUnits = pixel_units try: active_doc = photoshop.app.activeDocument orig_name = active_doc.name width_str = active_doc.width height_str = active_doc.height # build temp name for the thumbnail doc (just in case we fail to close it!): name, sfx = os.path.splitext(orig_name) thumb_name = "%s_tkthumb.%s" % (name, sfx) # find the doc size in pixels # Note: this doesn't handle measurements other than pixels. doc_width = doc_height = 0 exp = re.compile("^(?P<value>[0-9]+) px$") mo = exp.match(width_str) if mo: doc_width = int(mo.group("value")) mo = exp.match(height_str) if mo: doc_height = int(mo.group("value")) thumb_width = thumb_height = 0 if doc_width and doc_height: max_sz = max(doc_width, doc_height) if max_sz > MAX_THUMB_SIZE: scale = min(float(MAX_THUMB_SIZE) / float(max_sz), 1.0) thumb_width = max(min(int(doc_width * scale), doc_width), 1) thumb_height = max( min(int(doc_height * scale), doc_height), 1) # get a path in the temp dir to use for the thumbnail: png_pub_path = os.path.join(tempfile.gettempdir(), "%s_sgtk.png" % uuid.uuid4().hex) # get a file object from Photoshop for this path and the current PNG save options: thumbnail_file = photoshop.RemoteObject('flash.filesystem::File', png_pub_path) png_options = photoshop.RemoteObject( 'com.adobe.photoshop::PNGSaveOptions') # duplicate the original doc: save_options = photoshop.flexbase.requestStatic( 'com.adobe.photoshop.SaveOptions', 'DONOTSAVECHANGES') thumb_doc = active_doc.duplicate(thumb_name) try: # flatten image: thumb_doc.flatten() # resize if needed: if thumb_width and thumb_height: thumb_doc.resizeImage("%d px" % thumb_width, "%d px" % thumb_height) # save: thumb_doc.saveAs(thumbnail_file, png_options, True) finally: # close the doc: thumb_doc.close(save_options) return png_pub_path finally: # set units back to original photoshop.app.preferences.rulerUnits = original_ruler_units
errors.append( "Failed to construct export path for layer '%s': %s" % (layer_name, e)) return errors # ensure the export folder exists: export_folder = os.path.dirname(export_path) self.parent.ensure_folder_exists(export_folder) # get a path in the temp dir to use for the thumbnail: thumbnail_path = os.path.join(tempfile.gettempdir(), "%s_sgtk.png" % uuid.uuid4().hex) # set unit system to pixels: original_ruler_units = photoshop.app.preferences.rulerUnits pixel_units = photoshop.StaticObject('com.adobe.photoshop.Units', 'PIXELS') photoshop.app.preferences.rulerUnits = pixel_units # printerTool("More info", "Got here...") try: orig_name = active_doc.name width_str = active_doc.width height_str = active_doc.height # calculate the thumbnail doc size: doc_width = doc_height = 0 exp = re.compile("^(?P<value>[0-9]+) px$") mo = exp.match(width_str) if mo: doc_width = int(mo.group("value")) mo = exp.match(height_str)
def create_thumbnail(self, name="", targetpath=None, MAX_THUMB_SIZE=256): errors = [] if name == "": name = "thumbDouble" # get a path in the temp dir to use for the thumbnail: thumbnail_path = "" if targetpath != None: thumbnail_path = targetpath else: thumbnail_path = os.path.join(tempfile.gettempdir(), "%s_sgtk.png" % uuid.uuid4().hex) # set unit system to pixels: original_ruler_units = photoshop.app.preferences.rulerUnits pixel_units = photoshop.StaticObject('com.adobe.photoshop.Units', 'PIXELS') photoshop.app.preferences.rulerUnits = pixel_units try: active_doc = photoshop.app.activeDocument orig_name = active_doc.name width_str = active_doc.width height_str = active_doc.height # calculate the thumbnail doc size: doc_width = doc_height = 0 exp = re.compile("^(?P<value>[0-9]+) px$") mo = exp.match(width_str) if mo: doc_width = int(mo.group("value")) mo = exp.match(height_str) if mo: doc_height = int(mo.group("value")) thumb_width = thumb_height = 0 if doc_width and doc_height: max_sz = max(doc_width, doc_height) if max_sz > MAX_THUMB_SIZE: scale = min(float(MAX_THUMB_SIZE) / float(max_sz), 1.0) thumb_width = max(min(int(doc_width * scale), doc_width), 1) thumb_height = max( min(int(doc_height * scale), doc_height), 1) # set up the thumbnail options and get a file object: thumbnail_file = photoshop.RemoteObject('flash.filesystem::File', thumbnail_path) png_save_options = photoshop.RemoteObject( 'com.adobe.photoshop::PNGSaveOptions') close_save_options = photoshop.flexbase.requestStatic( 'com.adobe.photoshop.SaveOptions', 'DONOTSAVECHANGES') # duplicate doc doc_name, doc_sfx = os.path.splitext(orig_name) thumb_doc_name = "%s_%s.%s" % (doc_name, name, doc_sfx) thumb_doc = active_doc.duplicate(thumb_doc_name) try: # flatten thumb_doc.flatten() # resize for thumbnail if thumb_width and thumb_height: thumb_doc.resizeImage("%d px" % thumb_width, "%d px" % thumb_height) # save again (as thumbnail) thumb_doc.saveAs(thumbnail_file, png_save_options, True) finally: # close the doc: thumb_doc.close(close_save_options) except: errors.append("Failed to construct thumbnail for '%s': %s" % (name, e)) return errors return thumbnail_path
class PublishHook(Hook): """ Single hook that implements publish functionality for secondary tasks """ def execute(self, tasks, work_template, comment, thumbnail_path, sg_task, primary_task, primary_publish_path, progress_cb, **kwargs): """ Main hook entry point :param tasks: List of secondary tasks to be published. Each task is a dictionary containing the following keys: { item: Dictionary This is the item returned by the scan hook { name: String description: String type: String other_params: Dictionary } output: Dictionary This is the output as defined in the configuration - the primary output will always be named 'primary' { name: String publish_template: template tank_type: String } } :param work_template: template This is the template defined in the config that represents the current work file :param comment: String The comment provided for the publish :param thumbnail: Path string The default thumbnail provided for the publish :param sg_task: Dictionary (shotgun entity description) The shotgun task to use for the publish :param primary_publish_path: Path string This is the path of the primary published file as returned by the primary publish hook :param progress_cb: Function A progress callback to log progress during pre-publish. Call: progress_cb(percentage, msg) to report progress to the UI :param primary_task: The primary task that was published by the primary publish hook. Passed in here for reference. This is a dictionary in the same format as the secondary tasks above. :returns: A list of any tasks that had problems that need to be reported in the UI. Each item in the list should be a dictionary containing the following keys: { task: Dictionary This is the task that was passed into the hook and should not be modified { item:... output:... } errors: List A list of error messages (strings) to report } """ results = [] active_doc = photoshop.app.activeDocument scene_path = active_doc.fullName.nativePath # publish all tasks: for task in tasks: item = task["item"] output = task["output"] errors = [] # report progress: progress_cb(0, "Publishing", task) # merged doc as tif if output["name"] == "tif_output": # publish the layer as a tif: output_errors = self.__publish_merged_as_tif( work_template, output["publish_template"], scene_path, active_doc, sg_task, comment, progress_cb) if output_errors: errors += output_errors # groups elif output["name"] == "export_groups": # publish the layer as a tif: export_errors = self.__publish_group_as_tif( item["name"], work_template, output["publish_template"], scene_path, active_doc, primary_publish_path, sg_task, comment, progress_cb) if export_errors: errors += export_errors else: # don't know how to publish this output types! errors.append("Don't know how to publish this item!") # if there is anything to report then add to result if len(errors) > 0: # add result: results.append({"task": task, "errors": errors}) progress_cb(100) return results def __publish_merged_as_tif(self, work_template, publish_template, scene_path, active_doc, sg_task, comment, progress_cb): """ Publish the flattened doc as a tif """ errors = [] progress_cb(10, "Building output path") # generate the export path using the correct template together # with the fields extracted from the work template: export_path = None try: fields = work_template.get_fields(scene_path) fields = dict( chain( fields.items(), self.parent.context.as_template_fields( publish_template).items())) #fields["TankType"] = publish_type export_path = publish_template.apply_fields(fields).encode("utf8") except TankError, e: errors.append("Failed to construct export path: %s" % (e)) return errors # ensure the export folder exists: export_folder = os.path.dirname(export_path) self.parent.ensure_folder_exists(export_folder) # set unit system to pixels: original_ruler_units = photoshop.app.preferences.rulerUnits pixel_units = photoshop.StaticObject('com.adobe.photoshop.Units', 'PIXELS') photoshop.app.preferences.rulerUnits = pixel_units try: orig_name = active_doc.name width_str = active_doc.width height_str = active_doc.height # set up the export options and get a file object: tiff_file = photoshop.RemoteObject('flash.filesystem::File', export_path) tiff_save_options = photoshop.RemoteObject( 'com.adobe.photoshop::TiffSaveOptions') tiff_save_options.layers = False close_save_options = photoshop.flexbase.requestStatic( 'com.adobe.photoshop.SaveOptions', 'DONOTSAVECHANGES') progress_cb(20, "Exporting to tif") # duplicate doc doc_name, doc_sfx = os.path.splitext(orig_name) temp_doc_name = "%s_temp.%s" % (doc_name, doc_sfx) temp_doc = active_doc.duplicate(temp_doc_name) try: # flatten temp_doc.flatten() # save: temp_doc.saveAs(tiff_file, tiff_save_options, True) finally: # close the doc: temp_doc.close(close_save_options) finally: # set units back to original photoshop.app.preferences.rulerUnits = original_ruler_units return errors