2021-04-12 15:26:48 +08:00
|
|
|
/*
|
|
|
|
* This file is part of the ZoneMinder Project. See AUTHORS file for Copyright information
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2021-02-04 11:47:28 +08:00
|
|
|
#include "zm_font.h"
|
|
|
|
|
2021-02-04 06:56:42 +08:00
|
|
|
#include <cstring>
|
2021-04-12 15:26:48 +08:00
|
|
|
#include <fstream>
|
2020-11-28 22:14:45 +08:00
|
|
|
|
2021-04-24 06:54:41 +08:00
|
|
|
constexpr uint8 kRequiredZmFntVersion = 1;
|
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
constexpr uint8 FontVariant::kMaxNumCodePoints;
|
|
|
|
constexpr uint8 FontVariant::kMaxCharHeight;
|
|
|
|
constexpr uint8 FontVariant::kMaxCharWidth;
|
2020-11-28 22:14:45 +08:00
|
|
|
|
2021-04-24 06:54:41 +08:00
|
|
|
FontVariant::FontVariant() : char_height_(0), char_width_(0), char_padding_(0), codepoint_count_(0) {}
|
2020-11-28 22:14:45 +08:00
|
|
|
|
2021-04-24 06:54:41 +08:00
|
|
|
FontVariant::FontVariant(uint16 char_height, uint16 char_width, uint8 char_padding, std::vector<uint64> bitmap)
|
|
|
|
: char_height_(char_height), char_width_(char_width), char_padding_(char_padding), bitmap_(std::move(bitmap)) {
|
2021-04-12 15:26:48 +08:00
|
|
|
if (char_height_ > kMaxCharHeight) {
|
|
|
|
throw std::invalid_argument("char_height > kMaxCharHeight");
|
|
|
|
}
|
2020-12-04 05:21:18 +08:00
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
if (char_width_ > kMaxCharWidth) {
|
|
|
|
throw std::invalid_argument("char_width > kMaxCharWidth");
|
2020-11-30 20:27:59 +08:00
|
|
|
}
|
2020-11-29 12:55:06 +08:00
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
if (bitmap_.size() % char_height_ != 0) {
|
|
|
|
throw std::invalid_argument("bitmap has wrong length");
|
2021-02-06 00:03:36 +08:00
|
|
|
}
|
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
codepoint_count_ = bitmap_.size() / char_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
nonstd::span<const uint64> FontVariant::GetCodepoint(uint8 idx) const {
|
|
|
|
static constexpr std::array<uint64, kMaxCharHeight> empty_bitmap = {};
|
|
|
|
|
|
|
|
if (idx >= GetCodepointsCount()) {
|
|
|
|
return {empty_bitmap.begin(), GetCharHeight()};
|
2020-11-30 20:27:59 +08:00
|
|
|
}
|
2021-04-12 15:26:48 +08:00
|
|
|
|
|
|
|
return {bitmap_.begin() + (idx * GetCharHeight()), GetCharHeight()};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ifstream &operator>>(std::ifstream &stream, FontBitmapHeader &bm_header) {
|
|
|
|
stream.read(reinterpret_cast<char *>(&bm_header), sizeof(bm_header));
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ifstream &operator>>(std::ifstream &stream, FontFileHeader &header) {
|
|
|
|
stream.read(header.magic, sizeof(header.magic));
|
2021-04-24 06:54:41 +08:00
|
|
|
stream.read(reinterpret_cast<char *>(&header.version), sizeof(header.version));
|
2021-04-12 15:26:48 +08:00
|
|
|
stream.seekg(sizeof(header.pad), std::ifstream::cur);
|
|
|
|
|
|
|
|
for (FontBitmapHeader &bm_header : header.bitmap_header)
|
|
|
|
stream >> bm_header;
|
|
|
|
|
|
|
|
return stream;
|
2020-11-28 21:16:20 +08:00
|
|
|
}
|
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
FontLoadError ZmFont::LoadFontFile(const std::string &loc) {
|
|
|
|
std::ifstream font_file(loc, std::ifstream::binary);
|
|
|
|
font_file.exceptions(std::ifstream::badbit);
|
|
|
|
|
|
|
|
if (!font_file.is_open()) {
|
|
|
|
return FontLoadError::kFileNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
FontFileHeader file_header = {};
|
|
|
|
font_file >> file_header;
|
|
|
|
|
|
|
|
if (font_file.fail()) {
|
|
|
|
return FontLoadError::kInvalidFile;
|
|
|
|
}
|
|
|
|
|
2021-04-24 06:54:41 +08:00
|
|
|
if (memcmp(file_header.magic, "ZMFNT", 5) != 0 || file_header.version != kRequiredZmFntVersion) {
|
2021-04-12 15:26:48 +08:00
|
|
|
return FontLoadError::kInvalidFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumFontSizes; i++) {
|
|
|
|
FontBitmapHeader bitmap_header = file_header.bitmap_header[i];
|
|
|
|
|
|
|
|
if (bitmap_header.char_width > FontVariant::kMaxCharWidth
|
|
|
|
|| bitmap_header.char_height > FontVariant::kMaxCharHeight
|
|
|
|
|| bitmap_header.number_of_code_points > FontVariant::kMaxNumCodePoints) {
|
|
|
|
return FontLoadError::kInvalidFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<uint64> bitmap;
|
|
|
|
bitmap.resize(bitmap_header.number_of_code_points * bitmap_header.char_height);
|
|
|
|
|
|
|
|
std::size_t bitmap_bytes = bitmap.size() * sizeof(uint64);
|
|
|
|
font_file.read(reinterpret_cast<char *>(bitmap.data()), static_cast<std::streamsize>(bitmap_bytes));
|
|
|
|
|
|
|
|
variants_[i] =
|
2021-04-24 06:54:41 +08:00
|
|
|
{bitmap_header.char_height, bitmap_header.char_width, bitmap_header.char_padding, std::move(bitmap)};
|
2020-11-29 12:55:06 +08:00
|
|
|
}
|
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
if (font_file.fail()) {
|
|
|
|
return FontLoadError::kInvalidFile;
|
2020-11-29 12:55:06 +08:00
|
|
|
}
|
2021-04-12 15:26:48 +08:00
|
|
|
|
|
|
|
return FontLoadError::kOk;
|
2020-11-28 22:14:45 +08:00
|
|
|
}
|
|
|
|
|
2021-04-12 15:26:48 +08:00
|
|
|
const FontVariant &ZmFont::GetFontVariant(uint8 idx) const {
|
|
|
|
return variants_.at(idx);
|
2020-11-29 12:55:06 +08:00
|
|
|
}
|