6

I have no experience with python, but the owner of this script is not responding.

When I drag my photos over this script, to create a montage, it ends up cutting off half of the last photo on the right side edge.

Being 4 pictures wide,

1   2   3   4

5   6   7   8

Pictures 4 and 8 usually get halved. The space is there for the pictures (its blank though)

I was wondering what would be causing this.

I have thought it is possible that it was cropping, but its almost like the half of the picture isn't imported or detected.

Well, you drag selected photos over the script , it outputs something like this http://i.imgur.com/PzNylbV.png

So you can take a bunch of photos or screenshots, and combine them into one single file, easily instead of adding each photo individually.

Size of each photo is roughly 500x250 at max.

enter image description here

EDIT: Here is the upload of the preview, as you can see the images have the slots, but they are "disappearing" if that makes sense.

EDIT2: This script has worked at one time, I haven't edited it or anything. It had worked on a ~70 screenshot montage. No errors or anything. Is there something that my computer could be doing to disrupt the importing of the images?

#!/usr/bin/env python
import os
import sys
from time import strftime
import Image
import ImageDraw
import ImageFont

# parameters
row_size = 4
margin = 3

def generate_montage(filenames):
    images = [Image.open(filename) for filename in filenames]

    width = 0
    height = 0
    i = 0
    sum_x = max_y = 0 
    width = max(image.size[1]+margin for image in images)*row_size
    height = sum(image.size[0]+margin for image in images)

    montage = Image.new(mode='RGBA', size=(width, height), color=(0,0,0,0))
    try:
        image_font = ImageFont.truetype('font/Helvetica.ttf', 18)
    except:
        try:
            image_font = ImageFont.load('font/Helvetica-18.pil')
        except:
            image_font = ImageFont.load_default()
    draw = ImageDraw.Draw(montage)
    offset_x = offset_y = 0

    i = 0
    max_y = 0
    max_x = 0
    offset_x = 0
    for image in images:
        montage.paste(image, (offset_x, offset_y))

        text_coords = offset_x + image.size[0] - 45, offset_y + 120
        draw.text(text_coords, '#{0}'.format(i+1), font=image_font)

        max_x = max(max_x, offset_x+image.size[0])
        if i % row_size == row_size-1: 
            offset_y += max_y+margin
            max_y = 0
            offset_x = 0
        else:
            offset_x += image.size[0]+margin
            max_y = max(max_y, image.size[1])

        i += 1

    if i % row_size:
        offset_y += max_y

    filename = strftime("Montage %Y-%m-%d at %H.%M.%S.png")
    montage = montage.crop((0, 0, max_x, offset_y))
    montage.save(filename)

if __name__ == '__main__':
    old_cwd = os.getcwd()

    os.chdir(os.path.dirname(sys.argv[0]))
    try:
        if len(sys.argv) > 1:
            generate_montage(sys.argv[1:])
    finally:
        os.chdir(old_cwd)
user2565679
  • 89
  • 1
  • 2
  • 8
  • We need more information: 1) What is the stated purpose of this script? 2) What size images are you feeding into it? 3) Can you show us a screenshot of the input and the output? Without knowing what this script is supposed to do, it's hard to determine how to fix it. If you edit your question with the appropriate details, this question will move into the review queue to be re-opened. – George Stocker Jul 09 '13 at 18:18
  • Should have all the information you asked for. Not sure how else I can put it. Thanks for helping me provide what is needed. – user2565679 Jul 09 '13 at 18:37

1 Answers1

7

In the size calculation, you use image.size[1] for the width, but that's the height! Use image.size[0] for the width and image.size[1] for the height instead.

Also, a couple of minor stylistic notes:

  • Do you really need the script to always run from the program's directory? In any case, os.chdir(os.path.dirname(sys.argv[0])) prevents the program from being executed as ./montage.py, so you may want to use a abspath to allow the invocation from the current directory.
  • Instead of having to update the counter i, you can change the for loop to

    for i,image in enumerate(images):
    
  • The following lines have no effect, since the variables are overwritten / never used:

    width = 0
    height = 0
    i = 0
    sum_x = max_y = 0 
    

All in all, the code could look like this:

#!/usr/bin/env python
import os.path
import sys
from time import strftime
import Image

row_size = 4
margin = 3

def generate_montage(filenames, output_fn):
    images = [Image.open(filename) for filename in filenames]

    width = max(image.size[0] + margin for image in images)*row_size
    height = sum(image.size[1] + margin for image in images)
    montage = Image.new(mode='RGBA', size=(width, height), color=(0,0,0,0))

    max_x = 0
    max_y = 0
    offset_x = 0
    offset_y = 0
    for i,image in enumerate(images):
        montage.paste(image, (offset_x, offset_y))

        max_x = max(max_x, offset_x + image.size[0])
        max_y = max(max_y, offset_y + image.size[1])

        if i % row_size == row_size-1:
            offset_y = max_y + margin
            offset_x = 0
        else:
            offset_x += margin + image.size[0]

    montage = montage.crop((0, 0, max_x, max_y))
    montage.save(output_fn)

if __name__ == '__main__':
    basename = strftime("Montage %Y-%m-%d at %H.%M.%S.png")
    exedir = os.path.dirname(os.path.abspath(sys.argv[0]))
    filename = os.path.join(exedir, basename)
    generate_montage(sys.argv[1:], filename)
phihag
  • 278,196
  • 72
  • 453
  • 469
  • Thank you, i'll try the edits when I arrive home. I didn't write this, and only have little knowledge of C++ (beginner at college), so it's all a learning thing for me. I appreciate the response. I'll check back in to let you know how everything works out. – user2565679 Jul 09 '13 at 21:52
  • This did not end up working. I added another picture to the top. It seems all the measurements are correct, but the pictures seem to be "disappearing" – user2565679 Jul 10 '13 at 03:17
  • @user2565679 Can you post the result and the source images you get with the code in this answer? – phihag Jul 10 '13 at 07:05
  • With the new code, I get no result image. I can still post the 8 original pictures if you'd like. Thank you for the help. – user2565679 Jul 10 '13 at 15:49
  • Please do post the original pictures. Can you elaborate on `no result image`? Is the file 0 Bytes long? Just plain white? Note that it will be created in the current working directory. – phihag Jul 10 '13 at 18:59
  • No, no file was created when I dragged all 8 pictures over the EXE usually a resulting .png would be created in the directory of the EXE. http://imgur.com/a/hw0Aw There is a link to the album with all 8 images being used. – user2565679 Jul 10 '13 at 19:23
  • @user2565679 Well, look in your cwd for the montage. I updated the code to write the image to the exe directory. I get [this output](http://i.imgur.com/CUPLoym.png), which looks fine to me. – phihag Jul 10 '13 at 20:47
  • Looks like the program is now working perfectly. I appreciate the time you took to rework the code and stick with me. Thank you so much! My output is here (http://i.imgur.com/QaReiLe.png) Would there be a way to add a black background into the montage? – user2565679 Jul 10 '13 at 20:55
  • Excellent. If this (or any other) answer solves your problem, you can [mark it as accepted](http://meta.stackexchange.com/q/5234/141962) to indicate that it has solved your original problem. You are already using a black background, it's just fully transparent. Use `color=(0,0,0,255)` instead of `(0,0,0,0)` to make the background visible. – phihag Jul 10 '13 at 21:01
  • Alright thank you my good sir! You are awesome! I will mark as the accepted answer and appreciate your patience! Have a great day! How would I go about readding the text drawing? – user2565679 Jul 10 '13 at 21:25
  • I'm not sure what you mean. Do you want to run text recognition? In any case, that's far outside the scope of this question, so you should [ask a new one](http://stackoverflow.com/questions/ask). – phihag Jul 10 '13 at 21:40
  • Nononono, in the original script it added a #1, #2, #(i) (i being the number of pictures) to each picture pasted onto the montage. It seems that part hasn't been reestablished in the code. I tried using the original code for text but it seems to throw an error. – user2565679 Jul 10 '13 at 21:52
  • Here at stackoverflow, we try to limit questions to one topic only, so that someone else with the same problem benefits from the question and the answer as well. Since the text drawing was unrelated to the image cropping, I [removed it from the answer](http://sscce.org/#short). Since your current problem with the text is completely unrelated, just [**search for the error message**](http://stackoverflow.com/search?q=). If you cannot find it, or believe that your error is unrelated to all existing questions, [just ask a new question](http://stackoverflow.com/questions/ask). – phihag Jul 11 '13 at 06:49
  • I mean, the main idea was to keep the program working as it was before. But if its the way of this place, I guess I can make an entire new question on this same topic, and just ask how to add the number system back into it. Thanks. :D – user2565679 Jul 11 '13 at 07:06
  • Sorry, I think you misunderstood me. The new question should **not** be on the same topic. Instead, you should re-add the text code, and **post the full error message** you get. The previous code you had or the images are completely irrelevant for the new question. – phihag Jul 11 '13 at 08:11
  • I don't think they are irrelevant because they show what was previous and how it should be, then the new montage without the text drawn in. It shows how it is supposed to look, and how I can't get it to work : / – user2565679 Jul 11 '13 at 17:44
  • Stackoverflow questions are not intended to include full programs (that's what [codereview](http://codereview.stackexchange.com/) is for), but small snippets and problems. We're already pushing it with more than 20 lines of code. This is not set up to spite you: if someone else has a cropped montage, they will be able to benefit from your question and the answers. That's why stackoverflow questions get that good. And, no offense, if you don't feel comfortable coding in Python, you should really try to learn Python, pick a language you know, or hire someone who does. – phihag Jul 11 '13 at 20:50
  • I understand I didn't take it as a spiteful comment or anything I appreciate the help. I guess I just dont know how exactly the whole Stackeroverflow works yet. Thank you for your patience phihag. – user2565679 Jul 11 '13 at 21:03