Skip to content

Commit

Permalink
v1.7: 1.支持SVG,2.处理EXIF旋转方向
Browse files Browse the repository at this point in the history
jark006 committed Jul 22, 2024
1 parent 7ffe249 commit 1357941
Showing 12 changed files with 296 additions and 7 deletions.
Binary file modified jarkViewer/file/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified jarkViewer/file/home.psd
Binary file not shown.
Binary file modified jarkViewer/file/tips.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified jarkViewer/file/tips.psd
Binary file not shown.
74 changes: 73 additions & 1 deletion jarkViewer/include/ImageDatabase.h
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ class ImageDatabase{
L".pbm", L".pgm", L".ppm", L".pxm",L".pnm",L".sr", L".ras",
L".exr", L".tiff", L".tif", L".webp", L".hdr", L".pic",
L".heic", L".heif", L".avif", L".avifs", L".gif", L".jxl",
L".ico", L".icon", L".psd", L".tga"
L".ico", L".icon", L".psd", L".tga", L".svg"
};

static inline const unordered_set<wstring> supportRaw {
@@ -1022,6 +1022,40 @@ class ImageDatabase{
return final_result;
}

static cv::Mat loadSVG(const wstring& path, const vector<uchar>& buf, int fileSize){
const int maxEdge = 1024;

auto document = lunasvg::Document::loadFromData((const char*)buf.data(), buf.size());
if (!document) {
Utils::log("Failed to load SVG data {}", Utils::wstringToUtf8(path));
return cv::Mat();
}

// 宽高比例
const double AspectRatio = (document->height() == 0) ? 1 : (document->width() / document->height());
int height, width;

if (AspectRatio == 1) {
height = width = maxEdge;
}
else if (AspectRatio > 1) {
width = maxEdge;
height = int(maxEdge / AspectRatio);
}
else {
height = maxEdge;
width = int(maxEdge * AspectRatio);
}

auto bitmap = document->renderToBitmap(width, height);
if (!bitmap.valid()) {
Utils::log("Failed to render SVG to bitmap {}", Utils::wstringToUtf8(path));
return cv::Mat();
}

return cv::Mat(height, width, CV_8UC4, bitmap.data()).clone();
}

static vector<cv::Mat> loadMats(const wstring& path, const vector<uchar>& buf, int fileSize) {
vector<cv::Mat> imgs;

@@ -1426,6 +1460,13 @@ class ImageDatabase{
else if (ext == L".tga") {
img = loadTGA(path, buf, fileSize);
}
else if (ext == L".svg") {
img = loadSVG(path, buf, fileSize);
ret.exifStr = ExifParse::getSimpleInfo(path, img.cols, img.rows, buf.data(), fileSize);
if (img.empty()) {
img = getDefaultMat();
}
}
else if (ext == L".ico" || ext == L".icon") {
img = loadICO(path, buf, fileSize);
ret.exifStr = ExifParse::getSimpleInfo(path, img.cols, img.rows, buf.data(), fileSize);
@@ -1456,6 +1497,37 @@ class ImageDatabase{
if (img.channels() == 1)
cv::cvtColor(img, img, cv::COLOR_GRAY2BGR);

const size_t idx = ret.exifStr.find("方向: ");
if (idx != string::npos) {
int exifOrientation = ret.exifStr[idx + 8] - '0';

switch (exifOrientation) {
case 2: // 水平翻转
cv::flip(img, img, 1);
break;
case 3: // 旋转180度
cv::rotate(img, img, cv::ROTATE_180);
break;
case 4: // 垂直翻转
cv::flip(img, img, 0);
break;
case 5: // 顺时针旋转90度后垂直翻转
cv::rotate(img, img, cv::ROTATE_90_CLOCKWISE);
cv::flip(img, img, 0);
break;
case 6: // 顺时针旋转90度
cv::rotate(img, img, cv::ROTATE_90_CLOCKWISE);
break;
case 7: // 顺时针旋转90度后水平翻转
cv::rotate(img, img, cv::ROTATE_90_CLOCKWISE);
cv::flip(img, img, 1);
break;
case 8: // 逆时针旋转90度
cv::rotate(img, img, cv::ROTATE_90_COUNTERCLOCKWISE);
break;
}
}

ret.imgList.emplace_back(img, 0);

return ret;
1 change: 1 addition & 0 deletions jarkViewer/include/Utils.h
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ using std::endl;
#include "png.h"
#include "pngstruct.h"
#include "psdsdk.h"
#include "lunasvg.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
218 changes: 218 additions & 0 deletions jarkViewer/include/lunasvg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2020 Nwutobo Samuel Ugochukwu <sammycageagle@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef LUNASVG_H
#define LUNASVG_H

#include <memory>
#include <string>
#include <cstdint>

#if defined(_MSC_VER) && defined(LUNASVG_SHARED)
#ifdef LUNASVG_EXPORT
#define LUNASVG_API __declspec(dllexport)
#else
#define LUNASVG_API __declspec(dllimport)
#endif
#else
#define LUNASVG_API
#endif

namespace lunasvg {

class Rect;
class Matrix;

class LUNASVG_API Box {
public:
Box() = default;
Box(double x, double y, double w, double h);
Box(const Rect& rect);

Box& transform(const Matrix& matrix);
Box transformed(const Matrix& matrix) const;

public:
double x{0};
double y{0};
double w{0};
double h{0};
};

class Transform;

class LUNASVG_API Matrix {
public:
Matrix() = default;
Matrix(double a, double b, double c, double d, double e, double f);
Matrix(const Transform& transform);

Matrix& rotate(double angle);
Matrix& rotate(double angle, double cx, double cy);
Matrix& scale(double sx, double sy);
Matrix& shear(double shx, double shy);
Matrix& translate(double tx, double ty);
Matrix& transform(double a, double b, double c, double d, double e, double f);
Matrix& identity();
Matrix& invert();

Matrix& operator*=(const Matrix& matrix);
Matrix& premultiply(const Matrix& matrix);
Matrix& postmultiply(const Matrix& matrix);

Matrix inverted() const;
Matrix operator*(const Matrix& matrix) const;

static Matrix rotated(double angle);
static Matrix rotated(double angle, double cx, double cy);
static Matrix scaled(double sx, double sy);
static Matrix sheared(double shx, double shy);
static Matrix translated(double tx, double ty);

public:
double a{1};
double b{0};
double c{0};
double d{1};
double e{0};
double f{0};
};

class LUNASVG_API Bitmap {
public:
/**
* @note Bitmap format is ARGB32 Premultiplied.
*/
Bitmap();
Bitmap(std::uint8_t* data, std::uint32_t width, std::uint32_t height, std::uint32_t stride);
Bitmap(std::uint32_t width, std::uint32_t height);

void reset(std::uint8_t* data, std::uint32_t width, std::uint32_t height, std::uint32_t stride);
void reset(std::uint32_t width, std::uint32_t height);

std::uint8_t* data() const;
std::uint32_t width() const;
std::uint32_t height() const;
std::uint32_t stride() const;

void clear(std::uint32_t color);
void convert(int ri, int gi, int bi, int ai, bool unpremultiply);
void convertToRGBA() { convert(0, 1, 2, 3, true); }

bool valid() const { return !!m_impl; }

private:
struct Impl;
std::shared_ptr<Impl> m_impl;
};

class LayoutSymbol;

class LUNASVG_API Document {
public:
/**
* @brief Creates a document from a file
* @param filename - file to load
* @return pointer to document on success, otherwise nullptr
*/
static std::unique_ptr<Document> loadFromFile(const std::string& filename);

/**
* @brief Creates a document from a string
* @param string - string to load
* @return pointer to document on success, otherwise nullptr
*/
static std::unique_ptr<Document> loadFromData(const std::string& string);

/**
* @brief Creates a document from a string data and size
* @param data - string data to load
* @param size - size of the data to load, in bytes
* @return pointer to document on success, otherwise nullptr
*/
static std::unique_ptr<Document> loadFromData(const char* data, std::size_t size);

/**
* @brief Creates a document from a null terminated string data
* @param data - null terminated string data to load
* @return pointer to document on success, otherwise nullptr
*/
static std::unique_ptr<Document> loadFromData(const char* data);

/**
* @brief Sets the current transformation matrix of the document
* @param matrix - current transformation matrix
*/
void setMatrix(const Matrix& matrix);

/**
* @brief Returns the current transformation matrix of the document
* @return the current transformation matrix
*/
Matrix matrix() const;

/**
* @brief Returns the smallest rectangle in which the document fits
* @return the smallest rectangle in which the document fits
*/
Box box() const;

/**
* @brief Returns width of the document
* @return the width of the document in pixels
*/
double width() const;

/**
* @brief Returns the height of the document
* @return the height of the document in pixels
*/
double height() const;

/**
* @brief Renders the document to a bitmap
* @param matrix - the current transformation matrix
* @param bitmap - target image on which the content will be drawn
*/
void render(Bitmap bitmap, const Matrix& matrix = Matrix{}) const;

/**
* @brief Renders the document to a bitmap
* @param width - maximum width, in pixels
* @param height - maximum height, in pixels
* @param backgroundColor - background color in 0xRRGGBBAA format
* @return the raster representation of the document
*/
Bitmap renderToBitmap(std::uint32_t width = 0, std::uint32_t height = 0, std::uint32_t backgroundColor = 0x00000000) const;

Document(Document&&);
~Document();

private:
Document();

std::unique_ptr<LayoutSymbol> root;
};

} //namespace lunasvg

#endif // LUNASVG_H
Binary file modified jarkViewer/jarkViewer.aps
Binary file not shown.
Binary file modified jarkViewer/jarkViewer.rc
Binary file not shown.
4 changes: 2 additions & 2 deletions jarkViewer/jarkViewer.vcxproj
Original file line number Diff line number Diff line change
@@ -90,7 +90,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>IlmImf.lib;ippiw.lib;ippicvmt.lib;libjpeg-turbo.lib;libopenjp2.lib;libpng.lib;libprotobuf.lib;libtiff.lib;libwebp.lib;opencv_world4100.lib;zlib.lib;ittnotify.lib;heif.lib;libde265.lib;x265-static.lib;avif.lib;yuv.lib;dav1d.lib;aom.lib;gif.lib;raw.lib;OpenGL32.Lib;GlU32.Lib;freeglut.lib;lcms2.lib;jasper.lib;brotlicommon.lib;brotlidec.lib;brotlienc.lib;charset.lib;exiv2.lib;iconv.lib;inih.lib;INIReader.lib;intl.lib;libexpatMT.lib;Psapi.lib;jxl.lib;jxl_cms.lib;jxl_threads.lib;hwy.lib;libpng16.lib;FreeImage.lib;FreeImagePlus.lib;pixman-1.lib;fontconfig.lib;Psd_MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>IlmImf.lib;ippiw.lib;ippicvmt.lib;libjpeg-turbo.lib;libopenjp2.lib;libpng.lib;libprotobuf.lib;libtiff.lib;libwebp.lib;opencv_world4100.lib;zlib.lib;ittnotify.lib;heif.lib;libde265.lib;x265-static.lib;avif.lib;yuv.lib;dav1d.lib;aom.lib;gif.lib;raw.lib;OpenGL32.Lib;GlU32.Lib;freeglut.lib;lcms2.lib;jasper.lib;brotlicommon.lib;brotlidec.lib;brotlienc.lib;charset.lib;exiv2.lib;iconv.lib;inih.lib;INIReader.lib;intl.lib;libexpatMT.lib;Psapi.lib;jxl.lib;jxl_cms.lib;jxl_threads.lib;hwy.lib;libpng16.lib;FreeImage.lib;FreeImagePlus.lib;pixman-1.lib;fontconfig.lib;Psd_MT.lib;lunasvg.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<StackReserveSize>8388608</StackReserveSize>
</Link>
@@ -127,7 +127,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>IlmImf.lib;ippiw.lib;ippicvmt.lib;libjpeg-turbo.lib;libopenjp2.lib;libpng.lib;libprotobuf.lib;libtiff.lib;libwebp.lib;opencv_world4100.lib;zlib.lib;ittnotify.lib;heif.lib;libde265.lib;x265-static.lib;avif.lib;yuv.lib;dav1d.lib;aom.lib;gif.lib;raw.lib;OpenGL32.Lib;GlU32.Lib;freeglut.lib;lcms2.lib;jasper.lib;brotlicommon.lib;brotlidec.lib;brotlienc.lib;charset.lib;exiv2.lib;iconv.lib;inih.lib;INIReader.lib;intl.lib;libexpatMT.lib;Psapi.lib;jxl.lib;jxl_cms.lib;jxl_threads.lib;hwy.lib;libpng16.lib;FreeImage.lib;FreeImagePlus.lib;pixman-1.lib;fontconfig.lib;Psd_MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>IlmImf.lib;ippiw.lib;ippicvmt.lib;libjpeg-turbo.lib;libopenjp2.lib;libpng.lib;libprotobuf.lib;libtiff.lib;libwebp.lib;opencv_world4100.lib;zlib.lib;ittnotify.lib;heif.lib;libde265.lib;x265-static.lib;avif.lib;yuv.lib;dav1d.lib;aom.lib;gif.lib;raw.lib;OpenGL32.Lib;GlU32.Lib;freeglut.lib;lcms2.lib;jasper.lib;brotlicommon.lib;brotlidec.lib;brotlienc.lib;charset.lib;exiv2.lib;iconv.lib;inih.lib;INIReader.lib;intl.lib;libexpatMT.lib;Psapi.lib;jxl.lib;jxl_cms.lib;jxl_threads.lib;hwy.lib;libpng16.lib;FreeImage.lib;FreeImagePlus.lib;pixman-1.lib;fontconfig.lib;Psd_MT.lib;lunasvg.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<LinkTimeCodeGeneration>UseFastLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<StackReserveSize>8388608</StackReserveSize>
Binary file modified jarkViewer/lib/lib.7z
Binary file not shown.
6 changes: 2 additions & 4 deletions jarkViewer/src/jarkViewer.cpp
Original file line number Diff line number Diff line change
@@ -6,9 +6,7 @@

/*
TODO
1. exif 的旋转信息
2. avif crop 无法解码 kimono.crop.avif
3. 重构程序结构
1. 重构程序结构(当前快速拖动会画面撕裂), 换UI框架
*/

const int BG_GRID_WIDTH = 8;
@@ -20,7 +18,7 @@ const int fpsMax = 120;
const auto target_duration = std::chrono::microseconds(1000000 / fpsMax);
auto last_end = std::chrono::high_resolution_clock::now();

const wstring appName = L"JarkViewer V1.6";
const wstring appName = L"JarkViewer v1.7";
const string windowName = "mainWindows";

const vector<int64_t> ZOOM_LIST = {

0 comments on commit 1357941

Please sign in to comment.