hydrus/include/ClientSerialisable.py

274 lines
7.0 KiB
Python

import ClientConstants as CC
import ClientImageHandling
import ClientParsing
import cv2
import HydrusConstants as HC
import HydrusData
import HydrusSerialisable
import numpy
import os
import struct
import wx
if cv2.__version__.startswith( '2' ):
IMREAD_UNCHANGED = cv2.CV_LOAD_IMAGE_UNCHANGED
else:
IMREAD_UNCHANGED = cv2.IMREAD_UNCHANGED
png_font = cv2.FONT_HERSHEY_TRIPLEX
greyscale_text_color = 0
title_size = 0.7
payload_type_size = 0.5
text_size = 0.4
def CreateTopImage( width, title, payload_type, text ):
text_extent_bmp = wx.EmptyBitmap( 20, 20, 24 )
dc = wx.MemoryDC( text_extent_bmp )
text_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT )
basic_font_size = text_font.GetPointSize()
payload_type_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT )
payload_type_font.SetPointSize( int( basic_font_size * 1.4 ) )
title_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT )
title_font.SetPointSize( int( basic_font_size * 2.0 ) )
dc.SetFont( text_font )
( gumpf, text_line_height ) = dc.GetTextExtent( 'abcdefghijklmnopqrstuvwxyz' )
dc.SetFont( payload_type_font )
( gumpf, payload_type_line_height ) = dc.GetTextExtent( 'abcdefghijklmnopqrstuvwxyz' )
dc.SetFont( title_font )
( gumpf, title_line_height ) = dc.GetTextExtent( 'abcdefghijklmnopqrstuvwxyz' )
del dc
del text_extent_bmp
text_lines = WrapText( text, width, text_size, 1 )
if len( text_lines ) == 0:
text_total_height = 0
else:
text_total_height = ( text_line_height + 4 ) * len( text_lines )
text_total_height += 6 # to bring the last 4 padding up to 10 padding
top_height = 10 + title_line_height + 10 + payload_type_line_height + 10 + text_total_height
#
top_bmp = wx.EmptyBitmap( width, top_height, 24 )
dc = wx.MemoryDC( top_bmp )
dc.SetBackground( wx.Brush( wx.WHITE ) )
dc.Clear()
#
dc.DrawBitmap( CC.GlobalBMPs.file_repository, width - 16 - 5, 5 )
#
current_y = 10
dc.SetFont( title_font )
( t_width, t_height ) = dc.GetTextExtent( title )
dc.DrawText( title, ( width - t_width ) / 2, current_y )
current_y += t_height + 10
dc.SetFont( payload_type_font )
( t_width, t_height ) = dc.GetTextExtent( payload_type )
dc.DrawText( payload_type, ( width - t_width ) / 2, current_y )
current_y += t_height + 10
dc.SetFont( text_font )
for text_line in text_lines:
( t_width, t_height ) = dc.GetTextExtent( text_line )
dc.DrawText( text_line, ( width - t_width ) / 2, current_y )
current_y += t_height + 4
del dc
data = top_bmp.ConvertToImage().GetData()
top_image_rgb = numpy.fromstring( data, dtype = 'uint8' ).reshape( ( top_height, width, 3 ) )
top_bmp.Destroy()
top_image = cv2.cvtColor( top_image_rgb, cv2.COLOR_RGB2GRAY )
top_height_header = struct.pack( '!H', top_height )
( byte0, byte1 ) = top_height_header
top_image[0][0] = ord( byte0 )
top_image[0][1] = ord( byte1 )
return top_image
def DumpToPng( payload, title, payload_type, text, path ):
payload_length = len( payload )
payload_string_length = payload_length + 4
square_width = int( float( payload_string_length ) ** 0.5 )
width = max( 512, square_width )
payload_height = int( float( payload_string_length ) / width )
if float( payload_string_length ) / width % 1.0 > 0:
payload_height += 1
top_image = CreateTopImage( width, title, payload_type, text )
payload_length_header = struct.pack( '!I', payload_length )
num_empty_bytes = payload_height * width - payload_string_length
full_payload_string = payload_length_header + payload + '\x00' * num_empty_bytes
payload_image = numpy.fromstring( full_payload_string, dtype = 'uint8' ).reshape( ( payload_height, width ) )
finished_image = numpy.concatenate( ( top_image, payload_image ) )
cv2.imwrite( path, finished_image, [ cv2.IMWRITE_PNG_COMPRESSION, 9 ] )
def GetPayloadTypeAndString( payload_obj ):
payload_string = payload_obj.DumpToNetworkString()
if isinstance( payload_obj, ClientParsing.ParseRootFileLookup ):
payload_obj_type_string = 'File Lookup Script'
payload_type = payload_obj_type_string + ' - ' + HydrusData.ConvertIntToBytes( len( payload_string ) )
return ( payload_type, payload_string )
def LoadFromPng( path ):
try:
numpy_image = cv2.imread( path, flags = IMREAD_UNCHANGED )
except Exception as e:
HydrusData.ShowException( e )
raise Exception( 'That did not appear to be a valid image!' )
try:
( height, width ) = numpy_image.shape
complete_data = numpy_image.tostring()
top_height_header = complete_data[:2]
( top_height, ) = struct.unpack( '!H', top_height_header )
full_payload_string = complete_data[ width * top_height : ]
payload_length_header = full_payload_string[:4]
( payload_length, ) = struct.unpack( '!I', payload_length_header )
payload = full_payload_string[ 4 : 4 + payload_length ]
except Exception as e:
HydrusData.ShowException( e )
raise Exception( 'The image was fine, but it did not seem to have hydrus data encoded in it!' )
return payload
def TextExceedsWidth( text, width, size, thickness ):
( ( tw, th ), baseline ) = cv2.getTextSize( text, png_font, size, thickness )
return tw > width
def WrapText( text, width, size, thickness ):
words = text.split( ' ' )
lines = []
next_line = []
for word in words:
if word == '':
continue
potential_next_line = list( next_line )
potential_next_line.append( word )
if TextExceedsWidth( ' '.join( potential_next_line ), width, size, thickness ):
if len( potential_next_line ) == 1: # one very long word
lines.append( ' '.join( potential_next_line ) )
next_line = []
else:
lines.append( ' '.join( next_line ) )
next_line = [ word ]
else:
next_line = potential_next_line
if len( next_line ) > 0:
lines.append( ' '.join( next_line ) )
return lines