New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: insert_image() from a data stream #118

Closed
masters3d opened this Issue Apr 9, 2014 · 14 comments

Comments

5 participants
@masters3d

masters3d commented Apr 9, 2014

I am working with app engine and I wanted to see if there was a way to
add images (data strings? "pickled") from the data store straight in or

if there was a way to give a URL for a image instead of the local dir ( appegine limitation ?)

Alternatively I could just add all images to my root folder on app enginer but I was hoping to add images dynamically.

Thank you

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Apr 9, 2014

Owner

I can confirm that isn't currently available. I'll try add it in a future release.

John.

Owner

jmcnamara commented Apr 9, 2014

I can confirm that isn't currently available. I'll try add it in a future release.

John.

@jmcnamara jmcnamara self-assigned this May 3, 2014

@musslebot

This comment has been minimized.

Show comment
Hide comment
@musslebot

musslebot Aug 9, 2014

Currentlly in Workbook.py, line 864 this method only accepts filename, opens the file in mode read binary, then reads to extract the data:

def _get_image_properties(self, filename):
    ...
    # Open the image file and read in the data.
    fh = open(filename, "rb")
    data = fh.read()
    ...

This would allow multiple inputs:

def _get_image_properties(self, file):
    ...
    # Get image data from 
    try: # Is filename a path to image?
        # Open the image file and read in the data.
        fh = open(filename, "rb")
        data = fh.read()
        # Get the image filename without the path.
        image_name = os.path.basename(filename)
    # Is filename not a path?
    except TypeError:
        # Is filename a StringIO instance?
        if filename.__class__.__name__ == 'StringIO':
           data = filename.getvalue()
           image_name = 'img_from_memory'
        # Is filename a byte string?
        elif type(filename) is str:
            data = filename
            image_name = 'img_from_bytestring'
        else:
            raise TypeError(
                'Unknown argument (filename): {}'.format(filename)
            )
    ...

An example of inserting an image from a URL is as follows:

import requests
r = requests.get(img_url)
# As StringIO stream
img_stream = StringIO.StringIO(r.content)
wksht.insert_image(row, col, img_stream)
# As bytestring
wksht.insert_image(row, col, r.content)

musslebot commented Aug 9, 2014

Currentlly in Workbook.py, line 864 this method only accepts filename, opens the file in mode read binary, then reads to extract the data:

def _get_image_properties(self, filename):
    ...
    # Open the image file and read in the data.
    fh = open(filename, "rb")
    data = fh.read()
    ...

This would allow multiple inputs:

def _get_image_properties(self, file):
    ...
    # Get image data from 
    try: # Is filename a path to image?
        # Open the image file and read in the data.
        fh = open(filename, "rb")
        data = fh.read()
        # Get the image filename without the path.
        image_name = os.path.basename(filename)
    # Is filename not a path?
    except TypeError:
        # Is filename a StringIO instance?
        if filename.__class__.__name__ == 'StringIO':
           data = filename.getvalue()
           image_name = 'img_from_memory'
        # Is filename a byte string?
        elif type(filename) is str:
            data = filename
            image_name = 'img_from_bytestring'
        else:
            raise TypeError(
                'Unknown argument (filename): {}'.format(filename)
            )
    ...

An example of inserting an image from a URL is as follows:

import requests
r = requests.get(img_url)
# As StringIO stream
img_stream = StringIO.StringIO(r.content)
wksht.insert_image(row, col, img_stream)
# As bytestring
wksht.insert_image(row, col, r.content)
@musslebot

This comment has been minimized.

Show comment
Hide comment
@musslebot

musslebot Aug 11, 2014

This will also require additional changes to a method in packager.py, line 527, which I have done below. This is a somewhat sloppy implementation, but it works.

BEFORE

def _add_image_files(self):
    ...
    image_file = open(filename, mode='rb')
    image_data = image_file.read()
    ...
    self.filenames.append((os_filename, xml_image_name, True))
    image_file.close()

AFTER

def _add_image_files(self):
    ...
    try:
        image_file = open(filename, mode='rb')
        image_data = image_file.read()
    except:
        if image[0].__class__.__name__ == 'StringIO':
            image_data = image[0].getvalue()
        else:
            image_data = image[0]
    ...
    self.filenames.append((os_filename, xml_image_name, True))
    try:
        image_file.close()
    except:
        pass

musslebot commented Aug 11, 2014

This will also require additional changes to a method in packager.py, line 527, which I have done below. This is a somewhat sloppy implementation, but it works.

BEFORE

def _add_image_files(self):
    ...
    image_file = open(filename, mode='rb')
    image_data = image_file.read()
    ...
    self.filenames.append((os_filename, xml_image_name, True))
    image_file.close()

AFTER

def _add_image_files(self):
    ...
    try:
        image_file = open(filename, mode='rb')
        image_data = image_file.read()
    except:
        if image[0].__class__.__name__ == 'StringIO':
            image_data = image[0].getvalue()
        else:
            image_data = image[0]
    ...
    self.filenames.append((os_filename, xml_image_name, True))
    try:
        image_file.close()
    except:
        pass
@musslebot

This comment has been minimized.

Show comment
Hide comment
@musslebot

musslebot Aug 11, 2014

This is now working on my fork of XlsxWriter, branch name: image-stringbuffer
I have not tested extensively though, so use with caution.

musslebot commented Aug 11, 2014

This is now working on my fork of XlsxWriter, branch name: image-stringbuffer
I have not tested extensively though, so use with caution.

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Aug 11, 2014

Owner

Hi @wtrdrnkr,

Thanks for that. This is one of those features that is probably just easier to implement than to break down so I'll go ahead and do that.

I'll ping you when there is an update.

Owner

jmcnamara commented Aug 11, 2014

Hi @wtrdrnkr,

Thanks for that. This is one of those features that is probably just easier to implement than to break down so I'll go ahead and do that.

I'll ping you when there is an update.

@musslebot

This comment has been minimized.

Show comment
Hide comment
@musslebot

musslebot Aug 11, 2014

@jmcnamara
Awesome! Thank you!

musslebot commented Aug 11, 2014

@jmcnamara
Awesome! Thank you!

jmcnamara added a commit that referenced this issue Aug 12, 2014

@jmcnamara jmcnamara changed the title from Feature request: .insert_image with url or as data stream to Feature request: insert_image() from a data stream Aug 12, 2014

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Aug 12, 2014

Owner

@wtrdrnkr

Try out the latest code on master.

There is now an optional image_data parameter in write_image().

The image data must be in a BytesIO object and a filename is still required (by Excel). For example:

import io
import xlsxwriter

workbook = xlsxwriter.Workbook('image.xlsx')
worksheet = workbook.add_worksheet()

# The name of the file to read.
filename = 'python.png'

# Read the file into as binary data.
image_file = open(filename, 'rb')
image_data = io.BytesIO(image_file.read())
image_file.close()

# Write the image to a cell. The filename must still be specified.
worksheet.insert_image('B2', filename, {'image_data': image_data})

workbook.close()
Owner

jmcnamara commented Aug 12, 2014

@wtrdrnkr

Try out the latest code on master.

There is now an optional image_data parameter in write_image().

The image data must be in a BytesIO object and a filename is still required (by Excel). For example:

import io
import xlsxwriter

workbook = xlsxwriter.Workbook('image.xlsx')
worksheet = workbook.add_worksheet()

# The name of the file to read.
filename = 'python.png'

# Read the file into as binary data.
image_file = open(filename, 'rb')
image_data = io.BytesIO(image_file.read())
image_file.close()

# Write the image to a cell. The filename must still be specified.
worksheet.insert_image('B2', filename, {'image_data': image_data})

workbook.close()

@jmcnamara jmcnamara added the todo label Aug 12, 2014

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Aug 12, 2014

Owner

Or reading from a URL:

import io
import urllib
import xlsxwriter

workbook = xlsxwriter.Workbook('image2.xlsx')
worksheet = workbook.add_worksheet()

# The name of the file to read.
url = 'https://raw.githubusercontent.com/jmcnamara/XlsxWriter/master/examples/logo.png'

# Read the file into as binary data.
image_data = io.BytesIO(urllib.urlopen(url).read())

# Write the image to a cell. The filename must still be specified.
worksheet.insert_image('B2', url, {'image_data': image_data})

workbook.close()
Owner

jmcnamara commented Aug 12, 2014

Or reading from a URL:

import io
import urllib
import xlsxwriter

workbook = xlsxwriter.Workbook('image2.xlsx')
worksheet = workbook.add_worksheet()

# The name of the file to read.
url = 'https://raw.githubusercontent.com/jmcnamara/XlsxWriter/master/examples/logo.png'

# Read the file into as binary data.
image_data = io.BytesIO(urllib.urlopen(url).read())

# Write the image to a cell. The filename must still be specified.
worksheet.insert_image('B2', url, {'image_data': image_data})

workbook.close()

@jmcnamara jmcnamara added ready to close and removed todo labels Aug 12, 2014

@musslebot

This comment has been minimized.

Show comment
Hide comment
@musslebot

musslebot Aug 12, 2014

@jmcnamara
This is beautiful!
Thank you.

musslebot commented Aug 12, 2014

@jmcnamara
This is beautiful!
Thank you.

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Aug 12, 2014

Owner

Added in version 0.5.7 which has been release to PyPI.

See the following example in the updated docs: Inserting images from a URL or byte stream into a worksheet.

Thanks for the feature request and support.

Owner

jmcnamara commented Aug 12, 2014

Added in version 0.5.7 which has been release to PyPI.

See the following example in the updated docs: Inserting images from a URL or byte stream into a worksheet.

Thanks for the feature request and support.

@jmcnamara jmcnamara closed this Aug 12, 2014

@redarouichi

This comment has been minimized.

Show comment
Hide comment
@redarouichi

redarouichi Apr 3, 2016

Hi @jmcnamara
Thanks for your great library

for reading directly a database binary field ( in my case in odoo )

photo = item.photo # is a binary field ( image)
image_data = BytesIO(base64.b64decode(photo)) # to convert it to base64 file
worksheet.insert_image('B2', filename, {'image_data': image_data})

redarouichi commented Apr 3, 2016

Hi @jmcnamara
Thanks for your great library

for reading directly a database binary field ( in my case in odoo )

photo = item.photo # is a binary field ( image)
image_data = BytesIO(base64.b64decode(photo)) # to convert it to base64 file
worksheet.insert_image('B2', filename, {'image_data': image_data})

@jmcnamara

This comment has been minimized.

Show comment
Hide comment
@jmcnamara

jmcnamara Apr 4, 2016

Owner

@redarouichi Thanks for the tip.

Owner

jmcnamara commented Apr 4, 2016

@redarouichi Thanks for the tip.

@FelipeMedel

This comment has been minimized.

Show comment
Hide comment
@FelipeMedel

FelipeMedel Jan 25, 2018

@redarouichi Hello everyone, I have a problem with the image, I have the image saved in the database, in a base64 format, as the image can be displayed without having to download it, there is some way to show the image directly from the database?

photo = item.photo # is a binary field ( image) image_data = BytesIO(base64.b64decode(photo)) # to convert it to base64 file worksheet.insert_image('B2', filename, {'image_data': image_data})

what is the content of filename?

FelipeMedel commented Jan 25, 2018

@redarouichi Hello everyone, I have a problem with the image, I have the image saved in the database, in a base64 format, as the image can be displayed without having to download it, there is some way to show the image directly from the database?

photo = item.photo # is a binary field ( image) image_data = BytesIO(base64.b64decode(photo)) # to convert it to base64 file worksheet.insert_image('B2', filename, {'image_data': image_data})

what is the content of filename?

@masters3d

This comment has been minimized.

Show comment
Hide comment
@masters3d

masters3d Jan 25, 2018

please try stackoverflow. It’s been years since I used this library.

masters3d commented Jan 25, 2018

please try stackoverflow. It’s been years since I used this library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment