← Back to team overview

openshot.code team mailing list archive

[Branch ~openshot.code/openshot/main] Rev 500: Applied a patch from Emil that fixes bug #534284, Thumbnail is for first frame of original clip. ...

 

------------------------------------------------------------
revno: 500
committer: Andy Finch <we.rocked.in79@xxxxxxxxx>
branch nick: openshot
timestamp: Tue 2011-08-16 20:51:22 +0100
message:
  Applied a patch from Emil that fixes bug #534284, Thumbnail is for first frame of original clip. Now when cutting a clip on the timeline, another thumbnail is generated for the first frame of the second clip for both videos and image sequences. For a fuller description of Emil's patch, see the bug description. This patch also rebuilds the thumbnails if they are lost, so fixing bug #512516.
modified:
  openshot/classes/clip.py
  openshot/classes/files.py
  openshot/classes/open_project.py
  openshot/windows/ClipProperties.py
  openshot/windows/MainGTK.py


--
lp:openshot
https://code.launchpad.net/~openshot.code/openshot/main

Your team OpenShot Code is subscribed to branch lp:openshot.
To unsubscribe from this branch go to https://code.launchpad.net/~openshot.code/openshot/main/+edit-subscription
=== modified file 'openshot/classes/clip.py'
--- openshot/classes/clip.py	2011-08-10 20:50:17 +0000
+++ openshot/classes/clip.py	2011-08-16 19:51:22 +0000
@@ -57,6 +57,10 @@
 		self.file_object = file_object  # the file object that this clip is linked to
 		self.unique_id = str(uuid.uuid1())
 		self.rotation = 0.0
+		self.thumb_location = ""
+		
+		# Update the thumbnail of the clip and the location
+		self.update_thumbnail()
 		
 		# init key-frame dictionary
 		self.keyframes = {"start" : keyframe(0, 100.0, 100.0, 0.0, 0.0, 1.0),
@@ -75,7 +79,73 @@
 		# end_time = 25.0
 		# position_on_track = 3.0
 		
-
+	def update_thumbnail(self):
+		"""Updates the thumbnail of the clip to make it reflect the first frame.
+		   Creates a new thumbnail if there is none, gives it a new thumbnail path
+		   if it is empty."""
+	
+		# Initialize variables
+		project = self.parent.parent.project
+		thumbnailer = project.thumbnailer
+		fps = self.file_object.fps
+		start_frame = int(float(fps) * self.start_time)
+		file_type = self.file_object.file_type
+		
+		# Remove the thumbnail, if it can be removed
+		self.remove_thumbnail()
+	
+		# If it cannot be exchanged for the file thumbnail
+		if start_frame and (file_type == "video" or file_type == "image sequence"):
+		
+			# If it already has a thumbnail location, just update the thumbnail
+			if self.thumb_location and not self.thumb_location == self.file_object.thumb_location:
+				(dir_name, file_name) = os.path.split(self.thumb_location)
+				
+				# The shortened path to the thumbnail. %d is escaped to provide image sequence support
+				new_name = "thumbnail/" + file_name.replace("%d","%%d")
+				
+				# The whole path. %d shouldn't be escaped here.
+				path = project.folder + "/thumbnail/" + file_name
+				
+			# If the clip needs a new thumbnail location
+			else:
+			
+				# Split the file name
+				(dir_name, file_name) = os.path.split(self.file_object.name)
+				(file_base_name, ext) = os.path.splitext(file_name)
+				
+				# Escape some characters
+				ext = ext.replace(".", "")
+				
+				# Loop to find an unoccupied name. Start at 2, since the file thumbnail starts at 1
+				i = 2
+				while(True):
+					path = project.folder + "/thumbnail/" + file_base_name + "_" + ext + "_" + str(i) + ".png"
+					if not os.path.exists(path):
+						break
+					i += 1
+					
+				# The shortened path to the thumbnail. %d is escaped to provide image sequence support
+				new_name = "thumbnail/" + file_base_name.replace("%d","%%d") + "_" + ext + "_" + str(i) + ".png"
+	
+			# Create the new thumbnail
+			thumbnailer.get_thumb_at_frame(self.file_object.name, start_frame, new_name)
+			
+			# Update the path to the thumbnail
+			self.thumb_location = path
+			print "thumb " + self.thumb_location
+			
+		elif not file_type == "audio":
+			# Use the file thumbnail instead, to avoid creating a new
+			self.thumb_location = self.file_object.thumb_location
+			
+			
+	def remove_thumbnail(self):
+		"""Removes the thumbnail from the hard drive, if it isn't shared with a file"""
+		# Removes the thumbnail used by this clip if it is valid and isn't used by a file
+		if self.thumb_location and os.path.exists(self.thumb_location) and not self.thumb_location == self.file_object.thumb_location:
+			os.remove(self.thumb_location)
+		
 	def length(self):
 		# calculate the length of this clip (in decimal seconds)
 		length = self.end_time - self.start_time
@@ -114,6 +184,50 @@
 				self.effects.append(new_effect)
 				self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Added effect") + " " + service)
 
+
+	def get_thumbnail(self, width, height):
+		"""Get and resize the pixbuf thumbnail for a clip"""	
+		
+		# get the thumbnail (or load default)
+		try:
+			if self.thumb_location:
+				pbThumb = gtk.gdk.pixbuf_new_from_file(self.thumb_location)
+				pbThumb = pbThumb.add_alpha(False, 255, 255, 255)
+				
+				# Mask the corner of the thumbnail image (for a nice rounding effect)
+				corner_mask = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, 'thumbnail_mask.png'))
+				corner_mask.composite(pbThumb, 
+								0, 
+								0, 
+								320, 
+								240, 
+								0, 
+								0, 
+								1.0, 
+								1.0, 
+								gtk.gdk.INTERP_NEAREST, 
+								255)
+
+				# replace corner with transparency
+				pbThumb = pbThumb.add_alpha(True, 255, 0, 202)
+
+
+			else:
+				# Load the No Thumbnail Picture
+				if self.file_object.file_type == "audio":
+					pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "AudioThumbnail.png"))
+				else:
+					pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "NoThumbnail.png"))
+		except:
+
+				# Load the No Thumbnail Picture
+				if self.file_object.file_type == "audio":
+					pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "AudioThumbnail.png"))
+				else:
+					pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "NoThumbnail.png"))
+
+		# resize thumbnail
+		return pbThumb.scale_simple(width, height, gtk.gdk.INTERP_BILINEAR)	
 	
 	def Remove_Effect(self, unique_id):
 		# Remove an effect from the list
@@ -1230,7 +1344,7 @@
 			# ///////////////////////////////////////////////////////	 
 			if has_regular_images == False:
 				# get the thumbnail image
-				pbThumb = self.file_object.get_thumbnail(theme_settings["clip"]["thumbnail"]["w"], theme_settings["clip"]["thumbnail"]["h"])
+				pbThumb = self.get_thumbnail(theme_settings["clip"]["thumbnail"]["w"], theme_settings["clip"]["thumbnail"]["h"])
 				
 				# create canvas image object
 				imgThumb = goocanvas.Image (parent = GroupClip,
@@ -1976,6 +2090,14 @@
 			child_num = parent.find_child (item)
 			parent.remove_child (child_num)			
 			
+			# Initialize variables
+			pixels_per_second = self.parent.parent.get_pixels_per_second()
+			center_of_clip = (self.position_on_track * pixels_per_second) + ((self.length() * pixels_per_second) / 2)
+			
+			# If the clip was dragged on the left side, update the thumbnail to reflect the changes
+			if event.x_root < center_of_clip:
+				self.update_thumbnail()
+			
 			# re-render the clip at it's new size
 			self.RenderClip()
 			

=== modified file 'openshot/classes/files.py'
--- openshot/classes/files.py	2011-08-11 21:59:28 +0000
+++ openshot/classes/files.py	2011-08-16 19:51:22 +0000
@@ -104,6 +104,26 @@
 		# resize thumbnail
 		return pbThumb.scale_simple(width, height, gtk.gdk.INTERP_BILINEAR)	
 		
+	def update_thumbnail(self):
+	
+		# Initialize variables
+		project = self.project
+		thumbnailer = project.thumbnailer
+		file_type = self.file_type
+		
+		# Audio files have a common thumbnail
+		if not file_type == "audio":	
+		
+			# Split the file name
+			(dir_name, file_name) = os.path.split(self.name)
+			(file_base_name, ext) = os.path.splitext(file_name)
+			ext = ext.replace(".", "")
+			
+			# The shortened path to the thumbnail
+			new_name = "thumbnail/" + file_base_name + "_" + ext + "_1.png"
+			
+			# Create the new thumbnail
+			thumbnailer.get_thumb_at_frame(self.name, new_name=new_name)
 
 ########################################################################
 class OpenShotFolder:
@@ -442,8 +462,10 @@
 				for clip in reversed(track.clips):
 					# does clip match file
 					if clip.file_object == item:
-						# delete clip
+						# delete clip and remove thumbnail
 						track.clips.remove(clip)
+						clip.remove_thumbnail()
+			
 			# remove from file collection
 			self.items.remove(item)
 		else:

=== modified file 'openshot/classes/open_project.py'
--- openshot/classes/open_project.py	2011-01-13 07:33:37 +0000
+++ openshot/classes/open_project.py	2011-08-16 19:51:22 +0000
@@ -95,6 +95,26 @@
 		if missing_transitions:
 			messagebox.show("OpenShot", _("The following transition(s) no longer exist.") + "\n\n" + missing_transitions)
 		
+		# Recreate the thumbnail folder if it is missing
+		if not os.path.exists(project_object.folder + "/thumbnail"):
+			os.makedirs(project_object.folder + "/thumbnail")
+		
+		# Recreate missing thumbnails for files
+		for item in items:
+			if isinstance(item, files.OpenShotFile):
+				if not os.path.exists(item.thumb_location):
+					item.update_thumbnail()
+		
+		# Recreate missing thumbnails for clips
+		for sequence in project_object.sequences:
+			for track in sequence.tracks:
+				for clip in track.clips:
+					# Code to keep pre 1.4.0 .osp files compatible. May be removed later.
+					if not hasattr(clip, "thumb_location"):
+						clip.thumb_location = ""
+				
+					if not os.path.exists(clip.thumb_location) and not clip.file_object.file_type == "audio":
+						clip.update_thumbnail()
 		
 		# mark XML as refreshable
 		project_object.set_project_modified(is_modified=False, refresh_xml=True)

=== modified file 'openshot/windows/ClipProperties.py'
--- openshot/windows/ClipProperties.py	2011-08-10 20:13:08 +0000
+++ openshot/windows/ClipProperties.py	2011-08-16 19:51:22 +0000
@@ -891,6 +891,9 @@
 		# update keyframes
 		clip_object.keyframes = self.keyframes
 		
+		# Update the thumbnail
+		clip_object.update_thumbnail()
+		
 		if localcboDirection.lower() == _("Reverse").lower():
 			clip_object.reversed = True
 		else:

=== modified file 'openshot/windows/MainGTK.py'
--- openshot/windows/MainGTK.py	2011-08-11 20:33:40 +0000
+++ openshot/windows/MainGTK.py	2011-08-16 19:51:22 +0000
@@ -2253,7 +2253,7 @@
 						#this will be the new name of the snapshot image file
 						new_name = fileBaseName +  str(intNum) + ".png"
 						#extract the frame
-						self.project.thumbnailer.get_thumb_at_frame(clip.file_object.name, int(frame_position), new_name)
+						self.project.thumbnailer.get_thumb_at_frame(clip.file_object.name, int(frame_position), new_name, True)
 						#add the file to the project in the project folder
 						self.project.project_folder.AddFile(self.project.folder + "/" + new_name)
 						#refresh the tree
@@ -3535,6 +3535,7 @@
 		
 		# render timeline
 		self.project.Render()	
+		
 	def on_mnuClipEditTitle_activate(self, event, *args):
 		#print "on_mnuClipEditTitle_activate"
 		
@@ -3575,6 +3576,9 @@
 		child_num = parent.find_child (self.selected_clip_item)
 		parent.remove_child (child_num)
 		
+		# Remove the thumbnail
+		self.selected_clip.remove_thumbnail()
+		
 		# mark project as modified
 		self.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Removed clip"))
 		
@@ -3696,6 +3700,9 @@
 		new_clip.keyframes = copy.deepcopy(self.selected_clip.keyframes)
 		new_clip.effects = copy.deepcopy(self.selected_clip.effects)
 		
+		# Update the thumbnail
+		new_clip.update_thumbnail()
+		
 		# mark project as modified
 		self.project.set_project_modified(is_modified=True, refresh_xml=True, type="Duplicated clip")