2017-09-14 10 views
2

J'ai créé une application dans laquelle je veux afficher du texte sur google maps. J'ai choisi d'utiliser des marqueurs personnalisés, mais ils ne peuvent être que des images, j'ai donc décidé de créer une image à partir de mon texte en utilisant SkiaSharp.Comment puis-je me débarrasser des artefacts dans ImageSource créé avec SkiaSharp

private static ImageSource CreateImageSource(string text) 
    { 
     int numberSize = 20; 
     int margin = 5; 
     SKBitmap bitmap = new SKBitmap(30, numberSize + margin * 2, SKImageInfo.PlatformColorType, SKAlphaType.Premul); 
     SKCanvas canvas = new SKCanvas(bitmap); 

     SKPaint paint = new SKPaint 
     { 
      Style = SKPaintStyle.StrokeAndFill, 
      TextSize = numberSize, 
      Color = SKColors.Red, 
      StrokeWidth = 1, 
     }; 

     canvas.DrawText(text.ToString(), 0, numberSize, paint); 
     SKImage skImage = SKImage.FromBitmap(bitmap); 
     SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100); 
     return ImageSource.FromStream(data.AsStream); 
    } 

Les images que je créer ont cependant des artefacts disgracieux sur le dessus de l'image résultante et mon sentiment est qu'ils empirent si je crée plusieurs images. enter image description here J'ai construit un exemple d'application, qui montre les artefacts et le code que j'ai utilisé pour dessiner le texte. Il peut être trouvé ici: https://github.com/hot33331/SkiaSharpExample

Comment puis-je me débarrasser de ces artefacts. Est-ce que j'utilise skia mal?

+1

S'il vous plaît envoyez le code approprié dans votre question, ne faites pas seulement un lien vers une source externe et attendez-vous à prendre le temps de creuser votre code. Et si vous posez des questions spécifiques sur les "objets visuels", inclure une image montrant le problème serait une très bonne idée. – Jason

Répondre

1

J'ai obtenu la réponse suivante de Matthew Leibowitz sur le SkiaSharp GitHub:

Les chances sont que vous n'êtes pas Effacement de la toile/bitmap première.

Vous pouvez faire bitmap.Erase (SKColors.Transparent) ou canvas.Clear (SKColors.Transparent) (vous pouvez utiliser n'importe quelle couleur).

La raison en est la performance. Lors de la création d'un nouveau bitmap, l'ordinateur n'a aucun moyen de savoir quelle couleur d'arrière-plan vous voulez. Donc, si ça devait devenir transparent et que vous vouliez du blanc, alors il y aurait deux opérations de dessin pour effacer les pixels (et cela peut être très cher pour les grandes images).

Lors de l'allocation du bitmap, la mémoire est fournie, mais les données réelles ne sont pas touchées. S'il y avait quelque chose auparavant (ce qui sera le cas), ces données apparaissent sous forme de pixels colorés.

+0

C'est un comportement nouveau et amélioré, je pense, alors. Ce que j'avais vu dans le passé était que l'opération claire était ignorée sur une nouvelle surface de Skia, parce que c'était supposé être déjà clair. Si l'appel clair pour une nouvelle surface fonctionne correctement, alors ils doivent avoir fixé le comportement sous les couvertures, ce qui est génial. –

1

Quand je l'ai vu auparavant, c'est parce que la mémoire transmise à SkiaSharp n'était pas mise à zéro. Cependant, pour une optimisation, Skia suppose que le bloc de mémoire qui lui est passé est pré-mis à zéro. En conséquence, si votre première opération est un clear, il ignorera cette opération, car il pense que l'état est déjà propre. Pour résoudre ce problème, vous pouvez mettre à zéro manuellement la mémoire transmise à SkiaSharp.

public static SKSurface CreateSurface(int width, int height) 
    { 
     // create a block of unmanaged native memory for use as the Skia bitmap buffer. 
     // unfortunately, this may not be zeroed in some circumstances. 
     IntPtr buff = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(width * height * 4); 

     byte[] empty = new byte[width * height * 4]; 

     // copy in zeroed memory. 
     // maybe there's a more sanctioned way to do this. 
     System.Runtime.InteropServices.Marshal.Copy(empty, 0, buff, width * height * 4); 

     // create the actual SkiaSharp surface. 
     var colorSpace = CGColorSpace.CreateDeviceRGB(); 
     var bContext = new CGBitmapContext(buff, width, height, 8, width * 4, colorSpace, (CGImageAlphaInfo)bitmapInfo); 
     var surface = SKSurface.Create(width, height, SKColorType.Rgba8888, SKAlphaType.Premul, bitmap.Data, width * 4); 

     return surface; 
    } 

Édition: btw, je suppose que c'est un bug dans SkiaSharp. Les échantillons/API qui créent le tampon pour vous devriez probablement le mettre à zéro. En fonction de la plate-forme, il peut être difficile à reproduire car l'allocation mémoire se comporte différemment. Plus ou moins susceptible de vous fournir une mémoire intacte.