Version 124

This commit is contained in:
Hydrus 2014-07-30 16:18:17 -05:00
parent b7eaed8695
commit 033829f432
10 changed files with 188 additions and 43 deletions

View File

@ -4,9 +4,10 @@
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
import wx
import locale
wx.Locale()
try: locale.setlocale( locale.LC_ALL, '' )
except: pass
from include import HydrusConstants as HC

View File

@ -8,6 +8,13 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 124</h3></li>
<ul>
<li>fixed some more broken gifs (those with funky transparency, I think)</li>
<li>fixed a critical bug in the subscriptions dialog that was causing subscriptions to be deleted</li>
<li>reintroduced old locale code, with minor improvement, to fix number grouping (123,456,789) issue</li>
<li>added a short pre-activation wait to all daemons to reduce more wake-from-sleep problems like the UPnP issue last week</li>
</ul>
<li><h3>version 123</h3></li>
<ul>
<li>rewrote the old gif rendering code to the new system, so gifs with variable framerates now work again!</li>
@ -24,7 +31,7 @@
<li>neatened all object declarations</li>
<li>fixed a menu bug in OS X</li>
<li>added put a little delay in the upnp daemon, hopefully to stop the error popups after waking from sleep</li>
<li>updateid a old hacky bit of locale code that was breaking certain platforms of wx 2.9.5.0</li>
<li>updated an old hacky bit of locale code that was breaking certain platforms of wx 2.9.5.0</li>
<li>improved animation and other rendering timings on non-windows platforms</li>
<li>improved media focus on non-windows platforms</li>
</ul>

View File

@ -5386,6 +5386,8 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
self._original_subscription_names = HC.app.Read( 'subscription_names' )
self._names_to_delete = set()
InitialiseControls()
PopulateControls()
@ -5498,15 +5500,20 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
all_pages = self._listbook.GetNameToPageDict().values()
subscriptions = [ page.GetSubscription() for page in all_pages ]
try:
for ( name, info ) in subscriptions: HC.app.Write( 'subscription', name, info )
for name in self._names_to_delete: HC.app.Write( 'delete_subscription', name )
deletees = set( self._original_subscription_names ) - { name for ( name, info ) in subscriptions }
for name in deletees: HC.app.Write( 'delete_subscription', name )
for page in all_pages:
( name, info ) = page.GetSubscription()
original_name = page.GetOriginalName()
if original_name != name: HC.app.Write( 'delete_subscription', original_name )
HC.app.Write( 'subscription', name, info )
HC.subs_changed = True
@ -5530,6 +5537,10 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
panel = self._listbook.GetCurrentPage()
name = panel.GetOriginalName()
self._names_to_delete.add( name )
if panel is not None: self._listbook.DeleteCurrentPage()
@ -5694,6 +5705,7 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
else: info = HC.app.Read( 'subscription', name )
self._original_name = name
self._original_info = info
InitialiseControls()
@ -5870,6 +5882,8 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
return ( name, info )
def GetOriginalName( self ): return self._original_name
def GetName( self ): return self._name.GetValue()
def Update( self, name, info ):

View File

@ -64,7 +64,7 @@ options = {}
# Misc
NETWORK_VERSION = 13
SOFTWARE_VERSION = 123
SOFTWARE_VERSION = 124
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -115,24 +115,43 @@ def GenerateHydrusBitmapFromNumPyImage( cv_image ):
( y, x, depth ) = cv_image.shape
if depth == 4: raise Exception( 'CV is bad at alpha!' )
if depth == 4: return HydrusBitmap( cv_image.data, wx.BitmapBufferFormat_RGBA, ( x, y ) )
else: return HydrusBitmap( cv_image.data, wx.BitmapBufferFormat_RGB, ( x, y ) )
def GenerateNumPyImageFromPILImage( pil_image ):
if pil_image.mode == 'RGBA' or ( pil_image.mode == 'P' and pil_image.info.has_key( 'transparency' ) ):
if pil_image.mode == 'P': pil_image = pil_image.convert( 'RGBA' )
else:
if pil_image.mode != 'RGB': pil_image = pil_image.convert( 'RGB' )
( w, h ) = pil_image.size
s = pil_image.tostring()
return numpy.fromstring( s, dtype = 'uint8' ).reshape( ( h, w, len( s ) // ( w * h ) ) )
def GenerateHydrusBitmapFromPILImage( pil_image ):
if pil_image.mode == 'RGBA' or ( pil_image.mode == 'P' and pil_image.info.has_key( 'transparency' ) ):
if pil_image.mode == 'P': pil_image = pil_image.convert( 'RGBA' )
return HydrusBitmap( pil_image.tostring(), wx.BitmapBufferFormat_RGBA, pil_image.size )
format = wx.BitmapBufferFormat_RGBA
else:
if pil_image.mode != 'RGB': pil_image = pil_image.convert( 'RGB' )
return HydrusBitmap( pil_image.tostring(), wx.BitmapBufferFormat_RGB, pil_image.size )
format = wx.BitmapBufferFormat_RGB
return HydrusBitmap( pil_image.tostring(), format, pil_image.size )
def GeneratePerceptualHash( path ):
cv_image = cv2.imread( path, cv2.CV_LOAD_IMAGE_UNCHANGED )

View File

@ -68,7 +68,7 @@ class DAEMONQueue( DAEMON ):
class DAEMONWorker( DAEMON ):
def __init__( self, name, callable, topics = [], period = 1200, init_wait = 3, pre_callable_wait = 0 ):
def __init__( self, name, callable, topics = [], period = 1200, init_wait = 3, pre_callable_wait = 3 ):
DAEMON.__init__( self, name )

View File

@ -293,7 +293,7 @@ class VideoContainer( HydrusImageHandling.RasterContainer ):
self._durations = HydrusImageHandling.GetGIFFrameDurations( self._path )
self._renderer = GIFRendererCV( path, num_frames, target_resolution )
self._renderer = GIFRenderer( path, num_frames, target_resolution )
else:
@ -637,7 +637,7 @@ class VideoRendererFFMPEG( object ):
else: self.skip_frames( pos - self.pos )
class GIFRendererCV( object ):
class GIFRenderer( object ):
def __init__( self, path, num_frames, target_resolution ):
@ -645,6 +645,66 @@ class GIFRendererCV( object ):
self._num_frames = num_frames
self._target_resolution = target_resolution
self._cv_mode = True
self._InitialiseCV()
def _GetCurrentFrame( self ):
if self._cv_mode:
( retval, cv_image ) = self._cv_video.read()
if not retval:
self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
raise HydrusExceptions.CantRenderWithCVException( 'CV could not render frame ' + HC.u( self._next_render_index - 1 ) + '.' )
else:
if self._pil_image.mode == 'P' and 'transparency' in self._pil_image.info:
# I think gif problems are around here somewhere; the transparency info is not converted to RGBA properly, so it starts drawing colours when it should draw nothing
current_frame = self._pil_image.convert( 'RGBA' )
if self._pil_canvas is None: self._pil_canvas = current_frame
else: self._pil_canvas.paste( current_frame, None, current_frame ) # use the rgba image as its own mask
else: self._pil_canvas = self._pil_image
cv_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( self._pil_canvas )
self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
if self._next_render_index == 0:
self._RewindGIF()
else:
if not self._cv_mode:
self._pil_image.seek( self._next_render_index )
if self._pil_image.palette == self._pil_global_palette: # for some reason, when pil falls back from local palette to global palette, a bunch of important variables reset!
pil_image.palette.dirty = self._pil_dirty
pil_image.palette.mode = self._pil_mode
pil_image.palette.rawmode = self._pil_rawmode
return cv_image
def _InitialiseCV( self ):
self._cv_video = cv2.VideoCapture( self._path )
self._cv_video.set( cv2.cv.CV_CAP_PROP_CONVERT_RGB, True )
@ -653,53 +713,80 @@ class GIFRendererCV( object ):
self._last_frame = None
def _GetCurrentFrame( self ):
def _InitialisePIL( self ):
( retval, cv_image ) = self._cv_video.read()
self._pil_image = HydrusImageHandling.GeneratePILImage( self._path )
self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
self._pil_canvas = None
if self._next_render_index == 0:
self._RewindGIF()
#self._cv_video.set( cv2.cv.CV_CAP_PROP_POS_FRAMES, 0.0 )
self._pil_global_palette = self._pil_image.palette
if not retval:
raise HydrusExceptions.CantRenderWithCVException( 'CV could not render frame ' + HC.u( self._next_render_index ) + '.' )
self._pil_dirty = self._pil_image.palette.dirty
self._pil_mode = self._pil_image.palette.mode
self._pil_rawmode = self._pil_image.palette.rawmode
return cv_image
self._next_render_index = 0
self._last_frame = None
# believe it or not, doing this actually fixed a couple of gifs!
self._pil_image.seek( 1 )
self._pil_image.seek( 0 )
def _RenderCurrentFrame( self ):
try:
if self._cv_mode:
try:
cv_image = self._GetCurrentFrame()
cv_image = HydrusImageHandling.EfficientlyResizeCVImage( cv_image, self._target_resolution )
cv_image = cv2.cvtColor( cv_image, cv2.COLOR_BGR2RGB )
self._last_frame = cv_image
except HydrusExceptions.CantRenderWithCVException:
if self._last_frame is None:
self._cv_mode = False
self._InitialisePIL()
return self._RenderCurrentFrame()
else: cv_image = self._last_frame
else:
cv_image = self._GetCurrentFrame()
cv_image = HydrusImageHandling.EfficientlyResizeCVImage( cv_image, self._target_resolution )
cv_image = cv2.cvtColor( cv_image, cv2.COLOR_BGR2RGB )
self._last_frame = cv_image
except HydrusExceptions.CantRenderWithCVException:
cv_image = self._last_frame
return cv_image
def _RewindGIF( self ):
self._cv_video.release()
self._cv_video.open( self._path )
self._next_render_index = 0
if self._cv_mode:
self._cv_video.release()
self._cv_video.open( self._path )
self._next_render_index = 0
#self._cv_video.set( cv2.cv.CV_CAP_PROP_POS_FRAMES, 0.0 )
else:
self._pil_image.seek( 0 )
def read_frame( self ): return self._RenderCurrentFrame()

View File

@ -40,6 +40,17 @@ class TestHydrusDownloadingFunctions( unittest.TestCase ):
self.assertEqual( HydrusDownloading.ConvertServiceIdentifiersToTagsToServiceIdentifiersToContentUpdates( hash, service_identifiers_to_tags ), content_updates )
def test_number_conversion( self ):
i = 123456789
i_pretty = HC.ConvertIntToPrettyString( i )
# this test only works on anglo computers; it is mostly so I can check it is working on mine
self.assertEqual( i_pretty, '123,456,789' )
def test_tags_to_dict( self ):
local = TestConstants.GenerateClientServiceIdentifier( HC.LOCAL_TAG )

View File

@ -4,9 +4,10 @@
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
import wx
import locale
wx.Locale()
try: locale.setlocale( locale.LC_ALL, '' )
except: pass
from include import HydrusConstants as HC

View File

@ -1,3 +1,8 @@
import locale
try: locale.setlocale( locale.LC_ALL, '' )
except: pass
from include import HydrusConstants as HC
from include import ClientConstants as CC