Attachment 'BitmapManip.py'

Download

   1 """
   2 Advanced image and image mask manipulation.
   3 
   4 Note:  The terms "plane", "band", "layer" and "channel" are used interchangibly.
   5 
   6 Tested on Win7 64-bit (6.1.7600) and Win XP SP3 (5.1.2600) using Python 32-bit.
   7 
   8 Platform  Windows 6.1.7600
   9 Python    2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel) (x86)]
  10 Python wx 2.8.10.1
  11 Pil       1.1.7
  12 
  13 Ray Pasco      
  14 pascor(at)verizon(dot)net
  15 
  16 Last modification:      2011-04-02
  17 
  18 This code may be modified and distributed for any purpose whatsoever.
  19 
  20 """
  21 
  22 import os
  23 import wx
  24 import Image        # Pil
  25 import ImgConv      # wxImage <==> PilImage
  26 
  27 #------------------------------------------------------------------------------
  28 
  29 def CreateMaskBitmapFromPilImage( pilImage, useTransparency=True, threshold=128 ) :
  30     """
  31     Return a binary mask wxBitmap derived from an image file.
  32     
  33     If the image file has either binary or variable transparency 
  34     (aka "multivalued" or "alpha") then use it and ignore the image itself
  35     unless useTransparency=False. The pilImage may have any "L" mode.
  36     
  37     Transparency in the mask bmap will be indicated by the values less than "threshold" 
  38     and opaqueness by alpha values >= "threshold".  Alpha values will be quantized into [0, 255].
  39     
  40     If the pilImage has no alpha transparency layer then the image, itself, 
  41     will be used to create the mask 0/255 mask values. The pilImage may have any non-"L" mode.
  42     An RGB pilImage used as a mask will be converted to grey level by Pil :
  43         L = (R * 299/1000) + (G * 587/1000) + (B * 114/1000)
  44     """
  45     sizeX, sizeY = pilImage.size
  46     
  47     pilMode = pilImage.mode
  48     hasTransparency = pilMode[ -1 ] == 'A'      # This looks like a hack, but it always works.
  49     
  50     if hasTransparency and useTransparency :    # Extract the alpha plane for use as a mask.
  51         
  52         # convert to only 2 planes
  53         if not (pilMode == 'LA' ) :
  54             pilImage = pilImage.convert( 'LA' )
  55         
  56         # Extract the tranparency plane
  57         mask_pilImage = pilImage.split()[1]     # Keep only the alpha; the image data is discarded.
  58         
  59     else :  # no transparency present or useTransparency=False was given.
  60         
  61         # Convert image data to greyLevel for use as the mask
  62         if not (pilMode == 'L' ) :
  63             mask_pilImage = pilImage.convert( 'L' )
  64         
  65     #end if
  66     
  67     # Quantize any alpha (non-binary) values to [0, 255]
  68     mask_pilImage = mask_pilImage.point(lambda i: (i / threshold) * 255)
  69     
  70     return ImgConv.WxBitmapFromPilImage( mask_pilImage )
  71     
  72 #end def CreateMaskBitmapFromPilImage
  73 
  74 #------------------------------------------------------------------------------
  75 
  76 def CreateMaskBitmapFromFile( imageFilename, useTransparency=True, threshold=128 ) :
  77     """
  78     Return a mask wxBitmap derived from an image file. Image files read by PIL
  79     will have had any mask transparency automatically converted to alpha transparency.
  80     
  81     If the image file has either mask or alpha transparency then use that transparency
  82     information by default and ignore the image itself unless given [ useTransparency=False ]. 
  83     
  84     Transparency in the mask bmap will be indicated by the alpha values less than 127 
  85     and opaqueness by values >= 128.  Alpha values will be quantized using the 50% level 
  86     into black and white unless another [ threshold ] parameter is given.
  87     
  88     If no transparency information is within the image, then the image, itself, 
  89     will be used to create the mask values. It may be RGB or L format.
  90     
  91     All RGB images will be converted to grey level:
  92         L = (R * 299/1000) + (G * 587/1000) + (B * 114/1000)
  93     and quantized to binary 0 and 255 at the "threshold" level.
  94     """
  95     imageFile_pilImage = Image.open( imageFilename )
  96     
  97     mask_wxBitmap = CreateMaskBitmapFromPilImage( imageFile_pilImage, 
  98                                                   useTransparency=useTransparency, 
  99                                                   threshold=128 )
 100     
 101     return mask_wxBitmap
 102     
 103 #end def CreateMaskBitmapFromFile
 104 
 105 #------------------------------------------------------------------------------
 106 
 107 def GetCombinedImageSize( image1_size, image2_size, offset2, extend=True ) :
 108     
 109     # Default settings if ofset image2 is entirely within image1.
 110     #  I.e., if no target image extent increases are needed or are not wanted.
 111     image1Origin = [ 0, 0 ]                         # Where to paste image1 into the future target image
 112     image2Origin = [ offset2[0], offset2[1] ]       # Where to paste image2
 113     combinedSize = [ image1_size[0], image1_size[1] ] # Start by setting target image's size to image1's size
 114     
 115     # Check and adjust the default settings if any portion of image2
 116     #   extends beyond any of image1's 4 borders.
 117     if not extend :
 118         pass                # Image2 will get clipped if any portion extends past image1.
 119         
 120     else :
 121         if offset2[0] < image1Origin[0] :           # is image2 X offset negative ?
 122             image1Origin[0] = 0 - offset2[0]        # Offset image1 towards the right
 123             image2Origin[0] = 0                     # Make a new left border.
 124             combinedSize[0] = image1_size[0] - offset2[0] # Enlarge target to the left of image1
 125         #end if
 126         #
 127         if offset2[0] + image2_size[0] > image1_size[0] :       # ofsetted image2's right border is past image1's
 128             combinedSize[0] += (offset2[0] + image2_size[0]) - image1_size[0]
 129         #end if
 130         
 131             
 132         if offset2[1] < image1Origin[1] :           # is image2's Y offset negative ?
 133             image1Origin[1] = 0 - offset2[1]        # Offset image1 towards the bottom
 134             image2Origin[1] = 0                     # Make a new top border.
 135             combinedSize[1] = image1_size[1] - offset2[1] # Enlarge target to hold both image1 and image2
 136         #end if
 137         #
 138         if offset2[1] + image2_size[1] > image1_size[1] :       # ofsetted image2's bottom border is past image1's
 139             combinedSize[1] += (offset2[1] + image2_size[1]) - image1_size[1]
 140         #end if
 141         
 142     #end if
 143     
 144     # Convert the lists into tuples.
 145     image1Origin = ( image1Origin[0], image1Origin[1] )     # Where to paste image1
 146     image2Origin = ( image2Origin[0], image2Origin[1] )     # Where to paste image1
 147     combinedSize = ( combinedSize[0], combinedSize[1] )     # New combined image size.
 148     
 149     return (combinedSize, image1Origin, image2Origin)
 150     
 151 #end def GetCombinedImageSize
 152 
 153 #------------------------------------------------------------------------------
 154 
 155 def ConvertToPilImageAndGetImageType( inputImage ) :
 156     """
 157     The input object may be a pilImage, a wx.Bitmap, a wx.Image or an image filename.
 158     The image type returned will be according to inputImage's object type:
 159     
 160         Mask1 Type          returned Image Type
 161         ----------          -------------------
 162         Pil Image               Pil Image
 163         wx Image                wx Image
 164         wx Bitmap               wx Bitmap
 165         Filename (string)       wx Bitmap
 166     """
 167     
 168     # Determine the image's object type.
 169     if inputImage.__class__ == Image.Image :             # pilImage
 170         returnType = 'pilImage'
 171         pilImage = image        # Already PilImage.
 172         
 173     elif inputImage.__class__ == str :                   # a file image
 174         returnType = 'wxBitmap'
 175         pilImage = Image.open( inputImage )
 176         
 177     elif inputImage.__class__ == wx._gdi.Bitmap :        # wxBitmap
 178         returnType = 'wxBitmap'
 179         pilImage = ImgConv.PilImageFromWxBitmap( inputImage )
 180         
 181     elif inputImage.__class__ == wx._core.Image :        # wxImage
 182         returnType = 'wxImage'
 183         pilImage = ImgConv.PilImageFromWxImage( inputImage )
 184     #end if
 185     
 186     return (pilImage, returnType)
 187     
 188 #end def ConvertToPilImageAndGetImageType
 189 
 190 #------------------------------------------------------------------------------
 191 
 192 def CombineMasks( mask1_image, mask2_image, offset2=(0, 0), extend=True, threshold=128 ) :
 193     """
 194     Combine one transparency mask image with another.
 195     Fully transparent pixels are indicated by their values being < "threshold".
 196     Fully opaque pixels are indicated by values > "threshold".
 197     
 198     All RGB images will be converted to grey level:
 199         L = (R * 299/1000) + (G * 587/1000) + (B * 114/1000)
 200     and quantized to binary 0 and 255 at the "threshold" value.
 201     
 202     All wx mask bitmaps are RGB, but the given mask images may be either greyscale 
 203     or RGB.  TRANSPARENCY LAYERS ARE PERMITTED, BUT ARE IGNORED.
 204     
 205     The resultant image size will be the union of file1's area and the offset 
 206     file2's area. That is, if extend=True and mask2_image extends past mask1_image's borders
 207     then the returned area will be extended to include all of offset mask2_image's area.
 208     Setting extend=False would crop mask2_image at mask1_image's borders.
 209     """
 210     
 211     mask1_pilImage, returnType      = ConvertToPilImageAndGetImageType( mask1_image )
 212     mask2_pilImage, returnTypeDummy = ConvertToPilImageAndGetImageType( mask2_image )
 213     
 214     # Create easy-to-process 1-layer (grey-level) Pil images.
 215     # The given images should have already been processed into binary values.
 216     if not (mask1_pilImage.mode == 'L') :
 217         mask1_pilImage = mask1_pilImage.convert( 'L' )
 218     if not (mask2_pilImage.mode == 'L') :
 219         mask2_pilImage = mask2_pilImage.convert( 'L' )
 220     
 221     mask1_size = mask1_pilImage.size
 222     mask2_size = mask2_pilImage.size
 223     
 224     #--------------
 225     
 226     # The resulting size is automatically enlarged if there are any areas of non-overlap.
 227     combinedSize, image1Origin, image2Origin =  \
 228            GetCombinedImageSize( mask1_size, mask2_size, offset2, extend=extend )
 229            
 230     combinedMask_pilImage = Image.new( 'L', combinedSize, color=(0) )   # completely transparent to start
 231     
 232     # Use Pil to quickly paste image1 and image2 into combinedMask_pilImage 
 233     # using their own greylevel data as masks.
 234     combinedMask_pilImage.paste( mask1_pilImage, image1Origin, mask1_pilImage )
 235     combinedMask_pilImage.paste( mask2_pilImage, image2Origin, mask2_pilImage )
 236     
 237     #--------------
 238     
 239     # Convert the finished combined bitmask to Image1's format, whatever that happens to be.
 240     if   returnType == 'pilImage' :
 241         combinedMask = combinedMask_pilImage
 242         
 243     elif returnType == 'wxBitmap' :
 244         combinedMask = ImgConv.WxBitmapFromPilImage( combinedMask_pilImage )
 245             
 246     elif returnType == 'wxImage' :
 247         combinedMask = ImgConv.WxImageFromPilImage( combinedMask_pilImage )
 248     #end if
 249     
 250     return combinedMask
 251     
 252 #end def CombineMasks
 253 
 254 #------------------------------------------------------------------------------
 255 
 256 def CombinePilImagesUsingMasks( image1_pilImage, mask1_pilImage, 
 257                                 image2_pilImage, mask2_pilImage,
 258                                 offset2=(0, 0) ) :
 259     
 260     image1_size = image1_pilImage.size    
 261     image2_size = image2_pilImage.size
 262     
 263     mask1_size = mask1_pilImage.size
 264     mask2_size = mask2_pilImage.size
 265     
 266     # Size the combined output as the union of the 2 given.
 267     targetSizeX = image1_size[0]        # Start with image1's size
 268     if (image2_size[0] + offset2[0]) > targetSizeX :     # Extend right border
 269         targetSizeX = image2_size[0] + offset2[0]
 270     
 271     targetSizeY = image1_size[1]        # Start with image1's size
 272     if (image2_size[1] + offset2[1]) > targetSizeY :
 273         targetSizeY = image2_size[1] + offset2[1]        # Extend bottom border
 274     
 275     # Create a brand new Target PilImage and Mask PilImage
 276     targetSize = (targetSizeX, targetSizeY)
 277     targetRGB_pilImage  = Image.new( 'RGB', targetSize, color=(0, 0, 0) )
 278     targetMask_pilImage = Image.new( 'L',   targetSize, color=(0) )
 279     
 280     #----------------------------------
 281     
 282     if mask1_size != image1_size :      # !!  Fatal error  !!
 283         print '\n####  BitmapManip:  CombineFileImagesUsingFileMasks():   Unequal Mask1 and Image1 Sizes'
 284         print '        mask1_size, image1_size', mask1_size, image1_size
 285         os._exit(1)
 286     #end if
 287     size1 = image1_size
 288     
 289     if mask2_size != image2_size :
 290         print '\n####  BitmapManip:  CombineFileImagesUsingFileMasks():   Unequal Mask2 and Image2 Sizes'
 291         print '        mask2_size, image2_size', mask2_size, image2_size
 292         os._exit(1)
 293     #end if
 294     size2 = image2_size
 295     
 296     #----------------------------------
 297     
 298     # Copy image1 and mask1 images into the target image and target mask, respectively.
 299     image1Origin = (0, 0)
 300     targetRGB_pilImage.paste( image1_pilImage, image1Origin, mask1_pilImage )
 301     targetMask_pilImage.paste( mask1_pilImage, image1Origin, mask1_pilImage )
 302     
 303     # Copy image2 and mask2 into the target image and target mask.
 304     image2Origin = offset2
 305     targetRGB_pilImage.paste( image2_pilImage, image2Origin, mask2_pilImage )
 306     targetMask_pilImage.paste( mask2_pilImage, image2Origin, mask2_pilImage )
 307     
 308     # Compose the complete target RGBA PilImage.
 309     targetRGBA_pilImage =  targetRGB_pilImage.convert( 'RGBA' )
 310     targetRGBA_pilImage.putalpha( targetMask_pilImage )         # IN-PLACE METHOD
 311     
 312     return targetRGBA_pilImage
 313     
 314 #end def CombinePilImagesUsingMasks
 315 
 316 #------------------------------------------------------------------------------
 317 
 318 def CombineFileImagesUsingFileMasks( image1_filename, mask1_filename, 
 319                                      image2_filename, mask2_filename, 
 320                                      offset2=(0, 0) ) :
 321     """
 322     Combine file images into a single PilImage.
 323     Use file-based masks to determine the valid pxls in each image file.
 324     File2's opaque pixels are copied over File1's.
 325     
 326     The resultant image size will be the union of file1's area
 327     and the offset file2's area.
 328     """
 329     # File1 Image & Mask
 330     file1_pilImage = Image.open( image1_filename )
 331     if file1_pilImage.mode != 'RGB' :
 332         file1_pilImage = file1_pilImage.convert( 'RGB' )
 333     
 334     if ( mask1_filename ) :
 335         mask1_pilImage = Image.open( mask1_filename )
 336         if mask1_pilImage.mode != 'L' :
 337             mask1_pilImage = mask1_pilImage.convert( 'L' )
 338     else :
 339         mask1_bmap = CreateMaskBitmapFromFile( image1_filename, useTransparency=True )
 340         mask1_pilImage = ImgConv.PilImageFromWxBitmap( mask1_bmap )   # Always RGB
 341         mask1_pilImage = mask1_pilImage.convert( 'L' )
 342     #end if
 343     
 344     #------
 345     
 346     # File2 Image & Mask
 347     file2_pilImage = Image.open( image2_filename )
 348     if file2_pilImage.mode != 'RGB' :
 349         file2_pilImage = file2_pilImage.convert( 'RGB' )
 350     
 351     if ( mask2_filename ) :
 352         
 353         mask2_pilImage = Image.open( mask2_filename )
 354         if mask2_pilImage.mode != 'L' :
 355             mask2_pilImage = mask2_pilImage.convert( 'L' )
 356     else :
 357         
 358         mask2_bmap = CreateMaskBitmapFromFile( image2_filename, useTransparency=True )
 359         mask2_pilImage = ImgConv.PilImageFromWxBitmap( mask2_bmap )   # Always RGB
 360         mask2_pilImage = mask2_pilImage.convert( 'L' )
 361     #end if
 362     
 363     targetRGBA_pilImage = CombinePilImagesUsingMasks( file1_pilImage, mask1_pilImage, 
 364                                                       file2_pilImage, mask2_pilImage,
 365                                                       offset2 )
 366     return targetRGBA_pilImage
 367     
 368 #end def CombineFileImagesUsingFileMasks
 369 
 370 #------------------------------------------------------------------------------
 371 
 372 def GetTextExtent( text, fontSize=12, family=wx.DEFAULT, style=wx.NORMAL, weight=wx.NORMAL, 
 373                          underline=False, face='', encoding=wx.FONTENCODING_DEFAULT ) :
 374     
 375     
 376     textBmap = wx.EmptyBitmap( 0, 0 )   # Give a dummy size
 377     
 378     dc = wx.MemoryDC()                  # Pen and Brush are irrelevant.
 379     dc.SelectObject( textBmap )
 380     
 381     dc.SetBackgroundMode( wx.TRANSPARENT )  # wx.SOLID (BG will be painted) or wx.TRANSPARENT
 382     dc.SetTextBackground( wx.BLUE )         # Color is irrelevent - invisible because wx.TRANSPARENT
 383     
 384     # The pen and brush colors are irrelevant.
 385     dc.SetFont( wx.Font( fontSize, family, style, weight, underline, face, encoding ) )
 386     dc.SetTextForeground( (255, 255, 255) )
 387     textOffset = (0, 0)
 388     dc.DrawText( text, *textOffset )
 389     textExtent = dc.GetTextExtent( text )
 390     
 391     # The reported text extent is wrong !
 392     trueExtentX, trueExtentY = textExtent
 393     trueExtentX += 0
 394     trueExtentY += 0
 395     trueExtent = (trueExtentX, trueExtentY)
 396     
 397     # The apparent offset is wrong !
 398     # The offset where actual text writing must go into trueExtent.
 399     trueOffset = (0, 0)
 400     
 401     return (trueExtent, trueOffset)
 402     
 403 #end def GetTextExtent
 404 
 405 #------------------------------------------------------------------------------
 406 
 407 """
 408 AddSequences.py
 409 
 410 Ray Pasco
 411 pascor(at)verizon(dot)net
 412 
 413 2011-03-25  Rev. 1.0
 414 
 415 """
 416 
 417 def AddSequences( seq1, seq2 ) :
 418     """
 419     Sum the numerical values in 2 sequences. Either may be a tuple or a list. 
 420     The sequences may have different lengths.
 421     
 422     All values to be summed must be numerical, else the value None will be returned
 423       instead of a resulting sequence.
 424     
 425     If one list is longer its unassociated trailing elements will simply be 
 426     copied to the end of the returned sequence. Thus, the returned sequence size
 427     will always be the length of the longer sequence.
 428     
 429     The type of seq1 determines the returned sequence type (list or tuple).
 430     
 431     It's a shame that this isn't a Python builtin function !
 432     """
 433     #------------------------
 434     
 435     def IsNumeric( var ) :
 436         """
 437         It's a real shame that this isn't a Python builtin !
 438         """
 439         try:
 440             float( var )
 441             return True
 442         except ValueError:
 443             return False
 444         #end try
 445     #end def
 446     
 447     #------------------------
 448     
 449     # Temporarily convert any tuples into lists so they can be manipulated.
 450     list1 = seq1       
 451     outputType = 'list'            # First assume that it is a list.
 452     if type( seq1 ) == 'tuple' :   # Is it a tuple, instead ?
 453         list1 = list( seq1 )
 454         outputType = 'tuple'       # Set sequenceSum to this type on exit.
 455     #end if
 456     
 457     list2 = seq2
 458     if type( seq2 ) == 'tuple' :    
 459         list2 = list( seq2 )
 460     
 461     # Make sure both sequences contain all numerical values.
 462     seqIndex = 0
 463     for seq in (seq1, seq2) :           # iterate thru both sequences
 464         for i in xrange( len( seq ) ) :
 465             if not IsNumeric( seq[ i ] ) :
 466                 print '\n####  AddSequences():  Non-Numerical Value given in the',
 467                 if seqIndex == 0 :    print 'first',
 468                 else :                print 'second',
 469                 print 'sequence, index', i, ':'
 470                 print seq
 471                 return None
 472             #end if
 473         #end for
 474         seqIndex += 1       # move on to seq2
 475     #end for
 476     
 477     longerSeq  = seq1       # first assume seq1 is the longer
 478     shorterSeq = seq2
 479     if len( shorterSeq ) > len( longerSeq ) :    
 480         longerSeq  = seq2   # swap
 481         shorterSeq = seq1
 482     #end if
 483     
 484     seqSum = []
 485     for i in xrange( len( longerSeq ) ) :         # Iterate thru the longer sequence
 486         try :
 487             seqSum.append( longerSeq[ i ] + shorterSeq[ i ] )  # except if 2nd seq has no element at [i]
 488         except IndexError :
 489             seqSum.append( longerSeq[ i ] ) # just use the longer list's original value
 490         #end try
 491     #end for
 492     
 493     # seqSum is a list. Convert to a tuple according to outputType.
 494     if outputType == 'tuple' :    seqSum = tuple( seqSum )
 495         
 496     return seqSum
 497     
 498 #end def AddSequences
 499 
 500 #------------------------------------------------------------------------------
 501 
 502 def CreateDropshadowBitmap( text, textWxFont, textColor=(255, 255, 255), bgColor=(0, 0, 0) ) :
 503     """
 504     Create a bitmap of a text dropshadow. It is expected that the same text string
 505     is to be drawn on top using dc.DrawText()
 506     
 507     This backdrop needs to be offset from the actual text drawn 
 508     by the relative coord (-2, -2) to account for the increased dropshadow margins.
 509     """
 510     
 511     # Create a DC and an RGB bitmap larger than the expected maximum extent.
 512     fontSize = textWxFont.GetPointSize()
 513     textLen = len(text)
 514     sizeX = (fontSize * textLen * 4) /3         # empirical heuristic
 515     trialBmap_size = (sizeX, 500)
 516     textTrial_bmap = wx.EmptyBitmap( trialBmap_size[0], trialBmap_size[1] )
 517     
 518     dc = wx.MemoryDC( textTrial_bmap )
 519     dc.SetBrush( wx.Brush( bgColor, wx.SOLID) )
 520     dc.SetPen( wx.Pen( bgColor, 1) )
 521     dc.DrawRectangle( 0, 0, *trialBmap_size )
 522     dc.SetFont( textWxFont )
 523     dc.SetBackgroundMode( wx.TRANSPARENT )  # wx.SOLID or wx.TRANSPARENT
 524     dc.SetTextForeground( textColor )
 525     
 526     # Get the size of the needed bitmap.
 527     trialTextPosn = (25, 25)
 528     dc.DrawText( text, *trialTextPosn )
 529     trialTextExtent = dc.GetTextExtent( text )
 530     
 531     # The trialExtent X length is always short by 1 pixel.
 532     # Add more border to the bottom and the right sides.
 533     delta = max( 2, fontSize/10 )            # empirical heuristic 
 534     trialTextExtent = (trialTextExtent[0]+3*delta, trialTextExtent[1]+3*delta)
 535     
 536     dc.SelectObject( wx.NullBitmap )        # Done with this dc.
 537     
 538     #--------------
 539     
 540     # Create another enlarged RGB bitmap and a dc to draw the dropshadow onto.
 541     dropshadowSize = trialTextExtent
 542     dropshadow_bmap = wx.EmptyBitmap( dropshadowSize[0], dropshadowSize[1] )
 543     
 544     dc.SelectObject( dropshadow_bmap )
 545     dc.SetBrush (wx.Brush( bgColor, wx.SOLID))
 546     dc.SetPen( wx.Pen( bgColor, 1) )
 547     dc.DrawRectangle( 0, 0, *trialBmap_size )
 548     textOffsetIntoBmap = (delta, delta)   # Text center position
 549     textOffsetIntoBmapX, textOffsetIntoBmapY = textOffsetIntoBmap
 550     
 551     # The dropshadow offset positions coordinate list. 
 552     # This is why there is a +/- delta pxl border.
 553     skip = max( 1, fontSize/10 )
 554     offsetPosnList = []
 555     for i in range( 0-delta, delta+1, skip) :     # How much +/- to vary the text position
 556         for j in range( 0-delta, delta+1, skip) :
 557             offsetPosnList.append( (i, j)  )
 558         #end for
 559     #end for
 560     
 561     dc.SetBackgroundMode( wx.TRANSPARENT )  # wx.SOLID or wx.TRANSPARENT
 562     dc.SetTextBackground( wx.BLUE )   # Color is irrelevent; ivisible because wx.TRANSPARENT
 563     dc.SetTextForeground( textColor )
 564     
 565     #  Write the text string on it at all the text offset positions.
 566     for positionIndex in xrange( len( offsetPosnList ) ) :
 567     
 568         anOffsetX, anOffsetY = offsetPosnList[ positionIndex ]
 569         textPosn = (textOffsetIntoBmapX+anOffsetX, textOffsetIntoBmapY+anOffsetY)
 570         dc.DrawText( text, *textPosn )
 571         
 572     #end for
 573     dc.SelectObject( wx.NullBitmap )        # Close the DC to drawing.
 574     
 575     return (dropshadow_bmap, dropshadowSize, delta)
 576     
 577 #end def CreateDropshadowBitmap
 578 
 579 #------------------------------------------------------------------------------

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2011-04-02 19:08:14, 23.2 KB) [[attachment:BitmapManip.py]]
  • [get | view] (2011-03-27 19:21:24, 1.6 KB) [[attachment:DesktopScreenShotPIL.py]]
  • [get | view] (2012-12-25 18:23:31, 8.7 KB) [[attachment:ImgConv.py]]
  • [get | view] (2011-06-06 16:22:42, 4.6 KB) [[attachment:ScreenShotWX.py]]
  • [get | view] (2011-06-06 16:22:51, 3.9 KB) [[attachment:ScreenShotWX_Demo.py]]
  • [get | view] (2011-05-16 01:34:32, 8.5 KB) [[attachment:Win32IconImagePlugin.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.