I'm working with a map created using python, folium, and geojson, similar to this one.
However, instead of this image being an interactive HTML document, I would rather simply export it to png or svg.
Using the syntax:
m = folium.Map( # etc..)
m.save("filename.png")
Saves a file, but it is still HTML, rather than png. What's the correct output command to render not-to-html?
I use this:
... where m is my map object.
And 5 is the time (seconds) to render the map.
import io
from PIL import Image
img_data = m._to_png(5)
img = Image.open(io.BytesIO(img_data))
img.save('image.png')
Related
I wrote a code that takes a screenshot that I want to paste into a word document using docx. So far I have to save the image as a png file. The relevant part of my code is:
from docx import Document
import pyautogui
import docx
doc = Document()
images = []
img = pyautogui.screenshot(region = (some region))
images.append(img)
img.save(imagepath.png)
run =doc.add_picture(imagepath.png)
run
I would like to be able to add the image without saving it. Is it possible to do this using docx?
Yes, according to add_picture — Document objects — python-docx 0.8.10 documentation, add_picture can import data from a stream as well.
As per Screenshot Functions — PyAutoGUI 1.0.0 documentation, screenshot() produces a PIL/Pillow image object which can be save()'d with a BytesIO() as destination to produce a compressed image data stream in memory.
So that'll be:
import io
imdata = io.BytesIO()
img.save(imdata, format='png')
imdata.seek(0)
doc.add_picture(imdata)
del imdata # cannot reuse it for other pictures, you need a clean buffer each time
# can use .truncate(0) then .seek(0) instead but this is probably easier
I have some code below that is supposed to convert a SVG image to a PNG. It runs without errors but creates a PNG file that is blank instead of one with the same image as the original SVG. I did find that it is not an error with cairo but more one relating to rsvg, which I got here.
import cairo
import rsvg
img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480)
ctx = cairo.Context(img)
handle= rsvghandler.Handle('example.svg')
handle.render_cairo(ctx)
img.write_to_png("svg.png")
I am using Python 3.6 on Windows 10.
I can't for the life of me figure out why it isn't displaying the correct picture. Any help would be hugely appreciated.
If your goal is to convert from SVG to PNG, I would recommend using Wand, as in the following script:
from wand.api import library
import wand.color
import wand.image
with wand.image.Image() as image:
with wand.color.Color('transparent') as background_color:
library.MagickSetBackgroundColor(image.wand,
background_color.resource)
image.read(blob=NAMEOFTHEFILE.read(), format="svg")
png_image = image.make_blob("png32")
with open(NAMEOFTHENEWFILE, "wb") as out:
out.write(png_image)
How can I plot the image from a PDF file into a Pyplot figure (e.g. with plt.imshow, or inside some container I can add with ax.add_artist)?
Methods that do not work:
import matplotlib.pyplot as plt
im = plt.imread('file.pdf')
(Source: this question, where it works for PNG files.)
from PIL import Image
im = Image.open('file.pdf')
(Source: this doc, but again, it doesn't work for PDF files; the question links a library to read PDFs but the doc shows no obvious way to add them to a Pyplot figure.)
Also, this question exists, but the answers solve the problem without actually loading a PDF file.
There is a module called PyMuPDF that makes this job a lot easier.
Scraping PDF images into PIL Image
To scrape the individual images out of each page tutorials can be found here and here on how to convert them into PIL format.
If the intention is to grab an entire PDF page or pages, the page.get_pixmap() documented here, can do this.
The snippet below shows how to iterate through and grab each page of a PDF as a PIL.Image
import io
import fitz
from PIL import Image
file = 'myfile.pdf'
pdf_file = fitz.open(file)
# in case there is a need to loop through multiple PDF pages
for page_number in range(len(pdf_file)):
page = pdf_file[page_number]
rgb = page.get_pixmap()
pil_image = Image.open(io.BytesIO(rgb.tobytes()))
# display code or image manipulation here for each page #
Displaying scraped PDF Image
In either case, once there is a PIL.Image object, such as the pil_image variable above, the show() function can display it (and does so differently depending on the OS). However, if the preference is to use matplotlib.pyplot.imshow the PIL.Image must be converted to RGB first.
Snippet to display PIL.Image with pyplot.imshow
import matplotlib.pyplot as plt
plt.imshow(pil_image.convert('RGB'))
I would like to convert a PNG image to a 2 dimensional array where each array holds a list of the RGB values of that specific pixel. How could one create a program to read-in a *.png file and convert to this type of data structure?
If you have PIL installed then you can create an image with Image.open and get the colors like so:
data = [image.getpixel((x, y)) for x in range(image.width) for y in range(image.height)]
You can use the existing pygame module. Import a file into a Surface using pygame.image.load. You can then access the bit array from this using pygame.surfarray.array2d. Please see the Pygame docs for more information.
You can use wand for such basic tasks. The syntax is very easy to read unlike other ImageMagik libs. Basically you'd do something like:
from wand.image import Image
from wand.display import display
array = []
with Image(filename='yourfile.png') as img:
array.append(img.channel_images) # this is most likely wrong, but it should be something similar
It will be along those lines. Once I leave the office I will try this out.
I want to serve matplotlib generated images with django.
If the image is a static png file, the following code works great:
from django.http import HttpResponse
def static_image_view(request):
response = HttpResponse(mimetype='image/png')
with open('test.png', 'rb') as f:
response.write(f.read())
return response
However, if the image is dynamically generated:
import numpy as np
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot as plt
def dynamic_image_view(request):
response = HttpResponse(mimetype='image/png')
fig = plt.figure()
plt.plot(np.random.rand(100))
plt.savefig(response, format='png')
plt.close(fig)
return response
When accessing the url in Chrome (v36.0), the image will show up for a few seconds, then disappear and turn to the alt text. It seems that the browser doesn't know the image has already finished loading and waits until timeout. Checking with Chrome > Tools > Developer tools > Network supports this hypothesis: although the image appears after only about 1 sec, the status of the corresponding http request becomes "failed" after about 5 sec.
Note again, this strange phenomenon occurs only with the dynamically generated image, so it shouldn't be Chrome's problem (though it doesn't happen with IE or FireFox, presumably due to different rules in dealing with timeout requests).
To make it more tricky (i.e., hard to reproduce), it seems to be network speed dependent. It happens if I access the url from an IP in China, but not if via a proxy in the US (which seems to be faster visiting the host on which django is running)...
According to #HSquirrel, I tested writing the png into temporary disk file. Strangely, saving file with matplotlib didn't work,
plt.savefig('MPL.png', format='png')
with open('MPL.png', 'rb') as f:
response.write(f.read())
while saving file with PIL worked:
import io
from PIL import Image
f = io.BytesIO()
plt.savefig(f, format='png')
f.seek(0)
im = Image.open(f)
im.save('PIL.png', 'PNG')
Attempt of getting rid of temp file failed:
im.save(response, 'PNG')
However, if I generate the image data stream with PIL rather than matplotlib, temporary disk file would be unnecessary. The following code works:
from PIL import Image, ImageDraw
im = Image.new('RGBA', (256,256), (0,255,0,255))
draw = ImageDraw.Draw(im)
draw.line((100,100, 150,200), fill=128, width=3)
im.save(response, 'PNG')
Finally, savefig(response, 'jepg') has no problem at all.
Have you tried saving the image to disk and then returning that? (you can periodically clear your disk of such generated images based on their time of creation)
If that gives the same problem, it might be a problem with the way the png is generated. Than you could use some kind of image library (like PIL) to make sure all your png's are (re)generated in a way that works with all browsers.
EDIT:
I've checked the png you've linked and I've played around with it a bit, opening and saving it with different programs and with PIL. I get different binary data every time. It seems each program decides which chunks to keep and which to remove. They all encode the png image data differently as well (as far as I can see, I am by no means a specialist in this, I just looked at the binary data based on the specs).
There are a few different paths you can take:
1.The quick and dirty one:
import io
from PIL import Image
f = io.BytesIO()
plt.savefig(f, format='png')
f.seek(0)
im = Image.open(f)
tempfilename = generatetempfilename()
im.save(tempfilename, 'PNG')
with open(tempfilename, 'rb') as f:
response.write(f.read())
2.Adapt how matplotlib makes PNG files (possibly by just using PIL for
it as well). See
http://matplotlib.org/users/customizing.html#customizing-matplotlib
3.If it's an option for you, use jpeg.
4.Figure out what's wrong with the PNG generated by matplotlib and fix
it binary (I don't recommend this). You can use xxd (linux command: xxd test.png) to figure out how the files look in binary and then see how things go using the png spec: overview chunk spec