Blog posts

StegoCore – 3 tydzień, edycja zdjęć w .NET Core

StegoCore – 3 tydzień, edycja zdjęć w .NET Core

Daj Się Poznać 2017, dotnetcore

Czas na podsumowanie po kolejnym tygodniu prac nad StegoCore. W ostatnim poście projektowym skończyłem na tym, iż w końcu będę mógł zająć się biblioteką StegoCoreLib, służącą do ukrywania danych w plikach graficznych. Wcześniej jednak, musiałem zdecydować się na bibliotekę, której użyję do edycji zdjęć. Oczywiście, fajnie byłoby gdyby StegoCore była zależna tylko od standardowych bibliotek, ale nie chciałem tracić czasu pisanie własnego edytora zdjęć. Już prawie miesiąc, a backend prawie nie ruszony!

Długo nosiłem się z wyborem biblioteki. Wymagania, które musi spełniać to:

  • szybkość – szybko dostęp do pikseli zdjęcia
  • dostępność na .NET Core dla Windows, Linux i macOS
  • bezpieczeństwo

Ostatecznie zdecydowałem się na ImageSharp. Aktualnie jest ona jeszcze w fazie alpha, ale bardzo szybko się rozwija i do tego posiada już funkcjonalności, które są mi potrzebne. Mógłbym też skorzystać po prostu z System.Drawing, ale opinie o tej bibliotece nie są zbyt dobre. Została ona zaczerpnięta z Mono, jej źródła różnią się w zależności od systemu (Windows, Linux, Mac). ImageSharp jest niezależna od systemu, na którym jej używamy więc to duży plus. Dodatkowo podobno są kłopoty z wyciekami pamięci. Nauczony więc tym, że jeśli z czymś mogą być problemy – to na pewno będą, odrzuciłem ten wybór.

Konfiguracja ImageSharp

Aktualnie ImageSharp nie jest dostępna w menadżerze Nuget. Pojawi się tam wraz z pierwszą, oficjalną wersją biblioteki. Na szczęście nie musimy ściągać jej ręcznie i kompilować. Możemy wykorzystać menadżera MyGet. W tym celu w folderze projektu należy umieścić plik NuGet.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="ImageSharp Nightly" value="https://www.myget.org/F/imagesharp/api/v3/index.json" />
  </packageSources>
</configuration>

Teraz podczas uruchomienia dotnet restore , pod uwagę zostaną wzięte źródła z tego pliku. Możemy teraz dodać referencje do do biblioteki w naszym pliku konfiguracyjnego projektu:

<ItemGroup>
    <PackageReference Include="ImageSharp" Version="1.0.0-alpha2-00158" />
    <PackageReference Include="ImageSharp.Formats.Png" Version="1.0.0-alpha2-00154" />
    <PackageReference Include="ImageSharp.Formats.Bmp" Version="1.0.0-alpha2-00158" />  
    <PackageReference Include="ImageSharp.Formats.Jpeg" Version="1.0.0-alpha2-00158" />
    <PackageReference Include="ImageSharp.Processing" Version="1.0.0-alpha2-00146" />
</ItemGroup>

Biblioteka ImageSharp aktualnie jest podzielona na kilka mniejszych. Jeśli chcemy skorzystać, np. z metody umożliwiającej dostęp do pikseli zdjęcia czy odpowiednich formatów (jpeg, bmp, png) powinniśmy wskazać je osobno. Lista wszystkich dostępnych paczek dostępna jest na stronie MyGet.

Podczas dodawania biblioteki i jej paczek, miałem sporo problemów gdyż gryzły się ze sobą wersje kolejnych kompilacji. Na szczęście po kilku próbach udało mi się je odpowiednio dopasować. Wyżej wymieniona lista jest tą, którą aktualnie używam. Należy pamiętać o tym, aby zależności te znalazły się też w pliku konfiguracyjnym naszego projektu startowego. W moim przypadku obsługę plików graficznych umieściłem w projekcie StegoCoreLib, a projektem startowym jest StegoCoreWeb. Oznacza to, że w konfiguracji StegoCoreWeb również musimy dodać referencje do ImageSharp (sama referencja do StegoCoreLib nie wystarczy!). Jest to oczywista oczywistość, ale jako, że w VisualStudio, NuGet robi to za nas sam, kompletnie wyleciało mi to z głowy. Dwie godziny stracone na takim czymś, ehh!

Dostęp do pikseli

Moim celem jest ukrycie danych w pliku graficznym, nie zmieniając jego wielkości. Aby to zrobić muszę uzyskać dostęp do pikseli, a następnie je odpowiednio zmodyfikować. Można to zrobić przy użyciu ImageSharp.

var image = new Image(pathToImage); // utworzenie obiektu Image na podstawie ścieżki do zdjęcia
using (var pixels = image.Lock())
{
    pixels[0, 0] = new Color(255, 255, 255); // ustawienie koloru piksela
    var pixel = pixels[0, 1]; // pobranie pojedynczego piksela
    pixel.R += 1; // zwiększenie o 1
    pixels[0, 1] = pixel; // przypisanie zmodyfikowanego piksela
}

Dostęp ten jest bardzo szybki, gdyż jak zauważyłem biblioteka korzysta z unsafe code, czyli bezpośredniego dostępu do pamięci (wskaźniki).

Zmodyfikowany obraz możemy teraz zapisać do pliku lub pamięci.

Configuration.Default.AddImageFormat(new BmpFormat()); // ustawienie formatu wyjściowego pliku
image.Save(pathToOutput); // wskazanie ścieżki na dysku

using(var memory = new MemoryStream())
{
   result.Save(memory);
}

Co dalej?

Pomimo kilku kłopotów na początku, jestem zadowolony z wyboru ImageSharp jako biblioteki do edycji plików graficznych. Posiada to na czym mi najbardziej zależało, czyli szybki dostęp do pikseli zdjęcia.

Teraz czas na implementację pierwszego algorytmu: LSB, czyli ukrywania danych w najmniej znaczących bitach pikseli zdjęć. Aktualnie na githubie projektu znajduje się pierwsza wersja implementacji. Wymaga jeszcze kilku poprawek, ale jak tylko będzie gotowy to opisze go w na blogu.

Kolejnym krokiem będzie dodanie obsługi algorytmu do aplikacji webowej. Po uploadzie zdjęcia będzie możliwość wybrania algorytmu oraz pliku, który będzie można ukryć. Aktualna wersja StegoCoreWeb umożliwia jedynie upload pliku graficznego oraz jego usunięcie. Znajduje się pod adresem: http://pawelskaruz.pl:8080

About the author

Senior specialist, developer. Pasjonat programowania rozwijający się przy projektach komercyjnych oraz jako kontrybutor open source. W wolnym czasie lubi pobiegać za piłką, a także obejrzeć dobry film lub serial.

1 Comment

Leave a Comment

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *