awesome-inc / FontAwesome.Sharp

A library for using Font Awesome in WPF & Windows Forms applications
Apache License 2.0
383 stars 90 forks source link

Icon positioning in center bug #5

Closed VoidVolker closed 7 years ago

VoidVolker commented 7 years ago

I get issue with centering icon. Looks like it rendering not very accurate with paddings. Here the example: image

Icons have size 100x100 pixels. Control is inherited from IconPictureBox.

mkoertgen commented 7 years ago

Right now, i don't have much spare time on this project.

Please feel free to fork and fix. That would be great!

VoidVolker commented 7 years ago

I'm completed research and tested some variants of icon rendering: methods DrawString and DrawIcon can't align icons precicely, even with using StringFormat (only for DrawString) object with correct flags. And I found next solution:

TextRenderer.DrawText(
    graphics, 
    _iconText, _iconFont, 
    new Rectangle( 0, 0, Width, Height), 
    InActiveColor, 
    TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.NoPadding
 );

Result: image

This method require to rewrite some additional code and change the logic of icon rednering. I suggest next solution: for color use standard ForeColor variable and deprecate ActiveColor and InActiveColor variables, because they are not veru usefull. For example - I need to draw Icons in 5 colors: normal, hover, pressed, disabled, checked and all this drawnings are attached to standard events. And right now there only one method to change color: set both variables as one color. ActiveColor can be linked to ForeColor and what about InActiveColor - I'm not sure, may be leave it as is for some time for compability with old code and add method to disable it.

I just found FormsIconHelper class: there is using MeasureString - I checked this method early and it returns not accurate data. For example: for twitter icon this method this method returns 84,29687, 77,99999, but real icon size is 60x60.

mkoertgen commented 7 years ago

Great work! I agree that most of the time one wants icons centered. So we could add your solution.

mkoertgen commented 7 years ago

Concerning ActiveColor and InactiveColor: I think we can simply replace by ForeColor. Changing colors on hover seems to be supported only for buttons in Windows Forms.

VoidVolker commented 7 years ago

Ok, Then I'll create PR for for this case and add code for flip/rotate. For ActiveColor and InactiveColor I'll add depracation warnings and hide them from props grid in designer - in this case we can sure, that old applications with this library continue to work without bugs and some time later this variables can be removed completely.

VoidVolker commented 7 years ago

During many tests and experiments I meet a lot of bugs and issues: for example TextRenderer cant work correctly with matrix transforms - or only transforms with no icon precicely positioning or icon positioning without transforms. Artifacts example: image

All is complicated. For now I found only 2 variants:

I'm continue research and want to try SharpFont.

mkoertgen commented 7 years ago

I would recommend to avoid bindings to any native dependencies such as FreeType which is used with SharpFont.

Maybe the best bet is have the glyph rendered into an icon/bitmap (e.g. using TextRednerer) which then can be used in transforms, e.g. using Image.RotateFlip

VoidVolker commented 7 years ago

Yeah, think same. For case, when need trancparency color I suggest just to leave old logic under IconPictureBox2.

mkoertgen commented 7 years ago

Maybe we can use GDI TextRenderer for precisely renderering the glyph into an intermediate bitmap, then alpha blending it into the final Device Independent Bitmap (dib) with correct alpha/transparency?

This was suggested in this 10/2014 "Art of Dev" Blogpost: Transparent text rendering with GDI

However, it is not completely managed but uses some native P/Invokes into gdi32.dll. But this should be ok for users of Windows Forms.

VoidVolker commented 7 years ago

Yeah, I'm already found some similar code, thanks for link - I'll test it.

VoidVolker commented 7 years ago

Hooray! I get some results =) image Left icon have trasparent background and colored font. Right icon - transparent font color and colored background. Rendering logic is next:

  1. Render icon to separate memory buffer graphics with black and blue constant colors.
  2. For each pixel: move blue to alfa position and replace other 3 colors from icon by visible color (depends on what color is visible and what is transparent)
  3. Return result image.

This is short overall logic description - in real this is a bit more complicated and include checks for colors transparency and some additional code for native API calls import. COde is based from one of the SO answers.

Now I need add some additional code, some comments and make code cleaner. How shall I integrate this code? I'm thinking about replacing method ToBitmap, because my code returns Image object and add some features like rotation and flipping to uplevel controls, where ToBitmap is used.

mkoertgen commented 7 years ago

Fantastic! Glad you got it!

Concerning code integration: Yes, replacing ToBitmap would be exactly the right place, i.e.

For rotate/flip i would suggest adding to IFormsIcon interface, i.e.

Then, impementing in the uplevel controls like you said should be fine.

VoidVolker commented 7 years ago

Ok, I'll send you PR when complete with code. Also, how exactly shall I disable [In]ActiveColor variables: map them to font/back colors and add just build time warning about deprecation or I shall use error message instead? Warning:

[Obsolete("ActiveColor variable is deprecated, please use ForeColor instead. Thanks!")]

Error (compilation fail):

[Obsolete("ActiveColor variable is deprecated, please use ForeColor instead. Thanks!", true)]
mkoertgen commented 7 years ago

I don't think you need to spend too much energy on backwards compatibility. Most users i know of use WPF.

So instead of deprecating we might just replace the code and update the major version of FontAwesome.Sharp indicating a breaking change.

VoidVolker commented 7 years ago

Ok, then let's do it.

VoidVolker commented 7 years ago

A don't know how, but semitransparent white color on control over white color of it's parent is gray: image Image dump:

 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 68FFFFFF B2FFFFFF D9FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF E1FFFFFF D0FFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 7CFFFFFF E1FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF F8FFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF BDFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF F0FFFFFF D0FFFFFF BDFFFFFF BDFFFFFF BDFFFFFF D9FFFFFF F8FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF E9FFFFFF BDFFFFFF BDFFFFFF BDFFFFFF BDFFFFFF BDFFFFFF BDFFFFFF BDFFFFFF BDFFFFFF E1FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF F0FFFFFF 7CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF FFFFFFFF F0FFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF A7FFFFFF F8FFFFFF FFFFFFFF FFFFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF BDFFFFFF FFFFFFFF FFFFFFFF F8FFFFFF 7CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF C7FFFFFF FFFFFFFF FFFFFFFF D0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF FFFFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 7CFFFFFF F8FFFFFF FFFFFFFF F8FFFFFF 7CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 8CFFFFFF FFFFFFFF FFFFFFFF D0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF F8FFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 7CFFFFFF F8FFFFFF FFFFFFFF E9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF E9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F8FFFFFF FFFFFFFF D0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 8CFFFFFF FFFFFFFF FFFFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 8CFFFFFF FFFFFFFF FFFFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF A7FFFFFF FFFFFFFF FFFFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D9FFFFFF FFFFFFFF E9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF C7FFFFFF FFFFFFFF E9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F8FFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 9AFFFFFF FFFFFFFF FFFFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D9FFFFFF FFFFFFFF D9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF FFFFFFFF FFFFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF FFFFFFFF FFFFFFFF 9AFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF BDFFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF FFFFFFFF FFFFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF BDFFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF FFFFFFFF FFFFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF BDFFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E1FFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E9FFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F8FFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF E9FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F0FFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 7CFFFFFF FFFFFFFF FFFFFFFF 7CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 9AFFFFFF FFFFFFFF FFFFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF A7FFFFFF FFFFFFFF FFFFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF F0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F0FFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF F0FFFFFF FFFFFFFF E1FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 7CFFFFFF FFFFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 9AFFFFFF FFFFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF FFFFFFFF 7CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E9FFFFFF FFFFFFFF F0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF FFFFFFFF B2FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF FFFFFFFF BDFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E9FFFFFF FFFFFFFF FFFFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF E9FFFFFF FFFFFFFF FFFFFFFF E1FFFFFF 8CFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 8CFFFFFF E9FFFFFF FFFFFFFF FFFFFFFF D0FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF A7FFFFFF F8FFFFFF FFFFFFFF FFFFFFFF A7FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF D0FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF E9FFFFFF BDFFFFFF 8CFFFFFF 8CFFFFFF 9AFFFFFF BDFFFFFF E9FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF E1FFFFFF 8CFFFFFF 8CFFFFFF 8CFFFFFF 8CFFFFFF 8CFFFFFF 8CFFFFFF 8CFFFFFF A7FFFFFF D0FFFFFF F8FFFFFF FFFFFFFF FFFFFFFF F8FFFFFF 9AFFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 9AFFFFFF F0FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF D0FFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 9AFFFFFF D0FFFFFF E9FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF F8FFFFFF E1FFFFFF B2FFFFFF 68FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF
 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF 00FFFFFF

Short version with only alfa (all other colors is 0xFFFFFF in all cells):

 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 68 B2 D9 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 E1 D0 A7 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 7C E1 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8 BD 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 BD FF FF FF F0 D0 BD BD BD D9 F8 FF FF FF E9 BD BD BD BD BD BD BD BD E1 FF FF FF F0 7C 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 D0 FF FF F0 A7 00 00 00 00 00 00 00 A7 F8 FF FF A7 00 00 00 00 00 00 00 00 00 BD FF FF F8 7C 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 C7 FF FF D0 00 00 00 00 00 00 00 00 00 00 00 E1 FF FF A7 00 00 00 00 00 00 00 00 00 7C F8 FF F8 7C 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 8C FF FF D0 00 00 00 00 00 00 00 00 00 00 00 00 00 E1 FF F8 68 00 00 00 00 00 00 00 00 00 7C F8 FF E9 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 E1 FF E9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F8 FF D0 00 00 00 00 00 00 00 00 00 00 8C FF FF A7 00 00 00 00 00 00 00
 00 00 00 00 00 8C FF FF 8C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A7 FF FF 68 00 00 00 00 00 00 00 00 00 00 D9 FF E9 00 00 00 00 00 00 00
 00 00 00 00 00 C7 FF E9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F8 FF B2 00 00 00 00 00 00 00 00 00 00 9A FF FF 68 00 00 00 00 00 00
 00 00 00 00 00 E1 FF BD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D9 FF D9 00 00 00 00 00 00 00 00 00 00 00 FF FF A7 00 00 00 00 00 00
 00 00 00 00 00 FF FF 9A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BD FF E1 00 00 00 00 00 00 00 00 00 00 00 E1 FF BD 00 00 00 00 00 00
 00 00 00 00 00 FF FF 8C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BD FF E1 00 00 00 00 00 00 00 00 00 00 00 E1 FF BD 00 00 00 00 00 00
 00 00 00 00 00 FF FF 8C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BD FF E1 00 00 00 00 00 00 00 00 00 00 00 E1 FF BD 00 00 00 00 00 00
 00 00 00 00 00 E9 FF BD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0 FF E1 00 00 00 00 00 00 00 00 00 00 00 F8 FF B2 00 00 00 00 00 00
 00 00 00 00 00 D0 FF E9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 FF B2 00 00 00 00 00 00 00 00 00 00 7C FF FF 7C 00 00 00 00 00 00
 00 00 00 00 00 9A FF FF 8C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A7 FF FF 68 00 00 00 00 00 00 00 00 00 00 D0 FF F0 00 00 00 00 00 00 00
 00 00 00 00 00 00 F0 FF E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 FF E1 00 00 00 00 00 00 00 00 00 00 7C FF FF B2 00 00 00 00 00 00 00
 00 00 00 00 00 00 9A FF FF B2 00 00 00 00 00 00 00 00 00 00 00 00 00 D0 FF FF 7C 00 00 00 00 00 00 00 00 00 00 E9 FF F0 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 D0 FF FF B2 00 00 00 00 00 00 00 00 00 00 00 D0 FF FF BD 00 00 00 00 00 00 00 00 00 00 E9 FF FF 8C 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 E9 FF FF E1 8C 00 00 00 00 00 00 00 8C E9 FF FF D0 00 00 00 00 00 00 00 00 00 A7 F8 FF FF A7 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 D0 FF FF FF E9 BD 8C 8C 9A BD E9 FF FF FF E1 8C 8C 8C 8C 8C 8C 8C A7 D0 F8 FF FF F8 9A 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 9A F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF D0 68 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 9A D0 E9 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8 E1 B2 68 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

So, what you think about this effect? Looks like this bug is in GDI rendering logic. Also, transparent color is replacing to next colors: parent's background pixel color or parent's background image pixel. Even under this control can be other control.

Basically, I don't need transparent color - I'm just researching strange behaviour of controls rendering engine. So, I just leave current state of code as is - it isn't perfect, but it place icon in center and give feature to place icons on images without colored border (image control background). In other cases - trasparent color is useless.

mkoertgen commented 7 years ago

Looks like typical premultiplied alpha. Seems fine to me. Who would use semitransparent as foreground color, anyway?

VoidVolker commented 7 years ago

Checked GDI+ logic - this bug is fixed, so yes, this is bug of old GDI API. Currently I have 2 solutions:

  1. GDI+:
    • Render icon
    • Measure icon via manual all pixels color check
    • Get icon paddings - top, right, bottom, left
    • Render icon second time with correct icon offset
  2. Render with GDI:
    • Render icon with black and white colors
    • For each pixel - move white color to alfa position and set RGB values from visible color

In some cases variant 1 can place icon not perfectly, and second variant is always place icon perfectly and require double rendering, but in some cases can give not perfect icons rendering, because it is old API. In variant 1 double rendering can be removed, if calculate icons size before lib compilation and save sizes in some structure.

mkoertgen commented 7 years ago

Good work. My thoughts:

  1. Measure paddings by iterating on GDI+ bitmap pixels might be extremely slow. This might probably not hurt too bad since most icons should be small (<= 256x256).

    • precalculation of icon sizes/offset: I'm thinking on how to automate this in the build process. Scanning the font is done using t4-templates which requires manual intervention.
  2. Most icons should be ok, since semi-transparent pixels are not spuported in ttf, i think. However, i agree that we should avoid relying too much on old/obsolete APIs.

mkoertgen commented 7 years ago

Maybe i have time to do some experiments myself this weekend.

Double-pass rendering or using pre-compiled font-specific lookup tables seem a bit too complicated for my taste.

My preference would be a more simple & elegant solution (so corner-case bugs won't have much space to hide).

mkoertgen commented 7 years ago

Can you share your current state of implementation (fork/branch) so i might look into it?

VoidVolker commented 7 years ago

Almost done: https://github.com/VoidVolker/FontAwesome.Sharp/commit/8e2131c8c9eeea71e8bf458b3be49804120e900e Please, check this code and if all ok - I'll send you PR. I added one new method Icon.ToBitMap1(size, color, bgColor) and used it in IconPictureBox. For small icons GDI+ is still better. Maybe, when I have time - I'll add tt template for creating list of icons sizes. Then, solution will be next:

Here the code for getting icon real size:

var bitmap = new Bitmap(size, size);
using (var graphics = Graphics.FromImage(bitmap))
{
      font = GetAdjustedIconFont(graphics, text, size, size);

      graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
      graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
      graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
      graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

      graphics.Clear(bgColor);

      graphics.DrawString(
            text, font,
            new SolidBrush(color),
            size / 2, size / 2,
            format
      );

      int newX = 0, newY = 0;
      // This logic is recomended on StackOverflow 
      // for pixel processing because GetPixel is slow.
      unsafe
      {
            // Image prepare 
            BitmapData imageData = bitmap.LockBits(
                  new Rectangle(0, 0, size, size),
                  ImageLockMode.ReadOnly,
                  PixelFormat.Format32bppArgb
            );

            // variables init
            int x = 0,
                 y = 0,
                 top = size,
                 right = 0,
                 bottom = 0,
                 left = size
            ;

            uint c = 0,
                  backARGB = (uint)bgColor.ToArgb(),
                  stride = (uint)size; // imageData.Stride / 4 ; 4 = bytes per pixel, as result stride is equals width in pixels
            ;

            // StringBuilder s = new StringBuilder();

            uint* currentRow = (uint*)imageData.Scan0;
            uint* lastRow = currentRow + size * stride;

            // Here is 2 cycles because bmp format can contain 
            // empty bytes in the end of pixels horizontal string
            // and I'm not sure if bytes in memory can or can't
            // have similar structure.
            for (y = 0; y < size; y++)
            {
                  for (x = 0; x < size; x++)
                  {
                        c = currentRow[x];
                        if (c != backARGB)
                        {
                              top = Math.Min(y, top);
                              right = Math.Max(x, right);
                              bottom = Math.Max(y, bottom);
                              left = Math.Min(x, left);
                        }
                        // s.Append(c.ToString("X"));
                        // s.Append(" ");
                  }
                  currentRow += stride;
                  // s.Append("\n");
            }

            // s.Append("\n\n\n");
            // Debug.WriteLine(s.ToString());
            // Debug.WriteLine("size, top, right, bottom, left: " + size + " | " + top + ", " + (size - right) + ", " + (size - bottom) + ", " + left);

            bitmap.UnlockBits(imageData);

            float fx = (size - right - left) / 2 + size / 2;
            float fy = (size - bottom - top) / 2 + size / 2;

            newX = (int)Math.Ceiling(fx);
            newY = (int)Math.Ceiling(fy);
      }

      graphics.Clear(bgColor);
      graphics.DrawString(
             text, font,
             new SolidBrush(color),
             newX, newY,
             format
      );
}
mkoertgen commented 7 years ago

Looks ok to me. Iterating over pixels should be fast enough. Maybe add some robustness, i.e.


... bitmap.LockBits
try 
{ 
... 
}
finally { bitmap.UnlockBits(...) }
VoidVolker commented 7 years ago

Yes, this is fastest solution what I found - also, this loop will run only for transparent color case. Ok, I'll add.

VoidVolker commented 7 years ago

Done: https://github.com/VoidVolker/FontAwesome.Sharp/commits/develop Also I added icon cacher - check it please. I think icon caching allow to use manual size calculation. I need some time for tt logic research and how to calculate icon size int tt. Can you give me some comments about how exactly you load font and why so complicated? I'm used simple load to memory from resources. But, for unknow reason now I have some strange error with rendering FA icon on label - I'm tried to use label and default font rednering. It was working, but now not working. I'm using next code for fonts and fonts caching:

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Text;
    using System.Runtime.InteropServices;

    /// <summary>
    /// Fonts management
    /// </summary>
    public static class Fonts
    {
        /// <summary>
        /// Font sCache 
        /// </summary>
        public static FontsCache FontAwesome = new FontsCache(Properties.Resources.fontawesome_webfont);

        /// <summary>
        /// Load font
        /// </summary>
        /// <param name="fontData"></param>
        /// <returns>FontFamily</returns>
        public static FontFamily LoadFont(PrivateFontCollection pfc, byte[] fontData)
        {
            int len = fontData.Length;

            // create an unsafe memory block for the font data
            System.IntPtr data = Marshal.AllocCoTaskMem(len);

            // copy the bytes to the unsafe memory block
            Marshal.Copy(fontData, 0, data, len);

            // pass the font to the font collection
            pfc.AddMemoryFont(data, len);

            Marshal.FreeCoTaskMem(data);

            return pfc.Families[pfc.Families.Length - 1];
        }

        /// <summary>
        /// Fonts Cache
        /// </summary>
        public class FontsCache
        {
            private PrivateFontCollection pfc = new PrivateFontCollection();
            private Dictionary<int, Font> сacheRegular = new Dictionary<int, Font>();
            private Dictionary<int, Font> сacheBold = new Dictionary<int, Font>();

            /// <summary>
            /// Семейство шрифта
            /// </summary>
            public FontFamily Family;

            /// <summary>
            /// Get font of size pixels
            /// </summary>
            /// <param name="size"></param>
            /// <param name="style"></param>
            /// <returns></returns>
            public Font this[int size, FontStyle style = FontStyle.Regular]
            {
                get
                {
                    var cache = сacheRegular;
                    if (style == FontStyle.Bold)
                    {
                        cache = сacheBold;
                    }
                    if (!cache.TryGetValue(size, out Font f))
                    {
                        f = new Font(Family, size, style);
                        cache[size] = f;
                    }
                    return f;
                }
                private set
                {
                    // cache[size] = new Font(Vars.fontFamily, size, style, GraphicsUnit.Pixel);
                }
            }

            public FontsCache(byte[] fontData)
            {
                Family = LoadFont(pfc, fontData);
                //MessageBox.Show("FontsCache: " + family.Name);
            }
        }
    }
mkoertgen commented 7 years ago

I will try to find time this weekend.

mkoertgen commented 7 years ago

Meantime, you may open a pull request (with wip), cf.: How to write the perfect pull request

So we can discuss & review code better.