I want to set Password Protected Pages onWeasyPrint PDF Builder.
I am generated PDF using Weasyprint in Django and I want password encrypted after download PDF File.
** Here is code for generate PDF file.**
def build_pdf(request,html_content, header_html=None, footer_html=None):
def get_page_body(boxes):
for box in boxes:
if box.element_tag == "body":
return box
return get_page_body(box.all_children())
def get_page_and_body(html, css):
if html is None:
return None
html = weasyprint.HTML(
string=html,
base_url=getattr(settings, "WEASYPRINT_BASEURL", None),
url_fetcher=django_url_fetcher,
)
css += "#page { margin 0 !important; }"
document = html.render(stylesheets=[weasyprint.CSS(string=css)])
document_page = document.pages[0]
document_body = get_page_body(document_page._page_box.all_children())
return (
document_page,
document_body.copy_with_children(document_body.all_children()),
)
def preprocess_html(html, context):
for key, value in context.items():
html = html.replace(f"{{{{ {key} }}}}", str(value))
return html
document = weasyprint.HTML(
string=html_content,
base_url=request.build_absolute_uri(),
# base_url=getattr(settings, "WEASYPRINT_BASEURL", None),
url_fetcher=django_url_fetcher,
).render()
return document.write_pdf()
can anyone help me?
Related
I've created an angular component (product) on which a user is able to change an image (product's image).
html:
<img [attr.id]="_product.id" [attr.src]="_product.thumbnail_url"/>
When the image is chosen by the user from a custom file picker component on a modal form. The following method is called to reload the image in the parent product component.
The imageBinary here is a base64 blob binary image returned from a python FLASK REST API endpoint which is connected to a mysql database.
reloadProductImage(new_image_id):void{
let newUrl:SafeUrl;
let urlStr:string;
this.productservice.getImage(new_image_id).subscribe((filedata) =>{
let imageBinary = filedata.thumbnail;
urlStr = 'data:image/jpeg;base64,' + imageBinary + '?'+Date.now();
newUrl = this.domSanitizer.bypassSecurityTrustUrl(urlStr);
this.form.patchValue({image_id: new_image_id});
this._product.thumbnail_url = newUrl;
this._product.image_id = new_image_id;
I've found many examples how to force the browser to a reload on a regular src url by appending a timestamp to the url. However, these examples do not seem to apply to a blob stored in a saferurl.
inspect image element
<img _ngcontent-snv-c187="" id="146914e3-6e0a-409f-8046-ff04580f6242" src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgA+++very+long+blob+++vBzu3ZFwwAAAABJRU5ErkJggg==?1619156455998">
Console Error message
Failed to load resource: net::ERR_INVALID_URL
Failed attempts
I've tried:
newUrl = 'data:image/jpeg;base64,' + imageBinary + '?'+ Date.now();
and
newUrl = 'data:image/jpeg;base64,' + imageBinary + '?datetime='+ Date.now();
Background info
For illustration purposes, I'll post my Angular and Python code here (methods in a Flask SQLAlchemy DB Model) which post an image file to a Flask REST API, generate the thumbnail from the base64 image and return it to Angular. Note: the get function is called in a GET request. The Create function is called in a POST request.
Angular FileUpload component:
import { HttpClient } from '#angular/common/http';
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import {NotificationService} from '../..//notification/notification.service';
#Component({
selector: 'fileupload-form',
template: `
<p>
Productfoto toevoegen
</p>
<input type="file" (change)="onFileSelected($event)">
<button type="button" (click)="onUpload()">Upload</button>
`,
styles: [
]
})
export class FileuploadComponent implements OnInit {
selectedFile: File = null;
#Output()
fileSubmitted = new EventEmitter();
constructor(private http: HttpClient,
private notificationService: NotificationService,
) { }
onFileSelected(event){
this.selectedFile = <File>event.target.files[0];
}
onUpload(){
const fd = new FormData();
fd.append('inputFile', this.selectedFile , this.selectedFile.name);
this.http.post(['/offerte/api/files','upload'].join('/'),fd)
.subscribe(res => {
console.log(res);
this.notificationService.success(`Bestand ${this.selectedFile.name} is opgeslagen.`);
this.fileSubmitted.emit(res);
})
}
ngOnInit(): void {
}
}
Python Flask Endpoints:
Imports
import logging
from io import BytesIO
from flask import request, send_file
from flask_restx import Resource
from api.serializers import fileobject, page_of_files
from api.parsers import pagination_arguments
from api.restplus import api
from database.models import File
from flask_jwt_extended import jwt_required, get_jwt_identity
logger = logging.getLogger()
ns_files = api.namespace('files', description='Operations related to file management')
POST
#ns_files.route('/upload')
class Upload(Resource):
#api.doc(security='jwt')
#jwt_required
def post(self):
'''Upload a new file, returns id of new file'''
inputFile = request.files['inputFile']
logger.info('create new file %s', request.json)
current_user = get_jwt_identity()
return File.create(inputFile, current_user)
GET
#ns_files.route('/<string:file_id>')
#api.response(404, 'file not found')
class Details(Resource):
#api.marshal_with(fileobject)
def get(self, file_id):
'''Download a new file from the db (binary storage)'''
logger.info('loading file %s')
current_user = get_jwt_identity()
returnedFile = File.get(file_id)
return returnedFile
Python FLASK REST API functions
from PIL import Image
import magic
from base64 import b64encode
import io
accepted_mime_types = {'jpe':'image/jpeg','jpeg':'image/pjpeg','png':'image/png'}
def get(id):
return Product.query.filter(Product.id == id).one()
def create(inputFile, current_user):
filename = inputFile.filename
file_obj = File(
filename = filename,
extension = '.jpg',
folderpath = 'folderpath',
databinary = inputFile.read(),
category = 'default',
description = 'beschrijving...',
original_filename = filename,
created_by = current_user,
modified_by= current_user)
MAX_SIZE = (150, 150)
thumbnailFile, mimetype = File.getThumbnail(inputFile, MAX_SIZE)
if not thumbnailFile is None:
output = io.BytesIO()
thumbnailFile.save(output, format='PNG')
hex_data = output.getvalue()
file_obj.thumbnail = hex_data
else:
raise NameError(mimetype)
db.session.add(file_obj)
db.session.commit()
return str(file_obj.id)
def mimetype(file_obj):
return magic.from_buffer(file_obj.read(2048), mime=True)
def getThumbnail(file_obj, size):
file_obj.seek(0)
real_mime_type = magic.from_buffer(file_obj.read(2048), mime=True)
if (real_mime_type in accepted_mime_types.values()):
thumbnailImage = Image.open(file_obj)
thumbnailImage.thumbnail(size)
return thumbnailImage, real_mime_type
else:
raise NameError(real_mime_type)
I am trying to upload a file to a DMS via REST API. Each time I upload the file to DMS, an unique doc_id is generated which needs to be saved in DB.
I am trying out the following code for the first part i.e. upload.
def upload_sotr(filepath:str,file_name:str):
upload_url = 'dms_url_path'
f = open(os.path.join(filepath,file_name),'rb')
files = {"file":(os.path.join(filepath,file_name),f)}
resp = requests.post(url=url,files=files)
if resp.status_code==201:
print('Success!!')
##Want to get the doc_id as shown below and return the same
return 'Success!!'
else:
strg='Failure'
return strg
However, I am not able to capture the doc_id string from upload_url post uploading the doc. Typically, doc_id is returned as
{
doc_type: 'image',
doc_id: 'AAD3456Q77'
}
As indicated in the code, what trick I should do post print('Success!!') so that I get the doc_id?
Ok, I found the trick!!
I should use
data = resp.json()
doc_id = data['doc_id''
return doc_id
So the complete code would be:
def upload_sotr(filepath:str,file_name:str):
upload_url = 'dms_url_path'
f = open(os.path.join(filepath,file_name),'rb')
files = {"file":(os.path.join(filepath,file_name),f)}
resp = requests.post(url=url,files=files)
if resp.status_code==201:
data = resp.json()
doc_id = data['doc_id']
return doc_id
else:
strg='Failure'
return strg
I tried using
GET https://graph.microsoft.com/v1.0/me/photo/$value to get the user's image/photo but it only returns an HTTP 200 status code. How can I get the binary data?
I've also tried using the content.property as suggested in a similar post but get a .format is not an attribute of the dict.
#app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
photo = requests.get(app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']})
print(photo.status_code)
return photo
Gets a profile photo, and optionally saves a local copy. Returns a tuple of the raw photo data, HTTP status code, content type, and saved filename. Refer to this sample.
def profile_photo(session, *, user_id='me', save_as=None):
"""Get profile photo, and optionally save a local copy.
session = requests.Session() instance with Graph access token
user_id = Graph id value for the user, or 'me' (default) for current user
save_as = optional filename to save the photo locally. Should not include an
extension - the extension is determined by photo's content type.
Returns a tuple of the photo (raw data), HTTP status code, content type, saved filename.
"""
endpoint = 'me/photo/$value' if user_id == 'me' else f'users/{user_id}/$value'
photo_response = session.get(api_endpoint(endpoint),
stream=True)
photo_status_code = photo_response.status_code
if photo_response.ok:
photo = photo_response.raw.read()
# note we remove /$value from endpoint to get metadata endpoint
metadata_response = session.get(api_endpoint(endpoint[:-7]))
content_type = metadata_response.json().get('#odata.mediaContentType', '')
else:
photo = ''
content_type = ''
if photo and save_as:
extension = content_type.split('/')[1]
filename = save_as + '.' + extension
with open(filename, 'wb') as fhandle:
fhandle.write(photo)
else:
filename = ''
return (photo, photo_status_code, content_type, filename)
Alternate approach, based on the original question's code, if you want to display the resulting image on a web page.
from base64 import b64encode
#app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
response = requests.get(
app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']}
)
content_type = response.raw.getheader('Content-Type')
return render_template('index.html',
photo_data=b64encode(response.content),
photo_content_type=content_type)
Then in the index.html template you can display the photo like so:
<html>
<body>
<img src="data:{{ photo_content_type }};base64,{{ photo_data }}" />
</body>
</html>
Call Api: -
Axios.get('https://graph.microsoft.com/v1.0/me/photo/$value', {
headers: { 'Authorization': 'Bearer '+AccessToken },
responseType: 'blob'
}).then(o => {
const url = window.URL || window.webkitURL;
const blobUrl = url.createObjectURL(o.data);
self.setState({ imageUrl: blobUrl });
})
JSX: -
<img alt="image" src={this.state.imageUrl} />
Here is what worked for me:
from base64 import b64encode
token = _get_token_from_cache(app_config.graphSCOPE)
aadPhotoURI = "https://graph.microsoft.com/v1.0/me/photo/$value"
response = requests.get(aadPhotoURI, headers={'Authorization': 'Bearer ' +
token['access_token']},)
content_type = response.raw.getheader('Content-Type')
return render_template(
'usersettings.html',
photo_data = b64encode(response.content).decode(),
photo_content_type = content_type)
then in the .html page added:
<img class="account-img" alt="" src="data:{{ photo_content_type }};base64,{{ photo_data }}"/>
CSS for account-img:
.account-img {
width: 40px;
float: right;
border-radius: 50%;
}
I have a list of strings where each element is a line of LaTex.
Using flask, how can I generate the pdf to be return on a request?
For example:
document = []
def add( toAdd ):
global document
document.append( toAdd )
def begin(item):
return "\\begin{"+str(item)+"}"
def end(item):
return "\\end{"+str(item)+"}"
#route('/pdf')
def populate_document( protocol, document ):
TITLE = "title"
AUTHOR = "author"
HEADER = "\\documentclass[12pt]{article}"
ENUMERATE = "enumerate"
DOCUMENT = "document"
STEPS = "steps"
steps = protocol[STEPS]
# KEEP AT TOP
add( HEADER )
# KEEP AT TOP
add( cmd( TITLE, protocol[TITLE] ) )
add( cmd( AUTHOR, protocol[AUTHOR] ) )
add( begin( DOCUMENT ) )
add( cmd( "section*", protocol[TITLE] ) )
add( end( ENUMERATE ) )
add( end( DOCUMENT ) )
### HOW TO COMPILE `document` and RETURN AS PDF?
I'm happy to clarify further if needed.
Thanks in advance.
The key package to making this work is latex. With it, you can do something like this (extracted from a working demo):
from flask import Flask
from jinja2 import FileSystemLoader
from latex import build_pdf
from latex.jinja2 import make_env
app = Flask(__name__)
env = make_env(loader=FileSystemLoader('templates'))
#app.route('/')
def home():
latex_template = env.get_template('example.latex')
pdf = build_pdf(template.render(text='Hello World'))
return bytes(pdf), 200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'inline; filename="example.pdf"'}
Where example.latex is from the templates folder. Converting this to take LaTex from a string is left as an exercise.
This works O.K. as a proof-of-concept on small files.
def pdf_invoice(request, id=None):
# some code
return render_to_pdf(
'voucher_pdf/voucher_pdf.html',
{
'pagesize': page_size,
'title': title,
'init_data': init_data,
}
)
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.CreatePDF(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
The pdf print options get populated when I call the pdf_invoice function through url. but I need auto print dialog option.. Is there any solution. If the question is unclear do let me know.
I would suggest something, maybe you can do this "request.get_full_path()" for pdf_invoice's url.