Gimp Python plugin loading image disables undo history - python

I have a set of images that I am trying to process manually, so I wrote a simple plug-in to try and help make it a little less painful. The images are numbered sequentially. So when I finish working on one image I can hit a key combo and it saves the file with the correct name and opens the next one in the list. This all works fine.
The issue I have with the plug-in is that for newly opened images the undo-redo history does not work. I am not sure if I am not loading it in correctly, or if there is something that I have to set for the undo history to be enabled. When the new image is loaded the undo history is completely blank, and when I make changes to the image nothing new is added to it as I work on the file. This makes it difficult to do anything as a mistake means starting over. I am using the latest gimp version 2.8.18.
I am a complete newb at writing gimp plug-ins and built this from web examples, so any help to figure out why this is happening would greatly appreciated. Here is the code I wrote for the plug-in:
#!/usr/bin/python
from gimpfu import *
import os.path
def get_next_filename(filepath):
#Now figure out the next image to load
old_file = filepath.replace("\\", "/")
file_info = old_file.split('/')
#print file_info
name = file_info[len(file_info) - 1].replace(".JPG", "").replace("P", "")
print name
next_num = int(name) + 1
new_name = "P" + str(next_num) + ".JPG"
print new_name
file_info[len(file_info) - 1] = new_name
s = "/"
new_path = s.join(file_info)
print new_path
return new_path
def plugin_main(timg, tdrawable):
print "orig filename: ", timg.filename
new_filename = timg.filename.replace(".JPG", "_colored.JPG")
print "new filename: ", new_filename
layer = pdb.gimp_image_merge_visible_layers(timg, CLIP_TO_IMAGE)
if not os.path.isfile(new_filename):
pdb.gimp_file_save(timg, layer, new_filename, '?')
else:
pdb.gimp_message ("Failed to save segmented image. File " + new_filename + " already exists.")
print "Closing image"
#pdb.gimp_display_delete(gimp._id2display(0))
#Try to load one of the next 5 consecutive image numbers.
#If none found then quit plugin, else load it.
new_path = timg.filename
for i in range(0,5):
new_path = get_next_filename(new_path)
if os.path.isfile(new_path):
print new_path + " found. Loading it."
img = pdb.file_jpeg_load(new_path, new_path)
pdb.gimp_display_new(img)
return
pdb.gimp_message ("No more consecutive images were found in the folder.")
register(
"segmented_saver",
"Saves a segmented image with the correct name and opens next image.",
"Saves a segmented image with the correct name and opens next image.",
"DC",
"DC",
"2016",
"<Image>/Image/Save Segmented...",
"RGB*, GRAY*",
[],
[],
plugin_main)
main()

Just call image.enable_undo(). For example:
img = pdb.gimp_file_load('R:/1.jpg','1.jpg')
gimp.Display(img)
img.enable_undo()

Related

Closing an application (a CAD viewer), that blocks code execution, from within the code

Hi stackoverflow community!
I'm trying to write a piece of code that loops through CAD files and takes pictures of them. The problem that I encounter is that I have to open the CAD files in a viewer in order to take the pictures and this viewer blocks the further execution of code until I close it. I want to automate the process of picture taking and I thought that it would be possible to start the viewer in a separate process and then close it, but as I'm rather a beginner in python multiprocessing/threading, I struggle to do that. That's the code that I'm using:
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Display.SimpleGui import init_display
def load_step(filepath):
....
return step_reader.Shape()
for i in range(1191,2000):
folder = '00000000' + str(i)
folder_path = "E:/CAD/" + folder[-8:]
file_name = os.listdir(folder_path)
file_path = folder_path+'/'+file_name[0]
body = load_step(file_path)
picture1 = './' + folder[-8:] + '_n.png'
picture2 = './' + folder[-8:] + '_r.png'
if __name__ == "__main__":
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(body, update=True)
display.View.Dump(picture1)
display.View.Rotate(0,1.2,0)
display.View.Dump(picture2)
start_display() #starts the viewer
# close the viewer
So the question is: is there a way to close the viewer automatically from within the python code?

detect mime/extension of a file

I'm trying to write a program that when a user picks a file it can tell them whether it is a jpg, wav or another type (any other type goes under html). I got stuck in trying to process whether it is any of those types.
def openSoundOrPicture():
file=pickAFile()
print file
print len(file)
start=file.rfind('.')
print start
if start !=-1:
This is what I have so far but it doesn't work. (By the way, I'm really new to Python or any coding for the matter fact)
def openSoundOrPicture():
file=pickAFile()
print file
ln=len(file)
print ln
start=file.rfind('.')
print start
if start !=-1:
if file[start:ln]==".jpg"
print "File type:jpg"
elif file[start:ln]==".wav"
print "File type:wav"
You are basically trying to categorize files by their extension. Realize that there are other ways to do this like magic numbers. However, for what you asked to do, check out this code snippet:
recognized_types = ["jpg", "wav"]
default_type = "html"
file = pick_a_file()
file_extension = os.path.splitext(file)
if file_extension in recognized_types:
print "File Type: " + file_extension
else:
print "File Type: " + default_type

Downloading Webcomic Saving Blank Files

I have a script for downloading the Questionable Content webcomic. It looks like it runs okay, but the files it downloads are empty, only a few kb in size.
#import Web, Reg. Exp, and Operating System libraries
import urllib, re, os
#RegExp for the EndNum variable
RegExp = re.compile('.*<img src="http://www.questionablecontent.net/comics.*')
#Check the main QC page
site = urllib.urlopen("http://questionablecontent.net/")
contentLine = None
#For each line in the homepage's source...
for line in site.readlines():
#Break when you find the variable information
if RegExp.search(line):
contentLine = line
break
#IF the information was found successfuly automatically change EndNum
#ELSE set it to the latest comic as of this writing
if contentLine:
contentLine = contentLine.split('/')
contentLine = contentLine[4].split('.')
EndNum = int(contentLine[0])
else:
EndNum = 2622
#First and Last comics user wishes to download
StartNum = 1
#EndNum = 2622
#Full path of destination folder needs to pre-exist
destinationFolder = "D:\Downloads\Comics\Questionable Content"
#XRange creates an iterator to go over the comics
for i in xrange(StartNum, EndNum+1):
#IF you already have the comic, skip downloading it
if os.path.exists(destinationFolder+"\\"+str(i)+".png"):
print "Skipping Comic "+str(i)+"..."
continue
#Printing User-Friendly Messages
print "Comic %d Found. Downloading..." % i
source = "http://www.questionablecontent.net/comics/"+str(i)+".png"
#Save image from XKCD to Destination Folder as a PNG (As most comics are PNGs)
urllib.urlretrieve(source, os.path.join(destinationFolder, str(i)+".png"))
#Graceful program termination
print str(EndNum-StartNum) + " Comics Downloaded"
Why does it keep downloading empty files? Is there any workaround?
The problem here is that the server doesn't serve you the image if your user agent isn't set. Below is a sample code for Python 2.7, which should give you an idea regarding how to make your script work.
import urllib2
import time
first = 1
last = 2622
for i in range(first, last+1):
time.sleep(5) # Be nice to the server! And avoid being blocked.
for ext in ['png', 'gif']:
# Make sure that the img dir exists! If not, the script will throw an
# IOError
with open('img/{}.{}'.format(i, ext), 'wb') as ifile:
try:
req = urllib2.Request('http://www.questionablecontent.net/comics/{}.{}'.format(i, ext))
req.add_header('user-agent', 'Mozilla/5.0')
ifile.write(urllib2.urlopen(req).read())
break
except urllib2.HTTPError:
continue
else:
print 'Could not find image {}'.format(i)
continue
print 'Downloaded image {}'.format(i)
You may want to change your loop into something that resembles your loop (check whether the image has been downloaded previously etc.). This script will try to download all images from <start>.<ext> to <end>.<ext>, where <ext> is either gif or png.

What is wrong with my code? python [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am Programming in python however i have come to a slight glitch which i cannot solve! The issue is that when it prints out in a text files it only prints one line of the whole output! Otherwise it works! Please i need help to make this work!
import sys, bz2, string, os
#instead of hardcoding filename, get it from arguments
#filename = os.getcwd()
filename = raw_input("Enter the path of bz2 document e.g. files/access_log-20130301.bz2: ")
print "Using file : " + filename
source_file = bz2.BZ2File(filename, "r")
for line in source_file:
#Extract the date and put into a variable
logdate = string.split(line)[3][1:12]
#Extract movie name and put into variable movie
movie = string.split(line)[6]
#extract who read the movie username =
usernames = string.split(line)[2]
#Only process the movie line if we have /media/movie in it.
if movie.find('media/movies') > 0:
#Prints all things prosscesed
print "User:" + usernames + " On:" + logdate + " Was watching:"+ movie
#p=open(filename+"record.txt", "w")
fp=open(filename+"record.txt", "wb+")
fp.write("User: " + usernames + " On: " + logdate + " Was watching: "+ movie+" File from:"+filename+"\n")
sys.exit()
The problem is likely that you are opening a new file handle for the file each time you want to write a line, and you do not flush the output first. There are two possible solutions here:
Open the file you intend to write to before your main for loop. This way you will only have one file handle, and a lack of flushing will not cause this behavior. Make sure you close the file when you are done. (Consider using a with block, which will cause the file to be closed automatically at the termination of the block: with open(filename + "record.txt", "wb+") as f:)
Close fp immediately after the fp.write() call, which will force any buffered output to be flushed, at least to the kernel I/O cache.
I would prefer option 1, as there is no reason to open and close the file multiple times in this case. (If you are writing many lines to the file, these open/flush/close cycles will wind up wasting a lot of time!)
Option 1 would look something like this:
import sys, bz2, string, os
#instead of hardcoding filename, get it from arguments
#filename = os.getcwd()
filename = raw_input("Enter the path of bz2 document e.g. files/access_log-20130301.bz2: ")
print "Using file : " + filename
with open(filename+"record.txt", "wb+") as fp:
source_file = bz2.BZ2File(filename, "r")
for line in source_file:
#Extract the date and put into a variable
logdate = string.split(line)[3][1:12]
#Extract movie name and put into variable movie
movie = string.split(line)[6]
#extract who read the movie username =
usernames = string.split(line)[2]
#Only process the movie line if we have /media/movie in it.
if movie.find('media/movies') > 0:
#Prints all things prosscesed
print "User:" + usernames + " On:" + logdate + " Was watching:"+ movie
#p=open(filename+"record.txt", "w")
fp.write("User: " + usernames + " On: " + logdate + " Was watching: "+ movie+" File from:"+filename+"\n")
# The with block has ended at this point, so the file will already be closed here.
sys.exit()
You're opening the output file in write mode inside the loop. Open it once outside your main loop.
Be sure to close it when you're done. Even better, write that like:
with open(filename + "record.txt", "wb+") as fp:
for line in source_file:
...
fp.write(...)
so that the open context manager closes it for you afterward.

Imagekit - cache image not deleted after deleting original

In my project I have a model where I use Imagekit to process an image. When I save an image I have following requirements:
rename image and thumbnail to a unique name
when a new image is loaded, the old one should be removed (and the thumbnail in the cache should refresh to the new image).
To accomplish this, I use following code:
The model:
def generate_cache_filename(instance, path, specname, extension):
extension = '.jpg'
return 'cache/images_upload/%s_%s%s' % (instance.pk, specname, extension)
def generate_image_filename_1(instance, filename):
filename = '1'
extension = '.jpg'
return 'images_upload/%s_%s%s' % (instance.pk, filename, extension)
class Model(models.Model):
name = models.CharField(max_length=40)
image_1 = ProcessedImageField([Adjust(contrast=1.2, sharpness=1.1), ResizeToFill(500, 370)], upload_to=generate_image_filename_1, format='JPEG', options={'quality': 90})
thumbnail_1 = ImageSpec([Adjust(contrast=1.2, sharpness=1.1), ResizeToFill(83, 78)], image_field='image_1', cache_to=generate_cache_filename, format='JPEG', options={'quality': 90})
The form (to delete the image when it is replaced by a new one):
if form.is_valid():
form_image = form.cleaned_data['image_1']
try:
details = Model.objects.get(pk=pk)
if details.image_1 != form_image:
details.image_1.delete(save=False)
except Model.DoesNotExist:
pass
form.save()
The part of renaming the images and replacing image_1 (= loading new and deleting old) works just fine. But for some reason the thumbnail_1 in the cache does not refresh (= is still the thumbnail of the old image).
I think it has something to do with the deletion code in the form, but I can't figure out why and how to solve it. Someone with suggestions?
UPDATE 1: it has also something to do with the 'renaming'. I did some extra tests: when I don't rename the image_1 file, then everything works fine (also refreshing of the thumbnail). But when I load another image with the same name, then I have the same problem: image_1 is updated, but thumbnail_1 is still the thumbnail of the old image.
UPDATE 2: did some more tests and when uploading a new image with the same filename, I definitely enter the if statement in try. So the old image is deleted. According to the documentation of Imagekit, the thumbnail should also be deleted. But this is not the case.
Many thanks!
In the mean time I found a working solution.
The main reason why the above code didn't work was because of the thumbnail in the cache that was not deleted after deleting the original image, especially in cases where the new image had the same filename as the previous one => then the thumbnail was never deleted.
=> I still don't know why..., because I expected that the cached image is always deleted when the original is deleted.
Using the following code everything works as expected:
Basically I made sure the new uploaded image has always another filename:
Model.py
def generate_cache_filename(instance, path, specname, extension):
extension = '.jpg'
return 'cache/images_upload/%s_%s%s' % (instance.pk, specname, extension)
# generate random string of 10 characters
def id_generator(size=10, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))
def generate_random_filename(instance, filename):
filename = id_generator()
extension = '.jpg'
return 'images_upload/%s_%s%s' % (instance.pk, filename, extension)
class Model(models.Model):
name = models.CharField(max_length=20)
image_1 = ProcessedImageField([Adjust(contrast=1.2, sharpness=1.1), ResizeToFill(500, 370)], upload_to=generate_random_filename, format='JPEG', options={'quality': 90})
thumbnail_1 = ImageSpec([Adjust(contrast=1.2, sharpness=1.1), ResizeToFill(83, 78)], image_field='image_1', cache_to=generate_cache_filename, format='JPEG', options={'quality': 90})
View.py:
# thanks to jdi for the help in the for-loop
if form.is_valid():
# A for loop is used here, because my database contains 5 images and 5 thumbnails
image_list = ['image_%d' % i for i in xrange(1,6)]
for image_name in image_list:
form_image = form.cleaned_data[image_name]
try:
details = Model.objects.get(pk=pk)
if getattr(details, image_name, None) != form_image:
getattr(details, image_name, None).delete(save=False)
except Model.DoesNotExist:
pass
Hopefully this can help out others as well.
Kind Regards

Categories

Resources