3

I have a stored picture on my computer. I open it using the Python Image module. Then I crop this image into several pieces using this module. To conclude, I would like to upload the image via a POST request on a website.

Because that small images are PIL object, I converted each of them into StringIO to be able to send the form without having to save them on my PC.

Unfortunately, I encounter an error, whereas if the images are physically stored on my PC, there is no problem. I do not understand why.

You can visit the website here: http://www.noelshack.com/api.php This is a very basic API that returns the link to the uploaded picture. In my case, the problem is that returns nothing, at the end of the second image (no problem for the first).


Here is the programming code to crop the image into 100 pieces.

import requests
import Image
import StringIO
import os

image = Image.open("test.jpg")
width, height = image.size

images = []

for i in range(10):
    for j in range(10):
        crop = image.crop((i * 10, j * 10, (i + 1) * 10, (j + 1) * 10))
        images.append(crop)

The function to upload an image:

def upload(my_file):
    api_url = 'http://www.noelshack.com/api.php'
    r = requests.post(api_url, files={'fichier': my_file})

    if not 'www.noelshack.com' in r.text:
        raise Exception(r.text)

    return r.text

Now we have two possibilities. The first is to save each of the 100 images on disk and upload them.

if not os.path.exists("directory"):
    os.makedirs("directory")

i = 0
for img in images:
    img.save("directory/" + str(i) + ".jpg")
    i += 1

for file in os.listdir("directory"):
    with open("directory/" + file, "rb") as f:
        print upload(f)

It works like a charm, but it is not very convenient. So, I thought to use StringIO.

for img in images:
    my_file = StringIO.StringIO()
    img.save(my_file, "JPEG")
    print upload(my_file.getvalue())
    # my_file.close() -> Does not change anything

The first link is printed, but the function raise the exception then.

I think the problem lies in the img.save(), because the same kind of for loop was not working to save to disk and then upload. In addition, if you add a time.sleep(1) between the uploads, it seems to work.

Any help would be welcome please, because I'm really stuck.

Delgan
  • 18,571
  • 11
  • 90
  • 141
  • In the first, physical file case, you're passing `upload()` an opened image `file` object and in the second, `StringIO` case, you're passing it the data content of an image file. – martineau Jun 16 '14 at 16:29
  • @martineau What should I do? And why the second case works for one or two images, and then raise an exception? – Delgan Jun 16 '14 at 16:36
  • It may work if you just pass it the `StringIO` object (named `my_file`) because the former mostly behave like regular `file` objects. – martineau Jun 16 '14 at 16:42
  • @martineau Unfortunately, I already tried and it fails. But it is worst, because even the first requests does not work. – Delgan Jun 16 '14 at 16:54
  • Perhaps you need to rewind the virtual file with a `my_file.seek(0)` before passing it to `upload()`. – martineau Jun 16 '14 at 17:15
  • @martineau Tried too, it did not work. It is strange that adding `time.sleep(1)` "solves" the issue, I can not explain it. – Delgan Jun 16 '14 at 17:25
  • The noelshack API must require an actual file system object. – martineau Jun 16 '14 at 20:18

1 Answers1

2

my_file.getvalue() returns a string. What you need is a file-like object, which my_file already is. And file like objects have a cursor, so to speak, which says where to read from or write to. So, if you do my_file.seek(0) before the upload, it should get fixed.

modify the code to:

for img in images:
    my_file = StringIO.StringIO()
    img.save(my_file, "JPEG")
    my_file.seek(0)
    print upload(my_file)
sudP
  • 171
  • 3
  • 11