Why is this save method not resizing the image? - django-models

I am overriding the save method in order to resize the image after upload. The following code does not appear to be resizing the image, I double checked the media folder and there is only one copy of the uploaded image in it's original dimensions (900x850). Django is not throwing any errors, so I'm not sure how to troubleshoot the problem. To be clear, I am able to submit form and upload image without any problem, but the image is not resizing as I have intended below
class Mymodel(models.Model):
photo = models.ImageField(upload_to="...", blank=True)
def save(self, *args, **kwargs):
# Did we have to resize the image?
# We pop it to remove from kwargs when we pass these along
image_resized = kwargs.pop('image_resized',False)
if self.photo and image_resized:
basewidth = 300
filename = self.get_source_filename()
image = Image.open(filename)
wpercent = (basewidth/float(image.size[0]))
hsize = int((float(image.size[1])*float(wpercent)))
img = image.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
self.photo = img
# Save the updated photo, but inform when we do that we
# have resized so we don't try and do it again.
self.save(image_resized = True)
super(Mymodel, self).save(*args, **kwargs)
What am I doing wrong?

Related

Python 3.6 Image crwaling

I am crawling images from the Google image Search
I tried
1.Open the Chrome Driver with Selenium
2.Scroll down to end
3.Get image URL with BeautifulSoup and save Image
But it was a problem because the image was too small
So I found that there is an original image src
It is in the src(ends with ".jpg") of the irc_mi image class
But I do not know how to pull it out
I tried using find_all as the class name but it failed.
What should I do?
here are source codes
def Remainder_All_ImagesURLs_Google(searchText):
def scroll_page():
for i in range(7):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
sleep(3)
def click_button():
more_imgs_button_xpath = "//*[#id='smb']"
element = driver.find_element_by_xpath(more_imgs_button_xpath)
element.click()
sleep(3)
def create_soup():
html_source = driver.page_source
soup = BeautifulSoup(html_source, 'html.parser')
return soup
def find_imgs():
soup = create_soup()
imgs_urls = []
for img in soup.find_all('img'):
try:
if img['src'].startswith('http'):
imgs_urls.append(img['src'])
except:
pass
return imgs_urls
driver = webdriver.Chrome('C:/chromedriver.exe')
driver.maximize_window()
sleep(2)
searchUrl = "https://www.google.com/search?q={}&site=webhp&tbm=isch".format(searchText)
driver.get(searchUrl)
try:
scroll_page()
click_button()
scroll_page()
except:
click_button()
scroll_page()
imgs_urls = find_imgs()
driver.close()
return(imgs_urls)
def download_image(url,filename):
full_name = str(filename) + ".jpg"
urllib.request.urlretrieve(url, 'C:/Python/Picture' + full_name)
the problem is beautiful soup wont find any source or href of image since its a java-script based function which returns source(src) hence my suggestion use selenium to click image tag and wait for image src and extract it
use
element=driver.find_element_by_class_name("some_class")
element.click()
then search for image src

google app engine's ferris2.2 framework (python), uploading an image to cloud storage?

So.. This is my code for uploading an image with the Ferris2 frame work. Yay me, it works. However, see how I had to comment out gcs.open(... ? I don't want that commented out. I'd really love to just upload straight to cloud storage using that call, and not having to use anything related to blobs. What's the easiest way to accomplish this given that I'm stuck with using the AClassForm and the ferris framework?
class AClassForm(forms.model_form(AClass, exclude=('image_url') ) ):
image = FileField(u'Image File')
class AClasses(Controller):
class Meta:
Model = AClass
prefixes = ('admin',)
components = (scaffold.Scaffolding, Upload)
Form = AClassForm
admin_list = scaffold.list
admin_view = scaffold.view
admin_edit = scaffold.edit
admin_delete = scaffold.delete
def admin_add(self):
self.scaffold.ModelForm = AClassForm
self.scaffold.form_encoding = "multipart/form-data"
def before_save_callback(controller,container, item):
image = self.request.params["image"]
object_name = blobstore.parse_file_info(image).gs_object_name.split('/')[-1]
upload_settings = settings.get("upload")
url = upload_settings["url"]
bucket = upload_settings["bucket"]
#send to the cloud
#write a task to execute this?
item.image_url = url % (bucket, object_name)
#gcs_file= gcs.open("/".join(["", bucket, object_name]),
# 'w', content_type="image/jpeg",
#options={'x-goog-acl': 'public-read'} )
#gcs_file.write(item.image)#.file.encode('utf-8')) #
#gcs_file.close()
return
self.events.scaffold_before_save += before_save_callback
return scaffold.add(self)
I am not sure how Ferris works internally but you can use cloudstorage directly.
My image storage wrapper, provides resizing and returns a public URL to the upload for serving directly from storage.
import urlparse
from google.appengine.api import app_identity, blobstore, images
import cloudstorage
class ImageStorage(object):
def __init__(self, base_uri):
self.base_uri = "/{}/{}".format(app_identity.get_default_gcs_bucket_name(), base_uri.lstrip('/'))
def put(self, image, name, mime=None, width=None, height=None):
"""Puts an image into the Google Cloud Storage"""
if width or height:
image = images.resize(image, width=width or height, height=height or width)
mime = 'image/png' # resize defaults to output_encoding=PNG
options = {'x-goog-acl': 'public-read'}
with cloudstorage.open(self.make_key(name), 'w', content_type=mime, options=options) as fp:
fp.write(image)
return self.get_url(name)
def get_url(self, name):
"""Gets the url for an image from Google Cloud Storage"""
key = self.make_key(name)
# must be prefixed with /gs for the blob store to know it is from gcs
# https://cloud.google.com/appengine/docs/python/blobstore/#Python_Using_the_Blobstore_API_with_Google_Cloud_Storage
url = images.get_serving_url(blobstore.create_gs_key('/gs' + key))
# s/https/http/ if running under dev_appserver.py
# if not config.isLocal:
# parts = urlparse.urlparse(url)
# secure_parts = ('https',) + parts[1:]
# url = urlparse.urlunparse(secure_parts)
return url
def make_key(self, name):
"""Makes an item name key for Google Cloud Storage"""
return '%s/%s' % (self.base_uri, name)
Usage inside of a subclass of webapp2.RequestHandler. This stores the file with name "image" in the default bucket for your app in cloud storage at path /some/bucket/path/my-image-name.
thumb = self.request.POST["image"]
if hasattr(thumb, 'value'):
gs_base_uri = '/some/bucket/path'
image_storage = ImageStorage(gs_base_uri)
thumb_fn = 'my-image-name'
session_thumb_url = image_storage.put(image=thumb.value,
name=thumb_fn,
mime=thumb.type,
width=300, height=300)
return session_thumb_url
As I understand it, if you're using the Upload component of Ferris you can't escape the Blobstore, but the following comes pretty close. You don't have to use the Form class if you don't want to, I rarely use it myself. So imagine the following Controller:
from ferris import Controller, route
from ferris.components.upload import Upload
import cloudstorage as gcs
from google.appengine.ext import blobstore
import logging
class ImageManager(Controller):
class Meta:
components = (Upload,)
#route
def list(self):
#This just passes the upload URL to use in the form
self.context['upload_url'] = self.components.upload.generate_upload_url(uri=self.uri('image_manager:image_uploader_action'))
#route
def image_uploader_action(self):
# This gets all of the uploads passed in from the form
uploads = self.components.upload.get_uploads()
# This is the raw google cloud object reference. 'myfile' is the name of the upload field in the html form
file_gcs_obj_name = uploads['myfile'][0].cloud_storage.gs_object_name
# This is the blobstore key just for giggles
file_blobstore_key = uploads['myfile'][0].key()
# This will get rid of the preceeding junk you don't need i.e. "/gs/yadda/yadda"
clean_file_name = file_gcs_obj_name[3:]
# This is the name of the file as it was uploaded by the end-user
file_name_friendly = uploads['myfile'][0].filename
# This is the actual file, with this you can do whatever you want
the_actual_image = gcs.open(clean_file_name,'r')
# The file name by default is long and ugly, lets make a copy of the file with a more friendly name
new_filename = '/mydomain.appspot.com/'+file_name_friendly
gcs.copy2(clean_file_name,new_filename)
# We can generate a serving URL by using the blobstore API
valid_blob_reference = blobstore.create_gs_key('/gs'+new_filename)
file_serving_url = images.get_serving_url(valid_blob_reference)
logging.info('the serving url is: %s'% file_serving_url)
# delete the original image from cloud storage
gcs.delete(clean_file_name)
# Delete the original image from blobstore
blobstore.delete(file_blobstore_key)
# Close the file
the_actual_image.close()
return 'Done. go check the cloud storage browser'
Now all you need is the HTML form. You can use something like this:
{% extends "layouts/default.html" %}
{% block layout_content %}
<form name="myform" action="{{upload_url}}" method="POST" enctype="multipart/form-data">
<input type="file" name="myfile" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
</form>
{% endblock %}
Ferris is still going to place a file in the blobstore but you can delete it after you've used the cloudstorage.copy2() function. That function is fairly new so remember to update your cloudstorage package, you can download the latest copy from Google or Pypi (https://pypi.python.org/pypi/GoogleAppEngineCloudStorageClient/1.9.22.1)
Hope this helps.

Dynamic images with Image class

I'm trying to do a simple case, output an image which is saved in a db.BlobProperty. I've read all of the GAE docs but can't seem to figure this one out.
Working: renders in browser
photo = Photo.get(photo_key)
self.response.headers['Content-Type'] = 'image/png'
self.response.write( photo.image )
Failing: what I really want to do is modify the image using images
from google.appengine.api import images
photo = Photo.get(photo_key)
img = images.Image(photo.image)
# no actual processing/transforms, ruling out that as an issue
self.response.headers['Content-Type'] = 'image/png'
self.response.write( img )
I believe it's a header issue. For some reason, when I write a Image object GAE is encoding it. The working example just returns with the image/png the failing give image/png; charset=utf-8.
I'm not sure what else to do since I am explicitly setting the Content-Type header in both cases. Thanks for the help.
You can't just use the images.Image object as the source for self.response.write. You need the actual data as a string, which you get from img.execute_transforms() even if you haven't asked for any transformations.

Get url of Image in GAE (Python 2.7)

I am trying to get URL of Image(blob field of GAE):
class Product(db.Model):
name = db.StringProperty()
price = db.FloatProperty()
added = db.DateTimeProperty(auto_now_add=True)
image = db.BlobProperty(default=None)
url = images.get_serving_url(movie.image)
Handler of serve image:
def result(request):
product = Product()
product.name = "halva"
url = 'http://echealthinsurance.com/wp-content/uploads/2009/11/minnesota.jpg'
product.image = db.Blob(urlfetch.Fetch(url).content)
product.put()
template = loader.get_template("result.html")
context = RequestContext(request,
{
"result" : u"Add"})
return HttpResponse(template.render(context))
But i get except:
UnicodeDecodeError:
When try to ignore this exception(that was bug in Python 2.7) I get exception in other place.
And after that i try to encode Image to 'latin-1'('utf-8' don't work):
enc_img = movie.image.decode("latin-1")
url = images.get_serving_url(enc_img)
Result: url has a view like binary file:
"ÝêÓ9>èýÑNëCf Äàr0xã³3Ï^µ7±\íQÀ¡>.....ÕÝ£°Ëÿ"I¢¶L`ù¥ºûMþÒ¸ÿ+ÿL¢ï£ÿÙ' alt="" />"
How I get url to show dynamic image in template?
You are confusing two different things here.
If you are storing your image in a db.BlobProperty (code doesn't show you are doing this, but the Schema you have is using db.BlobProperty) this means your handler has to serve the image.
However you are using image.get_serving_url, which takes a BlobKey instance which comes from storing an Image in the BlobStore https://developers.google.com/appengine/docs/python/blobstore/blobkeyclass which is a completely different thing to what you are doing.
You will need to work out what you want to do, store an image (max size 1MB) in a BlobProperty and provide a handler that can serve the image, or upload it to the BlobStore and serve it from there
images.get_serving_url takes a BlobKey. Try:
enc_img = movie.image
url = images.get_serving_url(enc_img.key())

Grails create downloadable file on the fly

Briefly: I can make a file, save it in the file system and then make a page with a link to that file, but what if I want a page with links to many files which may not all need to be generated?
So my user clicks a link on the list page like:
<g:link action="gimmeAFile" id="${myThingieInstance.id}">${fieldValue(bean: myThingieInstance, field: "id")}</g:link>
Right now I have a controller that looks like this:
def gimmeAFile = {
def lotsaLines = []
//Do a ton of stuff that has lotsaLines.add(resultStrings) all over
def fileName = "blahblah-${dateOrSomething}.csv"
def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
lotsaLines.each{
out.println it
}
}
[fileName:fileName]
}
And then they go to gimmeAFile.gsp which has the link to actually download the file:
Download Report
How do I make a link on the list viewer that will create and download the file without dragging the user to an extra screen. NOTE: I cannot have the files pre-generated, so I need to figure out how to link to a file that isnt there yet. I'm thinking something like render() at the end of the controller. Can I make the gimmeAFile controller just give the file instead of making a page with a link to the file?
OK so to clarify this is what I finally figured out based on Kaleb's answer. Thankyou SO!!
def gimmeAFile = {
def lotsaLines = []
//Do a ton of stuff that has lotsaLines.add(resultStrings) all over
def fileName = "blahblah-${dateOrSomething}.csv"
def dumbFile = new File('web-app/tmpfiles/'+fileName).withWriter {out ->
lotsaLines.each{
out.println it
}
}
def openAgain = new File('web-app/tmpfiles/'+fileName)
response.setContentType("text/csv")
response.setHeader("Content-disposition", "filename=${fileName}")
response.outputStream << openAgain.getBytes()
response.outputStream.flush()
return
}
You can create a view that just gets the bytes of the file and writes out to the response:
response.contentType = 'image/jpeg' // or whatever content type your resources are
response.outputStream << file.getBytes()
response.outputStream.flush()
Is that what you're trying to do?
Another option which is a bit nicer, you can just render the file, straight from your controller's action:
render(file: theFile, contentType: 'your/contentType')
See also: http://grails.org/doc/latest/ref/Controllers/render.html
(I've found that if you add the fileName option, it prompts the user to download the file.)

Resources