libzipでzipファイルから画像データを取り出し、skiaでデコードし、wxWidgetsで表示する。
左右カーソルで画像切り替えをする。
zipから画像を取り出す関数群。
#pragma once #include <include/core/SkBitmap.h> #include <zip.h> #include <memory> #include <string> #include <vector> struct ImageData { std::unique_ptr<SkBitmap> bitmap; std::string filename; }; std::vector<ImageData> FilesInZip(const char* pathname); std::vector<std::uint8_t> GetZipData(zip_t* zipArchive, zip_int64_t index); std::unique_ptr<SkBitmap> ImageFromBinary(const std::vector<std::uint8_t>& contents);
#include <include/core/SkStream.h> #include <include/codec/SkCodec.h> #include <iostream> #include <zip.h> #include <vector> #include "LoadImageZip.hpp"
// zipファイルから画像データを取り出す std::vector<ImageData> FilesInZip(const char* pathname) { std::vector<ImageData> files; int error = 0; // zipファイルを読み取り専用で開く zip_t* zipArchive = zip_open(pathname, ZIP_RDONLY, &error); if (zipArchive == nullptr) { return std::vector<ImageData>(); } // zipファイル内のエントリ数を取得 zip_int64_t item_count = zip_get_num_entries(zipArchive, 0); // 各エントリの名前を取得して表示 for (zip_uint64_t i = 0; i < static_cast<zip_uint64_t>(item_count); ++i) { // ファイル名を取得 const char* file_name = zip_get_name(zipArchive, i, 0); // Zipファイル内のデータを取得 std::vector<std::uint8_t> binary = GetZipData(zipArchive, i); // バイナリデータから画像を作成 std::unique_ptr<SkBitmap> bitmap = ImageFromBinary(binary); // ファイル名と画像を一覧に追加 files.emplace_back(ImageData{ std::move(bitmap),file_name }); } // zipファイルを閉じる zip_close(zipArchive); return files; }
// zipファイルからバイナリデータを取得 std::vector<std::uint8_t> GetZipData(zip_t* zipArchive, zip_int64_t index) { struct zip_stat sb; zip_stat_index(zipArchive, index, 0, &sb); // 2番目のファイルのファイルサイズと同じメモリを確保する std::vector<std::uint8_t> contents(sb.size); // ファイルの内容をメモリに読み込む zip_file* zf = zip_fopen(zipArchive, sb.name, 0); zip_fread(zf, contents.data(), sb.size); zip_fclose(zf); return contents; }
// バイナリデータをSkiaの画像に変換 std::unique_ptr<SkBitmap> ImageFromBinary(const std::vector<std::uint8_t>& contents) { sk_sp<SkData> skdata = SkData::MakeWithoutCopy(contents.data(), contents.size()); if (!skdata) { std::cerr << "SkData作成に失敗しました" << std::endl; return nullptr; } // データからSkCodecを作成 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(skdata)); if (!codec) { return nullptr; } SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>(); if (!bitmap->tryAllocPixels(info)) { return nullptr; // メモリ確保に失敗 } SkCodec::Result ret = codec->getPixels( info, // 画像の情報 bitmap->getPixels(), // ロード先のメモリ bitmap->rowBytes() // ロード先の1行のバイト数 ); return bitmap; }
// https://docs.wxwidgets.org/3.0/overview_helloworld.html // プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 #ifdef _DEBUG #pragma comment(lib,"wxbase32ud.lib") #pragma comment(lib,"wxbase32ud_net.lib") #pragma comment(lib,"wxbase32ud_xml.lib") #pragma comment(lib,"wxmsw32ud_adv.lib") #pragma comment(lib,"wxmsw32ud_aui.lib") #pragma comment(lib,"wxmsw32ud_core.lib") #pragma comment(lib,"wxmsw32ud_gl.lib") #pragma comment(lib,"wxmsw32ud_html.lib") #pragma comment(lib,"wxmsw32ud_media.lib") #pragma comment(lib,"wxmsw32ud_propgrid.lib") #pragma comment(lib,"wxmsw32ud_qa.lib") #pragma comment(lib,"wxmsw32ud_ribbon.lib") #pragma comment(lib,"wxmsw32ud_richtext.lib") #pragma comment(lib,"wxmsw32ud_stc.lib") #pragma comment(lib,"wxmsw32ud_webview.lib") #pragma comment(lib,"wxmsw32ud_xrc.lib") #else #pragma comment(lib,"wxbase32u.lib") #pragma comment(lib,"wxbase32u_net.lib") #pragma comment(lib,"wxbase32u_xml.lib") #pragma comment(lib,"wxmsw32u_adv.lib") #pragma comment(lib,"wxmsw32u_aui.lib") #pragma comment(lib,"wxmsw32u_core.lib") #pragma comment(lib,"wxmsw32u_gl.lib") #pragma comment(lib,"wxmsw32u_html.lib") #pragma comment(lib,"wxmsw32u_media.lib") #pragma comment(lib,"wxmsw32u_propgrid.lib") #pragma comment(lib,"wxmsw32u_qa.lib") #pragma comment(lib,"wxmsw32u_ribbon.lib") #pragma comment(lib,"wxmsw32u_richtext.lib") #pragma comment(lib,"wxmsw32u_stc.lib") #pragma comment(lib,"wxmsw32u_webview.lib") #pragma comment(lib,"wxmsw32u_xrc.lib") #endif #if defined(_DEBUG) #pragma comment(lib, "skia.dll.lib") #pragma comment(lib, "skshaper.dll.lib") #else #pragma comment(lib, "skia.dll.lib") #endif #pragma comment(lib, "zip.lib") ///////////////////////////////////// #include <include/core/SkCanvas.h> #include <include/core/SkBitmap.h> #include <include/core/SkSurface.h> ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// #include "LoadImageZip.hpp" #include <string> // SkBitmapからRGBデータを取得 void PixelRGB(std::vector<std::uint8_t>& rgb, const SkBitmap& skbmp); // ウィンドウ作成 class MyFrame : public wxFrame { std::vector<ImageData> files; std::vector<wxBitmap> wxbitmaps; size_t index = 0; public: void ToBitmaps() { for (auto& file : files) { const SkBitmap& my_bitmap = *file.bitmap; int width = my_bitmap.width(); int height = my_bitmap.height(); std::vector<std::uint8_t> rgb; rgb.resize(width * height * 3); PixelRGB(rgb, my_bitmap); wxImage img(width, height, (unsigned char*)rgb.data(), true); wxBitmap wxbitmap(img); wxbitmaps.push_back(wxbitmap); } } void PostCreate() { files = FilesInZip("C:/temp/images.zip"); ToBitmaps(); index = 0; // OnPaintイベントを設定 Bind(wxEVT_PAINT, &MyFrame::OnPaint, this); // キーボードイベント Bind(wxEVT_KEY_DOWN, &MyFrame::OnKeyDown, this); this->Layout(); // レイアウトの更新 } // キーボードイベント void OnKeyDown(wxKeyEvent& event) { if (event.GetKeyCode() == WXK_RIGHT) { index++; if (index >= files.size()) { index = 0; } Refresh(); } else if (event.GetKeyCode() == WXK_LEFT) { if (index == 0) { index = files.size() - 1; } else { index--; } Refresh(); } } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); } // OnPaintイベント void OnPaint(wxPaintEvent& event) { if (wxbitmaps.empty()) { return; } const wxBitmap& wxbitmap = wxbitmaps[index]; // wxWidgetsのウィンドウに表示 wxPaintDC dc(this); dc.DrawBitmap(wxbitmap, 0, 0, true); } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(550, 550)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp); void PixelRGB(std::vector<std::uint8_t>& rgb, const SkBitmap& skbmp) { if (!skbmp.readyToDraw()) { return; } if (skbmp.colorType() != kRGBA_8888_SkColorType && skbmp.colorType() != kBGRA_8888_SkColorType) { return; } rgb.clear(); int Width = skbmp.width(); int Height = skbmp.height(); size_t rowBytes = skbmp.rowBytes(); const SkImageInfo& info = skbmp.info(); int channels = info.bytesPerPixel(); std::uint8_t* pixels = (std::uint8_t*)skbmp.getPixels(); rgb.resize(Width * Height * 3); for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { size_t pos_ppm = (i * Width + j) * 3; size_t pos_sk = (i * rowBytes + j * channels); rgb[pos_ppm + 0] = pixels[pos_sk + 2]; rgb[pos_ppm + 1] = pixels[pos_sk + 1]; rgb[pos_ppm + 2] = pixels[pos_sk + 0]; } } }