def makeTagsetCanvas(tagString, tagsetPixIds, showSubsetLabels): log(" Tagset: %s (contains %d images)" % (tagString, len(tagsetPixIds))) if not showSubsetLabels: tagString = None subCanvas = imgUtil.paintThumbnailGrid( thumbnailStore, length, spacing, tagsetPixIds, colCount, topLabel=tagString) tagSubPanes.append(subCanvas)
def makeTagsetCanvas(tagString, tagsetPixIds, showSubsetLabels): log(" Tagset: %s (contains %d images)" % (tagString, len(tagsetPixIds))) if not showSubsetLabels: tagString = None subCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, tagsetPixIds, colCount, topLabel=tagString) tagSubPanes.append(subCanvas)
def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged=False, colCount=10, length=100): """ Paints and returns a canvas of thumbnails from images, laid out in a set number of columns. Title and date-range of the images is printed above the thumbnails, to the left and right, respectively. @param conn: Blitz connection @param imageIds: Image IDs @param title: title to display at top of figure. String @param tagIds: Optional to sort thumbnails by tag. [long] @param colCount: Max number of columns to lay out thumbnails @param length: Length of longest side of thumbnails """ mode = "RGB" figCanvas = None spacing = length / 40 + 2 thumbnailStore = conn.createThumbnailStore() # returns omero.api.ThumbnailStorePrx metadataService = conn.getMetadataService() if len(images) == 0: return None timestampMin = images[0].getDate() # datetime timestampMax = timestampMin dsImageIds = [] imagePixelMap = {} imageNames = {} # sort the images by name images.sort(key=lambda x: (x.getName().lower())) for image in images: imageId = image.getId() pixelId = image.getPrimaryPixels().getId() name = image.getName() dsImageIds.append(imageId) # make a list of image-IDs imagePixelMap[imageId] = pixelId # and a map of image-ID: pixel-ID imageNames[imageId] = name timestampMin = min(timestampMin, image.getDate()) timestampMax = max(timestampMax, image.getDate()) # set-up fonts fontsize = length / 7 + 5 font = imgUtil.getFont(fontsize) textHeight = font.getsize("Textq")[1] topSpacer = spacing + textHeight leftSpacer = spacing + textHeight tagPanes = [] maxWidth = 0 totalHeight = topSpacer # if we have a list of tags, then sort images by tag if tagIds: # Cast to int since List can be any type tagIds = [int(tagId) for tagId in tagIds] log(" Sorting images by tags: %s" % tagIds) tagNames = {} taggedImages = {} # a map of tagId: list-of-image-Ids imgTags = {} # a map of imgId: list-of-tagIds for tagId in tagIds: taggedImages[tagId] = [] # look for images that have a tag types = ["ome.model.annotations.TagAnnotation"] annotations = metadataService.loadAnnotations("Image", dsImageIds, types, None, None) # filter images by annotation... for imageId, tags in annotations.items(): imgTagIds = [] for tag in tags: tagId = tag.getId().getValue() # make a dict of tag-names tagNames[tagId] = tag.getTextValue().getValue().decode('utf8') print " Tag:", tagId, tagId in tagIds imgTagIds.append(tagId) imgTags[imageId] = imgTagIds # get a sorted list of {'iid': iid, 'tagKey': tagKey, # 'tagIds':orderedTags} sortedThumbs = sortImagesByTag(tagIds, imgTags) if not showUntagged: sortedThumbs = [t for t in sortedThumbs if len(t['tagIds']) > 0] # Need to group sets of thumbnails by FIRST tag. toptagSets = [] groupedPixelIds = [] showSubsetLabels = False currentTagStr = None for i, img in enumerate(sortedThumbs): tagIds = img['tagIds'] if len(tagIds) == 0: tagString = "Not Tagged" else: tagString = tagNames[tagIds[0]] if tagString == currentTagStr or currentTagStr is None: # only show subset labels (later) if there are more than 1 # subset if (len(tagIds) > 1): showSubsetLabels = True groupedPixelIds.append({ 'pid': imagePixelMap[img['iid']], 'tagIds': tagIds }) else: toptagSets.append({ 'tagText': currentTagStr, 'pixelIds': groupedPixelIds, 'showSubsetLabels': showSubsetLabels }) showSubsetLabels = len(tagIds) > 1 groupedPixelIds = [{ 'pid': imagePixelMap[img['iid']], 'tagIds': tagIds }] currentTagStr = tagString toptagSets.append({ 'tagText': currentTagStr, 'pixelIds': groupedPixelIds, 'showSubsetLabels': showSubsetLabels }) # Find the indent we need maxTagNameWidth = max( [font.getsize(ts['tagText'])[0] for ts in toptagSets]) if showUntagged: maxTagNameWidth = max(maxTagNameWidth, font.getsize("Not Tagged")[0]) print "toptagSets", toptagSets tagSubPanes = [] # make a canvas for each tag combination def makeTagsetCanvas(tagString, tagsetPixIds, showSubsetLabels): log(" Tagset: %s (contains %d images)" % (tagString, len(tagsetPixIds))) if not showSubsetLabels: tagString = None subCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, tagsetPixIds, colCount, topLabel=tagString) tagSubPanes.append(subCanvas) for toptagSet in toptagSets: tagText = toptagSet['tagText'] showSubsetLabels = toptagSet['showSubsetLabels'] imageData = toptagSet['pixelIds'] # loop through all thumbs under TAG, grouping into subsets. tagsetPixIds = [] currentTagStr = None for i, img in enumerate(imageData): tag_ids = img['tagIds'] pid = img['pid'] tagString = ", ".join([tagNames[tid] for tid in tag_ids]) if tagString == "": tagString = "Not Tagged" # Keep grouping thumbs under similar tag set (if not on the # last loop) if tagString == currentTagStr or currentTagStr is None: tagsetPixIds.append(pid) else: # Process thumbs added so far makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels) # reset for next tagset tagsetPixIds = [pid] currentTagStr = tagString makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels) maxWidth = max([c.size[0] for c in tagSubPanes]) totalHeight = sum([c.size[1] for c in tagSubPanes]) # paste them into a single canvas for each Tag leftSpacer = spacing + maxTagNameWidth + 2 * spacing # Draw vertical line to right size = (leftSpacer + maxWidth, totalHeight) tagCanvas = Image.new(mode, size, WHITE) pX = leftSpacer pY = 0 for pane in tagSubPanes: imgUtil.pasteImage(pane, tagCanvas, pX, pY) pY += pane.size[1] if tagText is not None: draw = ImageDraw.Draw(tagCanvas) tt_w, tt_h = font.getsize(tagText) h_offset = (totalHeight - tt_h) / 2 draw.text((spacing, h_offset), tagText, font=font, fill=(50, 50, 50)) # draw vertical line draw.line( (leftSpacer - spacing, 0, leftSpacer - spacing, totalHeight), fill=(0, 0, 0)) tagPanes.append(tagCanvas) tagSubPanes = [] else: leftSpacer = spacing pixelIds = [] for imageId in dsImageIds: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) figCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount) tagPanes.append(figCanvas) # paste them into a single canvas tagsetSpacer = length / 3 maxWidth = max([c.size[0] for c in tagPanes]) totalHeight = totalHeight + sum( [c.size[1] + tagsetSpacer for c in tagPanes]) - tagsetSpacer size = (maxWidth, totalHeight) fullCanvas = Image.new(mode, size, WHITE) pX = 0 pY = topSpacer for pane in tagPanes: imgUtil.pasteImage(pane, fullCanvas, pX, pY) pY += pane.size[1] + tagsetSpacer # create dates for the image timestamps. If dates are not the same, show # first - last. # firstdate = timestampMin # lastdate = timestampMax # figureDate = str(firstdate) # if firstdate != lastdate: # figureDate = "%s - %s" % (firstdate, lastdate) draw = ImageDraw.Draw(fullCanvas) # dateWidth = draw.textsize(figureDate, font=font)[0] # titleWidth = draw.textsize(title, font=font)[0] dateY = spacing # dateX = fullCanvas.size[0] - spacing - dateWidth draw.text((leftSpacer, dateY), title, font=font, fill=(0, 0, 0)) # title # Don't show dates: see # https://github.com/openmicroscopy/openmicroscopy/pull/1002 # if (leftSpacer+titleWidth) < dateX: # if there's enough space... # draw.text((dateX, dateY), figureDate, font=font, fill=(0,0,0)) # add date return fullCanvas
def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged=False, colCount=10, length=100): """ Paints and returns a canvas of thumbnails from images, laid out in a set number of columns. Title and date-range of the images is printed above the thumbnails, to the left and right, respectively. @param conn: Blitz connection @param imageIds: Image IDs @param title: title to display at top of figure. String @param tagIds: Optional to sort thumbnails by tag. [long] @param colCount: Max number of columns to lay out thumbnails @param length: Length of longest side of thumbnails """ mode = "RGB" figCanvas = None spacing = length/40 + 2 thumbnailStore = conn.createThumbnailStore() # returns omero.api.ThumbnailStorePrx metadataService = conn.getMetadataService() if len(images) == 0: return None timestampMin = images[0].getDate() # datetime timestampMax = timestampMin dsImageIds = [] imagePixelMap = {} imageNames = {} # sort the images by name images.sort(key=lambda x: (x.getName().lower())) for image in images: imageId = image.getId() pixelId = image.getPrimaryPixels().getId() name = image.getName() dsImageIds.append(imageId) # make a list of image-IDs imagePixelMap[imageId] = pixelId # and a map of image-ID: pixel-ID imageNames[imageId] = name timestampMin = min(timestampMin, image.getDate()) timestampMax = max(timestampMax, image.getDate()) # set-up fonts fontsize = length/7 + 5 font = imgUtil.getFont(fontsize) textHeight = font.getsize("Textq")[1] topSpacer = spacing + textHeight leftSpacer = spacing + textHeight tagPanes = [] maxWidth = 0 totalHeight = topSpacer # if we have a list of tags, then sort images by tag if tagIds: # Cast to int since List can be any type tagIds = [int(tagId) for tagId in tagIds] log(" Sorting images by tags: %s" % tagIds) tagNames = {} taggedImages = {} # a map of tagId: list-of-image-Ids imgTags = {} # a map of imgId: list-of-tagIds for tagId in tagIds: taggedImages[tagId] = [] # look for images that have a tag types = ["ome.model.annotations.TagAnnotation"] annotations = metadataService.loadAnnotations( "Image", dsImageIds, types, None, None) # filter images by annotation... for imageId, tags in annotations.items(): imgTagIds = [] for tag in tags: tagId = tag.getId().getValue() # make a dict of tag-names tagNames[tagId] = tag.getTextValue().getValue() print " Tag:", tagId, tagId in tagIds imgTagIds.append(tagId) imgTags[imageId] = imgTagIds # get a sorted list of {'iid': iid, 'tagKey': tagKey, # 'tagIds':orderedTags} sortedThumbs = sortImagesByTag(tagIds, imgTags) if not showUntagged: sortedThumbs = [t for t in sortedThumbs if len(t['tagIds']) > 0] # Need to group sets of thumbnails by FIRST tag. toptagSets = [] groupedPixelIds = [] showSubsetLabels = False currentTagStr = None for i, img in enumerate(sortedThumbs): tagIds = img['tagIds'] if len(tagIds) == 0: tagString = "Not Tagged" else: tagString = tagNames[tagIds[0]] if tagString == currentTagStr or currentTagStr is None: # only show subset labels (later) if there are more than 1 # subset if (len(tagIds) > 1): showSubsetLabels = True groupedPixelIds.append({ 'pid': imagePixelMap[img['iid']], 'tagIds': tagIds}) else: toptagSets.append({ 'tagText': currentTagStr, 'pixelIds': groupedPixelIds, 'showSubsetLabels': showSubsetLabels}) showSubsetLabels = len(tagIds) > 1 groupedPixelIds = [{ 'pid': imagePixelMap[img['iid']], 'tagIds': tagIds}] currentTagStr = tagString toptagSets.append({ 'tagText': currentTagStr, 'pixelIds': groupedPixelIds, 'showSubsetLabels': showSubsetLabels}) # Find the indent we need maxTagNameWidth = max([font.getsize(ts['tagText'])[0] for ts in toptagSets]) if showUntagged: maxTagNameWidth = max(maxTagNameWidth, font.getsize("Not Tagged")[0]) print "toptagSets", toptagSets tagSubPanes = [] # make a canvas for each tag combination def makeTagsetCanvas(tagString, tagsetPixIds, showSubsetLabels): log(" Tagset: %s (contains %d images)" % (tagString, len(tagsetPixIds))) if not showSubsetLabels: tagString = None subCanvas = imgUtil.paintThumbnailGrid( thumbnailStore, length, spacing, tagsetPixIds, colCount, topLabel=tagString) tagSubPanes.append(subCanvas) for toptagSet in toptagSets: tagText = toptagSet['tagText'] showSubsetLabels = toptagSet['showSubsetLabels'] imageData = toptagSet['pixelIds'] # loop through all thumbs under TAG, grouping into subsets. tagsetPixIds = [] currentTagStr = None for i, img in enumerate(imageData): tag_ids = img['tagIds'] pid = img['pid'] tagString = ", ".join([tagNames[tid] for tid in tag_ids]) if tagString == "": tagString = "Not Tagged" # Keep grouping thumbs under similar tag set (if not on the # last loop) if tagString == currentTagStr or currentTagStr is None: tagsetPixIds.append(pid) else: # Process thumbs added so far makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels) # reset for next tagset tagsetPixIds = [pid] currentTagStr = tagString makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels) maxWidth = max([c.size[0] for c in tagSubPanes]) totalHeight = sum([c.size[1] for c in tagSubPanes]) # paste them into a single canvas for each Tag leftSpacer = spacing + maxTagNameWidth + 2*spacing # Draw vertical line to right size = (leftSpacer + maxWidth, totalHeight) tagCanvas = Image.new(mode, size, WHITE) pX = leftSpacer pY = 0 for pane in tagSubPanes: imgUtil.pasteImage(pane, tagCanvas, pX, pY) pY += pane.size[1] if tagText is not None: draw = ImageDraw.Draw(tagCanvas) tt_w, tt_h = font.getsize(tagText) h_offset = (totalHeight - tt_h)/2 draw.text((spacing, h_offset), tagText, font=font, fill=(50, 50, 50)) # draw vertical line draw.line((leftSpacer-spacing, 0, leftSpacer - spacing, totalHeight), fill=(0, 0, 0)) tagPanes.append(tagCanvas) tagSubPanes = [] else: leftSpacer = spacing pixelIds = [] for imageId in dsImageIds: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) figCanvas = imgUtil.paintThumbnailGrid( thumbnailStore, length, spacing, pixelIds, colCount) tagPanes.append(figCanvas) # paste them into a single canvas tagsetSpacer = length / 3 maxWidth = max([c.size[0] for c in tagPanes]) totalHeight = totalHeight + sum([c.size[1]+tagsetSpacer for c in tagPanes]) - tagsetSpacer size = (maxWidth, totalHeight) fullCanvas = Image.new(mode, size, WHITE) pX = 0 pY = topSpacer for pane in tagPanes: imgUtil.pasteImage(pane, fullCanvas, pX, pY) pY += pane.size[1] + tagsetSpacer # create dates for the image timestamps. If dates are not the same, show # first - last. # firstdate = timestampMin # lastdate = timestampMax # figureDate = str(firstdate) # if firstdate != lastdate: # figureDate = "%s - %s" % (firstdate, lastdate) draw = ImageDraw.Draw(fullCanvas) # dateWidth = draw.textsize(figureDate, font=font)[0] # titleWidth = draw.textsize(title, font=font)[0] dateY = spacing # dateX = fullCanvas.size[0] - spacing - dateWidth draw.text((leftSpacer, dateY), title, font=font, fill=(0, 0, 0)) # title # Don't show dates: see # https://github.com/openmicroscopy/openmicroscopy/pull/1002 # if (leftSpacer+titleWidth) < dateX: # if there's enough space... # draw.text((dateX, dateY), figureDate, font=font, fill=(0,0,0)) # add date return fullCanvas
def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged=False, colCount=10, length=100): """ Paints and returns a canvas of thumbnails from images, laid out in a set number of columns. Title and date-range of the images is printed above the thumbnails, to the left and right, respectively. @param conn: Blitz connection @param imageIds: Image IDs @param title: title to display at top of figure. String @param tagIds: Optional to sort thumbnails by tag. [long] @param colCount: Max number of columns to lay out thumbnails @param length: Length of longest side of thumbnails """ mode = "RGB" figCanvas = None spacing = length / 40 + 2 thumbnailStore = conn.createThumbnailStore( ) # returns omero.api.ThumbnailStorePrx metadataService = conn.getMetadataService() if len(images) == 0: return None timestampMin = images[0].getDate() # datetime timestampMax = timestampMin dsImageIds = [] imagePixelMap = {} imageNames = {} # sort the images by name images.sort(key=lambda x: (x.getName().lower())) for image in images: imageId = image.getId() pixelId = image.getPrimaryPixels().getId() name = image.getName() dsImageIds.append(imageId) # make a list of image-IDs imagePixelMap[imageId] = pixelId # and a map of image-ID: pixel-ID imageNames[imageId] = name timestampMin = min(timestampMin, image.getDate()) timestampMax = max(timestampMax, image.getDate()) # set-up fonts fontsize = length / 7 + 5 font = imgUtil.getFont(fontsize) textHeight = font.getsize("Textq")[1] topSpacer = spacing + textHeight leftSpacer = spacing + textHeight tagPanes = [] maxWidth = 0 totalHeight = topSpacer # if we have a list of tags, then sort images by tag if tagIds: log(" Sorting images by tags") tagNames = {} taggedImages = {} # a map of tagId: list-of-image-Ids for tagId in tagIds: taggedImages[tagId] = [] # look for images that have a tag types = ["ome.model.annotations.TagAnnotation"] annotations = metadataService.loadAnnotations("Image", dsImageIds, types, None, None) #filter images by annotation... for imageId, tags in annotations.items(): for tag in tags: tagId = tag.getId().getValue() if tagId in tagIds: # if image has multiple tags, it will be display more than once taggedImages[tagId].append( imageId) # add the image id to the appropriate list if imageId in dsImageIds: dsImageIds.remove( imageId) # remember which we've picked already if tagId not in tagNames.keys(): tagNames[tagId] = tag.getTextValue().getValue( ) # make a dict of tag-names # if we want to show remaining images in dataset (not picked by tag)... if showUntagged: tagIds.append("noTag") taggedImages["noTag"] = [untaggedId for untaggedId in dsImageIds] tagNames["noTag"] = "Untagged" # print results and convert image-id to pixel-id # make a canvas for each tag for tagId in tagIds: if tagId not in tagNames.keys(): # no images with this tag continue leftLabel = tagNames[tagId] log(" Tag: %s (contains %d images)" % (leftLabel, len(taggedImages[tagId]))) pixelIds = [] for imageId in taggedImages[tagId]: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) print 'pixelIds', pixelIds tagCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount, leftLabel=leftLabel) tagPanes.append(tagCanvas) maxWidth = max(maxWidth, tagCanvas.size[0]) totalHeight += tagCanvas.size[1] else: leftSpacer = spacing pixelIds = [] for imageId in dsImageIds: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) figCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount) tagPanes.append(figCanvas) maxWidth = max(maxWidth, figCanvas.size[0]) totalHeight += figCanvas.size[1] # paste them into a single canvas size = (maxWidth, totalHeight) fullCanvas = Image.new(mode, size, WHITE) pX = 0 pY = topSpacer for pane in tagPanes: imgUtil.pasteImage(pane, fullCanvas, pX, pY) pY += pane.size[1] # create dates for the image timestamps. If dates are not the same, show first - last. firstdate = timestampMin lastdate = timestampMax figureDate = str(firstdate) if firstdate != lastdate: figureDate = "%s - %s" % (firstdate, lastdate) draw = ImageDraw.Draw(fullCanvas) dateWidth = draw.textsize(figureDate, font=font)[0] titleWidth = draw.textsize(title, font=font)[0] dateY = spacing dateX = fullCanvas.size[0] - spacing - dateWidth draw.text((leftSpacer, dateY), title, font=font, fill=(0, 0, 0)) # title if (leftSpacer + titleWidth) < dateX: # if there's enough space... draw.text((dateX, dateY), figureDate, font=font, fill=(0, 0, 0)) # add date return fullCanvas
def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, colCount = 10, length = 100): """ Paints and returns a canvas of thumbnails from images, laid out in a set number of columns. Title and date-range of the images is printed above the thumbnails, to the left and right, respectively. @param conn: Blitz connection @param imageIds: Image IDs @param title: title to display at top of figure. String @param tagIds: Optional to sort thumbnails by tag. [long] @param colCount: Max number of columns to lay out thumbnails @param length: Length of longest side of thumbnails """ mode = "RGB" figCanvas = None spacing = length/40 + 2 thumbnailStore = conn.createThumbnailStore() # returns omero.api.ThumbnailStorePrx metadataService = conn.getMetadataService() if len(images) == 0: return None timestampMin = images[0].getDate() # datetime timestampMax = timestampMin dsImageIds = [] imagePixelMap = {} imageNames = {} # sort the images by name images.sort(key=lambda x:(x.getName().lower())) for image in images: imageId = image.getId() pixelId = image.getPrimaryPixels().getId() name = image.getName() dsImageIds.append(imageId) # make a list of image-IDs imagePixelMap[imageId] = pixelId # and a map of image-ID: pixel-ID imageNames[imageId] = name timestampMin = min(timestampMin, image.getDate()) timestampMax = max(timestampMax, image.getDate()) # set-up fonts fontsize = length/7 + 5 font = imgUtil.getFont(fontsize) textHeight = font.getsize("Textq")[1] topSpacer = spacing + textHeight leftSpacer = spacing + textHeight tagPanes = [] maxWidth = 0 totalHeight = topSpacer # if we have a list of tags, then sort images by tag if tagIds: log(" Sorting images by tags") tagNames = {} taggedImages = {} # a map of tagId: list-of-image-Ids for tagId in tagIds: taggedImages[tagId] = [] # look for images that have a tag types = ["ome.model.annotations.TagAnnotation"] annotations = metadataService.loadAnnotations("Image", dsImageIds, types, None, None) #filter images by annotation... for imageId, tags in annotations.items(): for tag in tags: tagId = tag.getId().getValue() if tagId in tagIds: # if image has multiple tags, it will be display more than once taggedImages[tagId].append(imageId) # add the image id to the appropriate list if imageId in dsImageIds: dsImageIds.remove(imageId) # remember which we've picked already if tagId not in tagNames.keys(): tagNames[tagId] = tag.getTextValue().getValue() # make a dict of tag-names # if we want to show remaining images in dataset (not picked by tag)... if showUntagged: tagIds.append("noTag") taggedImages["noTag"] = [untaggedId for untaggedId in dsImageIds] tagNames["noTag"] = "Untagged" # print results and convert image-id to pixel-id # make a canvas for each tag for tagId in tagIds: if tagId not in tagNames.keys(): # no images with this tag continue leftLabel = tagNames[tagId] log(" Tag: %s (contains %d images)" % (leftLabel, len(taggedImages[tagId]))) pixelIds = [] for imageId in taggedImages[tagId]: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) print 'pixelIds', pixelIds tagCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount, leftLabel=leftLabel) tagPanes.append(tagCanvas) maxWidth = max(maxWidth, tagCanvas.size[0]) totalHeight += tagCanvas.size[1] else: leftSpacer = spacing pixelIds = [] for imageId in dsImageIds: log(" Name: %s ID: %d" % (imageNames[imageId], imageId)) pixelIds.append(imagePixelMap[imageId]) figCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount) tagPanes.append(figCanvas) maxWidth = max(maxWidth, figCanvas.size[0]) totalHeight += figCanvas.size[1] # paste them into a single canvas size = (maxWidth, totalHeight) fullCanvas = Image.new(mode, size, WHITE) pX = 0 pY = topSpacer for pane in tagPanes: imgUtil.pasteImage(pane, fullCanvas, pX, pY) pY += pane.size[1] # create dates for the image timestamps. If dates are not the same, show first - last. firstdate = timestampMin lastdate = timestampMax figureDate = str(firstdate) if firstdate != lastdate: figureDate = "%s - %s" % (firstdate, lastdate) draw = ImageDraw.Draw(fullCanvas) dateWidth = draw.textsize(figureDate, font=font) [0] titleWidth = draw.textsize(title, font=font) [0] dateY = spacing dateX = fullCanvas.size[0] - spacing - dateWidth draw.text((leftSpacer, dateY), title, font=font, fill=(0,0,0)) # title if (leftSpacer+titleWidth) < dateX: # if there's enough space... draw.text((dateX, dateY), figureDate, font=font, fill=(0,0,0)) # add date return fullCanvas