I am trying to create a label with QR code and with some text and save the label as PDF. I am unable to alter the size of the label to 9 X 3 cms. How do I do that?
What I tried so far?
import requests
import shutil
zpl = """
^XA
^FO50,60^A0,15^FDID 123456^FS
^FO100,100
^BQN,2,5
^FDQA,QR_CODE^FS
^FO120,270^A0,15^FDTest here^FS
^FO150,290^A0,15^FDSome more text here^FS
^FO25,25^GB500,350,2^FS
^XZ
"""
# adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
url = 'http://api.labelary.com/v1/printers/8dpmm/labels/3.5x10/0/'
files = {'file' : zpl}
headers = {'Accept' : 'application/pdf'} # omit this line to get PNG images back
response = requests.post(url, headers = headers, files = files, stream = True)
if response.status_code == 200:
response.raw.decode_content = True
with open('label.pdf', 'wb') as out_file: # change file name for PNG images
shutil.copyfileobj(response.raw, out_file)
else:
print('Error: ' + response.text)
You need to find the right combination of basically 4 parameters, which are:
The size of your graphical elements in dots, for example the texts and the bounding box.
The density (or resolution) of your label, which should match your printer's.
The size of the (physical) label.
The size of the PDF page.
Here's an example of how to control each one of these.
Only the relevant lines are shown:
# The values in your ZPL set the sizes in dots:
zpl = """
^XA
^FO50,60^A0,15^FDID 123456^FS
... (your full ZPL here) ...
"""
# Then:
# 1. Set the density (24dpmm) and the size of the label in inches (2.8x2):
url = 'http://api.labelary.com/v1/printers/24dpmm/labels/2.8x2/0/'
# 2. Set the PDF page size, here A4:
headers = {'Accept' : 'application/pdf', 'X-Page-Size':'A4'}
Note: if the PDF page size is not set in the header, then it will match the physical label size.
Related
My goal is to add a text overlay to a series of clips at a given timestamp and then concatenate them all to make a single video. Currently, the video that is output as 'movie.mp4' only plays the first text overlay and none of the others.
I have looked at other posts (here) to try to recreate this but I have been unsuccessful.
In the comments for create_final_video(clips, texts, totalDuration) you can see what else I have tried in order to concatenate the clips. This method also requires removing clip = CompositeVideoClip([clip, text]).set_duration(float(clip_data['clipDuration'])). This second version concatenates the videos but the text overlay doesn't have its position set to the bottom left but to the top right instead, and the text overlays play back to back after each other rather than at the end of each clip.
Below is the first version:
import os
import json
from moviepy.editor import VideoFileClip, CompositeVideoClip, concatenate_videoclips, vfx, TextClip
# reads clip valid clip names from file
def read_valid_clips_list():
# gets clip data
def get_clip_data(filename):
def create_clips(clip_list):
clips = []
texts = []
currentDuration = 0
for filename in clip_list:
filename = filename.strip()
clip_data = get_clip_data(filename)
video_file_path = os.path.join(PATH_TO_RAW_CLIPS, filename)
# create video clip
clip = VideoFileClip(video_file_path)
clip = clip.set_duration(float(clip_data['clipDuration']))
clip = clip.fx(vfx.fadein, .1).fx(vfx.fadeout, .15)
# create text overlay for clip
text = create_text_overlay(clip_data, currentDuration)
# combine clip and text before concatenation
clip = CompositeVideoClip([clip, text]).set_duration(float(clip_data['clipDuration']))
currentDuration += float(clip_data['clipDuration'])
texts.append(text)
clips.append(clip)
return clips, texts, currentDuration
def create_text_overlay(clip_data, currentDuration):
streamerName = str(clip_data.get('streamerName'))
text_clip = TextClip(txt = streamerName, font = FONT_PATH, size = (400,0), color = 'rgb(145, 70, 255)')
tc_width, tc_height = text_clip.size
print(currentDuration)
text_clip = text_clip.set_start(currentDuration)
text_clip = text_clip.set_position(('left', 'bottom'))
text_clip = text_clip.set_duration(2.5)
text_clip = text_clip.crossfadein(0.2).crossfadeout(0.5)
return text_clip
def create_final_video(clips, texts, totalDuration):
vid_clips = concatenate_videoclips(clips, method='compose').set_duration(totalDuration)
# print(type(vid_clips))
# text_clips = concatenate_videoclips(texts).set_duration(totalDuration)
# print(type(text_clips))
# final_movie = CompositeVideoClip([vid_clips, text_clips], size=(1920,1080)).set_duration(totalDuration)
return vid_clips
def create_movie():
valid_list = read_valid_clips_list()
clips, texts, totalDuration = create_clips(valid_list)
movie = create_final_video(clips, texts, totalDuration)
return movie
movie = create_movie()
movie.write_videofile('VideoCompilation\VideoFiles\\videos\movie.mp4')
The solution was to use text_clip = text_clip.set_start(0)
I am trying to work with IMDb API. My code thus far is
import http.client
import json
import requests
conn = http.client.HTTPSConnection("imdb-api.com", 443)
payload = ''
headers = {'User-agent': 'Chrome/95.0'}
conn.request("GET", "https://imdb-api.com/en/API/MostPopularMovies/<API_Key>",headers=headers)
res = conn.getresponse()
data = res.read()
convertedDict = json.loads(data.decode("utf-8"))
imagepath = r'venv/files/image.jpeg'
req = requests.get(convertedDict['items'][0]['image'], headers=headers)
with open(imagepath, 'wb') as file:
file.write(req.content)
This allows me to download the image of the first popular movie, however, the image size is really small. This is the link that I am downloading. I know that if I get rid of everything after # the image will become a lot larger. Is there a way to edit the link such that I can drop everything after # and even edit the numbers after UX with code?
Everything I try to do with string or URL operations give's me an error
https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg
Thank you in advance
Explanation
(code example below)
Here's how to get a bigger image of the size you want. Given this URL,
https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg
There's a substring of it:
UX128_CR0,3,128,176
This has three important parts:
The first 128 resizes the image by width, keeping ratio
The second 128 controls the container width that the image appears in
176 controls the container height that the image appears in.
So, we can view the structure like this:
UX<image_width>_CR0,3,<container_width>,<container_height>
As an example, to double the image size:
UX256_CR0,3,256,352_AL_.jpg
(Click here to see: https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#.V1_UX256_CR0,3,256,352_AL.jpg
Update: Example of how you might do it in Python.
import re
resize_factor = 2 # Image size multiple
url = "https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg"
#
# resize_factor : Image size multiplier (e.g., resize_factor = 2 doubles the image size, positive integer only)
# url : full URL of the image
# return : string of the new URL
#
def getURL(resize_factor, url):
# Regex for pattern matching relevant parts of the URL
p = re.compile(".*UX([0-9]*)_CR0,([0-9]*),([0-9]*),([0-9]*).*")
match = p.search(url)
if match:
# Get the image dimensions from the URL
img_width = str(int(match.group(1)) * resize_factor)
container_width = str(int(match.group(3)) * resize_factor)
container_height = str(int (match.group(4)) * resize_factor)
# Change the image dimensions
result = re.sub(r"(.*UX)([0-9]*)(.*)", r"\g<1>"+ img_width +"\g<3>", url)
result = re.sub(r"(.*UX[0-9]*_CR0,[0-9]*,)([0-9]*)(.*)", r"\g<1>"+ img_width +"\g<3>", result)
result = re.sub(r"(.*UX[0-9]*_CR0,[0-9]*,[0-9]*,)([0-9]*)(.*)", r"\g<1>"+ container_height +"\g<3>", result)
return result
#
# Test
#
print (getURL(resize_factor,url))
Edit: Typo
I have a snippet that reads my images locally (returns binary), i.e:
image = 'car.jpg'
with open(image, 'rb') as image_file:
content = image_file.read()
I'm trying to recreate the same but with images that are hosted on the internet, I have tried with the following but I've had no luck.
from urllib.request import urlopen
from PIL import Image
import io
url = 'https://somewebsite.com/fm-01/car.jpg'
image = urlopen(url)
image_file = io.BytesIO(image.read())
im = Image.open(image_file)
im = im.tobytes()
EDIT ...
Same exact image, one on google cloud storage and the other one locally.
They have different bytes when opening them.
with open('car.jpg','rb') as image_file:
content = image_file.read()
print(len(content))
size : 234712
url = 'https://storage.googleapis.com/fm-01/car.jpg'
img = Image.open(urlopen(url))
image = img.tobytes()
print(len(image))
size : 1077600
It is simple as:
from urllib.request import urlopen
url = 'https://somewebsite.com/fm-01/car.jpg'
img = urlopen(url).read()
You have not understood the comment I made explaining exactly this under Mikhail's answer.
The 234,712 bytes is the size of the JPEG-encoded data in the disk file - it includes the image height, width, date, GPS coordinates, camera manufacturer and the all the pixels of the image DCT-compressed into a JPEG.
The 1,077,600 bytes is the size of the array you will need to create in memory to hold the uncompressed red, green and blue pixels in, say 898x400 pixels at 3 bytes (1 red, 1 green and 1 blue) per pixel.
898 * 400 * 3 = 1077600
I am using xlsxwriter 1.1.0 and Microsoft Excel 2016 I copied the example listed here (my version pasted below):
######################################################################
#
# This program shows several examples of how to set up headers and
# footers with XlsxWriter.
#
# The control characters used in the header/footer strings are:
#
# Control Category Description
# ======= ======== ===========
# &L Justification Left
# &C Center
# &R Right
#
# &P Information Page number
# &N Total number of pages
# &D Date
# &T Time
# &F File name
# &A Worksheet name
#
# &fontsize Font Font size
# &"font,style" Font name and style
# &U Single underline
# &E Double underline
# &S Strikethrough
# &X Superscript
# &Y Subscript
#
# &[Picture] Images Image placeholder
# &G Same as &[Picture]
#
# && Miscellaneous Literal ampersand &
#
# See the main XlsxWriter documentation for more information.
#
# Copyright 2013-2018, John McNamara, jmcnamara#cpan.org
#
import xlsxwriter
workbook = xlsxwriter.Workbook('E:\\headers_footers.xlsx')
preview = 'Select Print Preview to see the header and footer'
######################################################################
#
# A simple example to start
#
worksheet1 = workbook.add_worksheet('Simple')
header1 = '&CHere is some centered text.'
footer1 = '&LHere is some left aligned text.'
worksheet1.set_header(header1)
worksheet1.set_footer(footer1)
worksheet1.set_column('A:A', 50)
worksheet1.write('A1', preview)
######################################################################
#
# Insert a header image.
#
worksheet2 = workbook.add_worksheet('Image')
header2 = '&L&G'
# Adjust the page top margin to allow space for the header image.
worksheet2.set_margins(top=1.3)
worksheet2.set_header(header2, {'image_left': 'logo.png'})
worksheet2.set_column('A:A', 50)
worksheet2.write('A1', preview)
######################################################################
#
# This is an example of some of the header/footer variables.
#
worksheet3 = workbook.add_worksheet('Variables')
header3 = '&LPage &P of &N' + '&CFilename: &F' + '&RSheetname: &A'
footer3 = '&LCurrent date: &D' + '&RCurrent time: &T'
worksheet3.set_header(header3)
worksheet3.set_footer(footer3)
worksheet3.set_column('A:A', 50)
worksheet3.write('A1', preview)
worksheet3.write('A21', 'Next sheet')
worksheet3.set_h_pagebreaks([20])
######################################################################
#
# This example shows how to use more than one font
#
worksheet4 = workbook.add_worksheet('Mixed fonts')
header4 = '&C&"Courier New,Bold"Hello &"Arial,Italic"World'
footer4 = '&C&"Symbol"e&"Arial" = mc&X2'
worksheet4.set_header(header4)
worksheet4.set_footer(footer4)
worksheet4.set_column('A:A', 50)
worksheet4.write('A1', preview)
######################################################################
#
# Example of line wrapping
#
worksheet5 = workbook.add_worksheet('Word wrap')
header5 = "&CHeading 1\nHeading 2"
worksheet5.set_header(header5)
worksheet5.set_column('A:A', 50)
worksheet5.write('A1', preview)
######################################################################
#
# Example of inserting a literal ampersand &
#
worksheet6 = workbook.add_worksheet('Ampersand')
header6 = '&CCuriouser && Curiouser - Attorneys at Law'
worksheet6.set_header(header6)
worksheet6.set_column('A:A', 50)
worksheet6.write('A1', preview)
workbook.close()
On line 40, I changed the destination of the file and on line 68 I changed the name of the image; I have changed nothing apart from that. When I run the said program I don't see the images as well as the fonts. I have attached a screenshot below:
The program finished correctly without throwing any exception. Most of the other functions like set_column, insert_image etc. are working. But set_header isn't.
I don't know if any more information is required. Please feel free to demand for the same if required.
Headers and Footers in Excel don't show up in the normal view of the worksheet. As the output from the example says "Select Print Preview to see the header and footer".
In Print Preview mode the output looks like this:
Or in "Page Layout" view it looks like this:
I'm building a webapp that takes uploaded images, stores them on Amazon S3 and then stores the URL in a SQLite database. Unfortunately, EXIF tags cause images that were taken via a smartphone to appear rotated (since they are landscape images w/ EXIF orientation tags).
Currently, my environment grabs the file from the POST data, saves it to my static files folder, rotates image (if needed) with PIL, pushes to S3 and finally deletes the local copy. Here is a little of the code involved:
from PIL import Image
import boto
from boto.s3.connection import S3Connection
from boto.s3.key import Key
def fix_orientation(filename):
img = Image.open(filename)
if hasattr(img, '_getexif'):
exifdata = img._getexif()
try:
orientation = exifdata.get(274)
except:
# There was no EXIF Orientation Data
orientation = 1
else:
orientation = 1
if orientation is 1: # Horizontal (normal)
pass
elif orientation is 2: # Mirrored horizontal
img = img.transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 3: # Rotated 180
img = img.rotate(180)
elif orientation is 4: # Mirrored vertical
img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 5: # Mirrored horizontal then rotated 90 CCW
img = img.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 6: # Rotated 90 CCW
img = img.rotate(-90)
elif orientation is 7: # Mirrored horizontal then rotated 90 CW
img = img.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 8: # Rotated 90 CW
img = img.rotate(90)
#save the result and overwrite the originally uploaded image
img.save(filename)
def push_to_s3(**kwargs):
try:
conn = S3Connection(app.config["S3_KEY"], app.config["S3_SECRET"])
buckets = [bucket.name for bucket in conn.get_all_buckets()]
bucket = conn.get_bucket(app.config["S3_BUCKET"])
k = Key(bucket)
k.key = app.config["S3_UPLOAD_DIR"] + kwargs.get("filename")
k.set_contents_from_filename(kwargs.get("photo"))
k.make_public()
return k
except Exception, e:
abort(500)
Here is handling the POST data
# Retrieving Form POST Data
fi = request.files.get("file")
#print "Storing and Rotating File (if needed)"
f = photos.save(fi)
path = photos.path(f)
fix_orientation(path)
#print "Uploading to S3"
img = push_to_s3(photo=path, filename=filename)
#print "Deleting Local Version"
os.remove(path)
The above solution works on Heroku's servers, but it just seems very duct tape'd together of a solution. Is there are cleaner way to do what I'm doing. That is, take a uploaded file, rotate it from memory and then push to S3?
I'm also using Flask-Uploads to handle storage of the upload images.
For what it is worth, Pillow supports a number of other inputs than a file name - including bytearray, buffer, and file-like object. The third is most probably what you are looking for, as anything loaded out of request.files is just a FileStorage file-like object. That simplifies the load-and-transform code to:
def fix_orientation(file_like_object):
img = Image.open(filename)
# ... snip ...
data = BytesIO()
img.save(data)
return data
Since we are going to be passing around data without using the filesystem very much, we can also switch to using boto.s3.key.Key's set_contents_from_file method instead of set_contents_from_filename:
def push_to_s3(photo, filename):
# ... snip ...
k.set_contents_from_file(photo, rewind=True)
# ... etc. ...
That simplifies the resulting implementation to:
# Retrieving Form POST Data
fi = request.files.get("file")
# print "Rotating File (if needed)"
fi = fix_orientation(fi)
# print "Uploading to S3"
push_to_s3(photo=fi, filename=filename)