Mad Converter GIF'ok zu animierten Aufklebern für Telegramm

Anstelle von tausend Worten ...


xZibit freut sich auch, denn hier werden GIFs in Aufkleber eingefügt, um sie in GIFs für KDPV einzufügen!

Und nun zu den Implementierungsdetails.

Alles begann mit einer Diskussion im Chat des Telegrammentwicklers über die bevorstehende Funktion:

Bohdan Horbeshko, [04/04/19 20:21] Hmm, aber der Bot wird wahrscheinlich nur Gifs akzeptieren und dann konvertieren ... | Vitaly, [07/04/19 20:22] vom GIF an Jason? Ich hätte geschaut :))) | Bohdan Horbeshko, [04.07.19 20:22] Und warum nicht? In JSON gibt es einen PlayCanvas-Modelleditor. | Vitaly, [04/04/19 8:23 p.m.] und wie ist das GIF? Pixel für Pixel exportieren? :) | Bohdan Horbeshko, [04/04/19 20:24] Natürlich hat die IT-Welt solche Verzerrungen gesehen und wird sie nicht tolerieren.

Ein Mann sagte - ein Mann tat es! Der erste Prototyp in Pillow und svgwrite, bei dem GIFs in Pixel analysiert und in Vektorquadrate mit Vorschau in SVG konvertiert wurden, wurde an einem freien Tag geschrieben.

Der Spaß begann weiter ...

JSON ist ein offenes Format, sagten sie ...


Bis jetzt haben sie mit den Formaten in Telegram immer wieder ausgetrickst. Unterstützung für GIF-Animationen - tatsächlich werden sie in MP4-Video konvertiert. Unterstützung für Aufkleber - sie werden in PNG hochgeladen, aber in WebP konvertiert. Diesmal ist alles ehrlicher: am Eingang, dann am Ausgang.

Für animierte Aufkleber verwendet Telegram keine GIFs, Videos oder sogar ein etabliertes Vektorgrafikformat wie SVG oder, Gott bewahre Cthulhu! - Blitz. Es verwendet ein neues Format, das unter dem Flügel von Airbnb - Lottie entstanden ist. Bis jetzt war er unter den Entwicklern von Mobilgeräten bekannt, aber dank Telegram kann es an Popularität gewinnen.

Im Wesentlichen handelt es sich bei Lottie-Dateien um JSON-serialisierte Adobe After Effects-Projekte, die alle Funktionen dieses Programms maximieren. Mit dem Display ist leider nicht alles so rosig . Obwohl es viele vorgefertigte "offizielle" Implementierungen der Bibliothek zum Rendern von Lottie gibt, nur für die von Telegram abgedeckten Plattformen: Android, iOS, Qt und Web - nur ein Teil der Funktionen des Formats ist in allen implementiert. Telegram ging noch weiter und beschränkte die Liste der unterstützten Funktionen sowie ein eigenes Format, das sich vom üblichen Lottie nur durch das Einpacken von GZip und den Parameter "tgs": 1 . Ich glaube ich weiß wo Denis Popov jetzt arbeitet! :-)

Und wenn mit der Dokumentation für Bibliotheken für verschiedene Plattformen alles in Ordnung ist, war es leider nicht möglich, zumindest eine Beschreibung des Formatgeräts zu finden - nur das JSON-Schema in den Quellen von lottie-web. Ich musste auf dem Weg in vorhandenen Animationen basteln, um die allgemeinen Konzepte des Formats zu verstehen. Es gab auch Diskrepanzen zwischen realen Dateien und dem Schema: Insbesondere in Schichten vom Typ 4 werden gemäß dem Schema verschachtelte Objekte in der Eigenschaft "it" gespeichert. In realen Dateien heißt der Schlüssel jedoch "shapes" , und "it" funktioniert nicht.

Die geklärten Nuancen des Formats:

  • Eine Datei besteht aus Ebenen. Im Gegensatz zu GIF kann hier jede Ebene eine beliebige Start- und Endzeit für die Anzeige haben. Auf die Ebene können verschiedene Transformationen angewendet werden (genauer gesagt, dies ist erforderlich ): Skalieren, Drehen, Ändern der Transparenz usw. Ebenen können sogar dreidimensional sein (für Telegramm verboten).
  • Eine Ebene besteht aus „Formen“. Sie haben viele Arten, einige können nicht in Telegramm verwendet werden. In der Praxis sollte eine Ebene drei Formen enthalten: einen Pfad (in fertigen Animationen ist dies normalerweise der Typ "sh" - Bezier-Kurven; der Konverter verwendet bisher nur den Typ "rc" - Rechtecke), die Füllung (der Typ "fl" ) und die Transformation ( Typ "tr" ).
  • Sie können sogar Rasterelemente einfügen, Textebenen erstellen und durch Ausdrücke Beziehungen zwischen Ebenen- und Formparametern herstellen. All diese Leckereien sind auch im Telegramm verboten.

Das erste Problem folgt direkt von hier: Redundanz . Obwohl kürzlich Standardwerte für Transformationsparameter zum JSON-Schema hinzugefügt wurden, sind sie nicht in Bibliotheken implementiert. Es ist also immer noch notwendig, sie explizit zu fragen.

Es scheint, dass dies überhaupt kein Problem ist? Sogar ein einfacher GZip komprimiert sich offensichtlich wiederholende Daten gut, und 1 MB roher JSON verwandelt sich auf magische Weise in ein paar zehn Kilobyte, die sich leise in die angegebene Grenze von 64 kB einschleichen. Da war es!

Ich lade, was bedeutet, dass eine mollige Animation, die Lottie-Web in Telegram ruhig anzeigt - und hier anstelle einer bedingt schönen Pixelkunst der statische, verschwommene Blick auf mich lautet:



Was?! Es stellte sich jedoch heraus, dass die dekomprimierten Daten eindeutig auf 1 MB begrenzt sind. Ein Vertreter des Telegrammteams bestätigte dies schnell und kündigte die bevorstehende Erhöhung des Limits auf 2 MB an.

Selbst wenn sie diese Probleme lösen, können Benutzer älterer Versionen von Telegram nicht auf Aufkleber zugreifen, die über 1 MB unkomprimierter Daten hinausgehen und keine Transformationen enthalten. Es wird also wahrscheinlich in Zukunft die Einschränkungen einhalten müssen.

Transparenz ist wichtig.


Pillow kann zusammen mit OpenCV als Industriestandard für die Bildverarbeitung in Python bezeichnet werden. Darüber hinaus ist es auch für GIF-Funktionen gut geschärft: Es unterstützt indizierte Farben und ermöglicht den Zugriff auf die Palette. Es unterstützt die Konvertierung einer Pixelkarte in ein NumPy-Array, was für die produktive Verarbeitung wichtig ist. Sammelt sogar Statistiken über Farben! Es gab aber auch Nachteile:

  1. Es gab keine dokumentierte Möglichkeit, den transparenten Farbindex zu erhalten. Ich musste als vorübergehende Lösung annehmen, dass transparente Farben am häufigsten vorkommen, aber in echten GIFs ist dies nicht immer der Fall.
  2. Das Gleiche gilt für eine Verzögerung zwischen den Bildern: Pillow gibt nur die Bilder selbst als Folge von Bildern an, ohne Informationen über die Verzögerungen.
  3. Manchmal werden Teilbilder falsch überlagert.

Deshalb musste ich nach einem Ersatz suchen. Das gif2numpy- Modul hat so gehandelt. Es ist für GIF-Funktionen „geschärft“ und bietet Zugriff auf alle technischen Eigenschaften sowohl des Bilds als auch einzelner Frames, einschließlich GCE . Damit löst er das Problem der Leseverzögerungen.

Wie sich herausstellte, unterstützt gif2numpy die Transparenz überhaupt nicht: Farben werden sofort in drei Kanäle mit einer Bittiefe in Byte konvertiert, ohne die Bittiefe zu berücksichtigen und Farbindizes zu speichern. Glücklicherweise besteht das Modul aus einer Datei, sodass es nicht schwierig war, es in das Projekt aufzunehmen und zu ändern, indem die Farbe #FE00FE für Transparenz reserviert wurde.

Das Teilrahmenproblem war nicht trivial zu lösen. gif2numpy versucht, solche Frames mit dem vorherigen zu überlagern, überprüft jedoch nicht die Overlay-Parameter, weshalb auch nicht immer das richtige Ergebnis angezeigt wird. Um nicht mit Flags gifsicle , wird die vorläufige Bildverarbeitung mit gifsicle mit dem Schlüssel - --unoptimize wird --unoptimize - Teilbilder in Vollbilder konvertiert. Gleichzeitig wird die globale Palette verwendet, sodass die transparente Farbe bei Verwendung Ihrer eigenen Rahmenpalette nicht mehr separat verarbeitet werden muss.

Drück mich fester


Quadrate sind gut, aber mit solchen Einschränkungen müssen Sie mehr Vorstellungskraft zeigen, da sich sonst selbst Miniatur-GIFs nicht in das Telegramm „einschleichen“.

Zuerst wurde etwas Ähnliches wie RLE verwendet : Horizontal benachbarte Quadrate derselben Farbe werden zu einem Rechteck kombiniert.

Als nächstes folgt die Nutzung der Lottie-Funktionen. Da jede Ebene eine beliebige Start- und Endzeit hat, können Sie eine Technik anwenden, die seit langem von Videocodecs und teilweise im GIF selbst verwendet wird: Die Quadrate, die für mehrere Frames an derselben Stelle verbleiben, können zu einer Ebene zusammengeführt werden, während der sich die Anzeige ändert mehrere andere. Was bisher nur für Paare benachbarter Schichten implementiert ist.

Entwicklungspläne


Die Ideen, die hier angewendet werden können, sind in großen Mengen:

  • Erkennen Sie einfarbige Bereiche beliebiger Größe. Sie können sie in eine Reihe von Rechtecken aufteilen, für die es einen guten Algorithmus gibt . Es ist auch ratsam, sie in eine Kontur umzuwandeln, dies wird jedoch durch die Notwendigkeit überschattet, alle Punkte der Bezier-Kurven in Lottie anzugeben - Rechtecke können in einigen Fällen vorteilhafter sein.
  • Bewegung erkennen. Die Technik wird wiederum seit langem in Video-Codecs verwendet. Wenn dieselbe Kontur nicht die Form von Bild zu Bild ändert, sondern nur die Koordinaten - anstatt sie auf mehreren Ebenen zu duplizieren, platzieren Sie sie mit Transformation auf einer Ebene.
  • Erkennen Sie die „Bedeckung“ eines Bereichs mit einem anderen. Ein Beispiel:

     ...... .O..O. ...... .OOOO. ...... 

    Pixel einer anderen Farbe werden einem Rechteck einer Farbe überlagert. Anstatt dieses Rechteck in ein paar kleine zu zerlegen oder es in eine Kontur komplexer Form umzuwandeln, können Sie sie einfach über das gesamte Rechteck legen.
  • Vektorisierung von Kurven und Ellipsen, Erkennung von Gradienten. Dies wird den Pixel-Charme beeinträchtigen, aber die Komprimierbarkeit einiger GIFs um Größenordnungen verbessern. Gradienten sind sogar in den antidiluvianischen "Koloboks", das garantiere ich! : D.
  • Verlustbehaftete Komprimierung. Zuallererst wird die Beseitigung von Dithering und selbst bei übermäßig glatten Bildern die Mäßigung der Farbe nicht behindern. Das oben erwähnte Gifsicle wird wahrscheinlich damit umgehen.

Referenzen


  • Quellen . Stellenweise beängstigend.
  • Der Kanal, auf den ich Pakete erfolgreich konvertierter GIFs hochlade.

Source: https://habr.com/ru/post/de460411/


All Articles