Reformatted all files
This commit is contained in:
parent
8c29b72961
commit
72d8bf1644
@ -1,84 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# clang-format-all: a tool to run clang-format on an entire project
|
|
||||||
# Copyright (C) 2016 Evan Klitzke <evan@eklitzke.org>
|
|
||||||
#
|
|
||||||
# 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 3 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/>.
|
|
||||||
|
|
||||||
function usage {
|
|
||||||
echo "Usage: $0 DIR..."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ $# -eq 0 ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Variable that will hold the name of the clang-format command
|
|
||||||
FMT=""
|
|
||||||
|
|
||||||
# Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent
|
|
||||||
# that the version number be part of the command. We prefer clang-format if
|
|
||||||
# that's present, otherwise we work backwards from highest version to lowest
|
|
||||||
# version.
|
|
||||||
for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do
|
|
||||||
if which "$clangfmt" &>/dev/null; then
|
|
||||||
FMT="$clangfmt"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check if we found a working clang-format
|
|
||||||
if [ -z "$FMT" ]; then
|
|
||||||
echo "failed to find clang-format"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check all of the arguments first to make sure they're all directories
|
|
||||||
for dir in "$@"; do
|
|
||||||
if [ ! -d "${dir}" ]; then
|
|
||||||
echo "${dir} is not a directory"
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Find a dominating file, starting from a given directory and going up.
|
|
||||||
find-dominating-file() {
|
|
||||||
if [ -r "$1"/"$2" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [ "$1" = "/" ]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
find-dominating-file "$(realpath "$1"/..)" "$2"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run clang-format -i on all of the things
|
|
||||||
for dir in "$@"; do
|
|
||||||
pushd "${dir}" &>/dev/null
|
|
||||||
if ! find-dominating-file . .clang-format; then
|
|
||||||
echo "Failed to find dominating .clang-format starting at $PWD"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
find . \
|
|
||||||
\( -name '*.c' \
|
|
||||||
-o -name '*.cc' \
|
|
||||||
-o -name '*.cpp' \
|
|
||||||
-o -name '*.h' \
|
|
||||||
-o -name '*.hh' \
|
|
||||||
-o -name '*.hpp' \) \
|
|
||||||
-exec "${FMT}" -i '{}' \;
|
|
||||||
popd &>/dev/null
|
|
||||||
done
|
|
@ -10,11 +10,15 @@ namespace glez {
|
|||||||
struct rgba {
|
struct rgba {
|
||||||
rgba() = default;
|
rgba() = default;
|
||||||
inline constexpr rgba(int r, int g, int b)
|
inline constexpr rgba(int r, int g, int b)
|
||||||
: r(r / 255.0f), g(g / 255.0f), b(b / 255.0f), a(1.0f)
|
: r(r / 255.0f)
|
||||||
{}
|
, g(g / 255.0f)
|
||||||
|
, b(b / 255.0f)
|
||||||
|
, a(1.0f) { }
|
||||||
inline constexpr rgba(int r, int g, int b, int a)
|
inline constexpr rgba(int r, int g, int b, int a)
|
||||||
: r(r / 255.0f), g(g / 255.0f), b(b / 255.0f), a(a / 255.0f)
|
: r(r / 255.0f)
|
||||||
{}
|
, g(g / 255.0f)
|
||||||
|
, b(b / 255.0f)
|
||||||
|
, a(a / 255.0f) { }
|
||||||
|
|
||||||
float r;
|
float r;
|
||||||
float g;
|
float g;
|
||||||
|
@ -4,21 +4,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <glez/texture.hpp>
|
#include <freetype-gl.h>
|
||||||
#include <glez/font.hpp>
|
#include <glez/font.hpp>
|
||||||
#include <glez/glez.hpp>
|
#include <glez/glez.hpp>
|
||||||
|
#include <glez/texture.hpp>
|
||||||
|
#include <vector>
|
||||||
#include <vertex-buffer.h>
|
#include <vertex-buffer.h>
|
||||||
#include <glez/font.hpp>
|
|
||||||
#include <freetype-gl.h>
|
|
||||||
|
|
||||||
namespace glez::detail::record {
|
namespace glez::detail::record {
|
||||||
|
|
||||||
class RecordedCommands {
|
class RecordedCommands {
|
||||||
public:
|
public:
|
||||||
struct segment
|
struct segment {
|
||||||
{
|
|
||||||
std::size_t start { 0 };
|
std::size_t start { 0 };
|
||||||
std::size_t size { 0 };
|
std::size_t size { 0 };
|
||||||
glez::texture* texture { nullptr };
|
glez::texture* texture { nullptr };
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "color.hpp"
|
#include "color.hpp"
|
||||||
#include "font.hpp"
|
#include "font.hpp"
|
||||||
#include "texture.hpp"
|
#include "texture.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace glez::draw {
|
namespace glez::draw {
|
||||||
|
|
||||||
|
@ -23,9 +23,10 @@ public:
|
|||||||
// void stringSize(std::string_view string, float* width, float* height);
|
// void stringSize(std::string_view string, float* width, float* height);
|
||||||
void stringSize(const std::string& string, float* width, float* height);
|
void stringSize(const std::string& string, float* width, float* height);
|
||||||
inline bool isLoaded() { return this->m_font != nullptr && this->atlas != nullptr; };
|
inline bool isLoaded() { return this->m_font != nullptr && this->atlas != nullptr; };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
texture_font_t* m_font = nullptr;
|
texture_font_t* m_font = nullptr;
|
||||||
texture_atlas_t* atlas = nullptr;
|
texture_atlas_t* atlas = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace glez::detail::font
|
} // namespace glez
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vertex-buffer.h>
|
|
||||||
#include <freetype-gl.h>
|
#include <freetype-gl.h>
|
||||||
#include <glez/color.hpp>
|
#include <glez/color.hpp>
|
||||||
|
#include <vertex-buffer.h>
|
||||||
|
|
||||||
namespace glez {
|
namespace glez {
|
||||||
|
|
||||||
@ -33,4 +33,4 @@ struct vertex {
|
|||||||
|
|
||||||
void bind(GLuint texture);
|
void bind(GLuint texture);
|
||||||
|
|
||||||
}; // namespace glez::detail::program
|
}; // namespace glez
|
||||||
|
@ -4,16 +4,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace glez::detail::record
|
namespace glez::detail::record {
|
||||||
{
|
|
||||||
class RecordedCommands;
|
class RecordedCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace glez::record
|
namespace glez::record {
|
||||||
{
|
|
||||||
|
|
||||||
class Record
|
class Record {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Record();
|
Record();
|
||||||
~Record();
|
~Record();
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <freetype-gl.h>
|
|
||||||
#include <string>
|
|
||||||
#include <limits>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <freetype-gl.h>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace glez
|
namespace glez {
|
||||||
{
|
|
||||||
|
|
||||||
class texture {
|
class texture {
|
||||||
public:
|
public:
|
||||||
@ -26,6 +25,7 @@ public:
|
|||||||
void bind();
|
void bind();
|
||||||
|
|
||||||
inline bool isLoaded() { return this->init; }
|
inline bool isLoaded() { return this->init; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool init = false;
|
bool init = false;
|
||||||
bool bound = false;
|
bool bound = false;
|
||||||
@ -36,4 +36,4 @@ public:
|
|||||||
GLubyte* data;
|
GLubyte* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace glez::texture
|
} // namespace glez
|
||||||
|
@ -3,23 +3,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <glez/detail/record.hpp>
|
|
||||||
#include <glez/record.hpp>
|
|
||||||
#include <glez/glez.hpp>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <glez/detail/record.hpp>
|
||||||
|
#include <glez/glez.hpp>
|
||||||
|
#include <glez/record.hpp>
|
||||||
|
|
||||||
namespace glez::detail::record
|
namespace glez::detail::record {
|
||||||
{
|
|
||||||
|
|
||||||
void RecordedCommands::render()
|
void RecordedCommands::render() {
|
||||||
{
|
|
||||||
isReplaying = true;
|
isReplaying = true;
|
||||||
vertex_buffer_render_setup(vertex_buffer, GL_TRIANGLES);
|
vertex_buffer_render_setup(vertex_buffer, GL_TRIANGLES);
|
||||||
for (const auto& i : segments) {
|
for (const auto& i : segments) {
|
||||||
if (i.texture) {
|
if (i.texture) {
|
||||||
i.texture->bind();
|
i.texture->bind();
|
||||||
}
|
} else if (i.font) {
|
||||||
else if (i.font) {
|
|
||||||
if (i.font->atlas->id == 0) {
|
if (i.font->atlas->id == 0) {
|
||||||
glGenTextures(1, &i.font->atlas->id);
|
glGenTextures(1, &i.font->atlas->id);
|
||||||
}
|
}
|
||||||
@ -68,17 +65,14 @@ void RecordedCommands::bindTexture(glez::texture *tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordedCommands::bindFont(glez::font *font)
|
void RecordedCommands::bindFont(glez::font* font) {
|
||||||
{
|
if (current.font != font) {
|
||||||
if (current.font != font)
|
|
||||||
{
|
|
||||||
cutSegment();
|
cutSegment();
|
||||||
current.font = font;
|
current.font = font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordedCommands::cutSegment()
|
void RecordedCommands::cutSegment() {
|
||||||
{
|
|
||||||
current.size = vertex_buffer->indices->size - current.start;
|
current.size = vertex_buffer->indices->size - current.start;
|
||||||
if (current.size)
|
if (current.size)
|
||||||
segments.push_back(current);
|
segments.push_back(current);
|
||||||
@ -86,8 +80,7 @@ void RecordedCommands::cutSegment()
|
|||||||
current.start = vertex_buffer->indices->size;
|
current.start = vertex_buffer->indices->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordedCommands::end()
|
void RecordedCommands::end() {
|
||||||
{
|
|
||||||
cutSegment();
|
cutSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,29 +89,24 @@ bool isReplaying{ false };
|
|||||||
|
|
||||||
} // namespace glez::detail::record
|
} // namespace glez::detail::record
|
||||||
|
|
||||||
glez::record::Record::Record()
|
glez::record::Record::Record() {
|
||||||
{
|
|
||||||
commands = new glez::detail::record::RecordedCommands {};
|
commands = new glez::detail::record::RecordedCommands {};
|
||||||
}
|
}
|
||||||
|
|
||||||
glez::record::Record::~Record()
|
glez::record::Record::~Record() {
|
||||||
{
|
|
||||||
delete commands;
|
delete commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glez::record::Record::begin()
|
void glez::record::Record::begin() {
|
||||||
{
|
|
||||||
detail::record::currentRecord = commands;
|
detail::record::currentRecord = commands;
|
||||||
commands->reset();
|
commands->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void glez::record::Record::end()
|
void glez::record::Record::end() {
|
||||||
{
|
|
||||||
commands->end();
|
commands->end();
|
||||||
detail::record::currentRecord = nullptr;
|
detail::record::currentRecord = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glez::record::Record::replay()
|
void glez::record::Record::replay() {
|
||||||
{
|
|
||||||
commands->render();
|
commands->render();
|
||||||
}
|
}
|
||||||
|
13
src/draw.cpp
13
src/draw.cpp
@ -4,18 +4,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
#include <glez/detail/record.hpp>
|
||||||
|
#include <glez/detail/render.hpp>
|
||||||
#include <glez/draw.hpp>
|
#include <glez/draw.hpp>
|
||||||
#include <glez/font.hpp>
|
#include <glez/font.hpp>
|
||||||
#include <glez/detail/render.hpp>
|
|
||||||
#include <glez/glez.hpp>
|
#include <glez/glez.hpp>
|
||||||
#include <vertex-buffer.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include <glez/texture.hpp>
|
#include <glez/texture.hpp>
|
||||||
#include <cmath>
|
#include <vertex-buffer.h>
|
||||||
#include <glez/detail/record.hpp>
|
|
||||||
|
|
||||||
namespace indices
|
namespace indices {
|
||||||
{
|
|
||||||
|
|
||||||
static GLuint rectangle[6] = { 0, 1, 2, 2, 3, 0 };
|
static GLuint rectangle[6] = { 0, 1, 2, 2, 3, 0 };
|
||||||
static GLuint triangle[3] = { 0, 1, 2 };
|
static GLuint triangle[3] = { 0, 1, 2 };
|
||||||
|
11
src/font.cpp
11
src/font.cpp
@ -3,10 +3,10 @@
|
|||||||
Copyright (c) 2018 nullworks. All rights reserved.
|
Copyright (c) 2018 nullworks. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glez/font.hpp>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <glez/font.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace glez {
|
namespace glez {
|
||||||
|
|
||||||
@ -46,8 +46,7 @@ void font::stringSize(const std::string& string, float* width, float* height) {
|
|||||||
|
|
||||||
const char* sstring = string.c_str();
|
const char* sstring = string.c_str();
|
||||||
|
|
||||||
for (size_t i = 0; i < string.size(); ++i)
|
for (size_t i = 0; i < string.size(); ++i) {
|
||||||
{
|
|
||||||
// c_str guarantees a NULL terminator
|
// c_str guarantees a NULL terminator
|
||||||
texture_glyph_t* glyph = texture_font_find_glyph(m_font, &sstring[i]);
|
texture_glyph_t* glyph = texture_font_find_glyph(m_font, &sstring[i]);
|
||||||
if (glyph == nullptr)
|
if (glyph == nullptr)
|
||||||
@ -68,4 +67,4 @@ void font::stringSize(const std::string& string, float* width, float* height) {
|
|||||||
*height = size_y;
|
*height = size_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glez::detail::font
|
} // namespace glez
|
||||||
|
24
src/glez.cpp
24
src/glez.cpp
@ -3,18 +3,17 @@
|
|||||||
Copyright (c) 2018 nullworks. All rights reserved.
|
Copyright (c) 2018 nullworks. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <freetype-gl.h>
|
|
||||||
#include <vertex-buffer.h>
|
|
||||||
#include <mat4.h>
|
|
||||||
#include <glez/glez.hpp>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <freetype-gl.h>
|
||||||
|
#include <glez/detail/record.hpp>
|
||||||
#include <glez/detail/render.hpp>
|
#include <glez/detail/render.hpp>
|
||||||
#include <glez/font.hpp>
|
#include <glez/font.hpp>
|
||||||
#include <cstring>
|
|
||||||
#include <glez/glez.hpp>
|
#include <glez/glez.hpp>
|
||||||
#include <glez/detail/record.hpp>
|
#include <mat4.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vertex-buffer.h>
|
||||||
|
|
||||||
static const char* shader_vertex = R"END(
|
static const char* shader_vertex = R"END(
|
||||||
#version 130
|
#version 130
|
||||||
@ -70,8 +69,7 @@ static GLuint compile(const char *source, GLenum type) {
|
|||||||
glCompileShader(result);
|
glCompileShader(result);
|
||||||
glGetShaderiv(result, GL_COMPILE_STATUS, &status);
|
glGetShaderiv(result, GL_COMPILE_STATUS, &status);
|
||||||
|
|
||||||
if (status != GL_TRUE)
|
if (status != GL_TRUE) {
|
||||||
{
|
|
||||||
char error[512];
|
char error[512];
|
||||||
GLsizei length;
|
GLsizei length;
|
||||||
glGetShaderInfoLog(result, 512, &length, error);
|
glGetShaderInfoLog(result, 512, &length, error);
|
||||||
@ -113,8 +111,7 @@ void resize(int width, int height) {
|
|||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(int width, int height)
|
void init(int width, int height) {
|
||||||
{
|
|
||||||
buffer = ftgl::vertex_buffer_new("vertex:2f,tex_coord:2f,color:4f,drawmode:1i");
|
buffer = ftgl::vertex_buffer_new("vertex:2f,tex_coord:2f,color:4f,drawmode:1i");
|
||||||
shader = link(compile(shader_vertex, GL_VERTEX_SHADER), compile(shader_fragment, GL_FRAGMENT_SHADER));
|
shader = link(compile(shader_vertex, GL_VERTEX_SHADER), compile(shader_fragment, GL_FRAGMENT_SHADER));
|
||||||
|
|
||||||
@ -132,7 +129,6 @@ void shutdown() {
|
|||||||
|
|
||||||
static GLuint current_texture { 0 };
|
static GLuint current_texture { 0 };
|
||||||
|
|
||||||
|
|
||||||
void begin() {
|
void begin() {
|
||||||
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
|
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
@ -183,4 +179,4 @@ void bind(GLuint texture) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace glez
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <vector>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <vector>
|
||||||
/*
|
/*
|
||||||
decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a raw pixel buffer.
|
decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a raw pixel buffer.
|
||||||
out_image: output parameter, this will contain the raw pixels after decoding.
|
out_image: output parameter, this will contain the raw pixels after decoding.
|
||||||
@ -20,8 +20,7 @@ convert_to_rgba32: optional parameter, true by default.
|
|||||||
works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information.
|
works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information.
|
||||||
return: 0 if success, not 0 if some error occured.
|
return: 0 if success, not 0 if some error occured.
|
||||||
*/
|
*/
|
||||||
int decodePNG(unsigned char* &out_image, int& image_width, int& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true)
|
int decodePNG(unsigned char*& out_image, int& image_width, int& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true) {
|
||||||
{
|
|
||||||
// picoPNG version 20101224
|
// picoPNG version 20101224
|
||||||
// Copyright (c) 2005-2010 Lode Vandevenne
|
// Copyright (c) 2005-2010 Lode Vandevenne
|
||||||
//
|
//
|
||||||
@ -55,41 +54,55 @@ int decodePNG(unsigned char* &out_image, int& image_width, int& image_height, co
|
|||||||
static const unsigned long CLCL[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; // code length code lengths
|
static const unsigned long CLCL[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; // code length code lengths
|
||||||
struct Zlib // nested functions for zlib decompression
|
struct Zlib // nested functions for zlib decompression
|
||||||
{
|
{
|
||||||
static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; bitp++; return result;}
|
static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) {
|
||||||
static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits)
|
unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1;
|
||||||
{
|
bitp++;
|
||||||
unsigned long result = 0;
|
|
||||||
for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
struct HuffmanTree
|
static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits) {
|
||||||
{
|
unsigned long result = 0;
|
||||||
int makeFromLengths(const std::vector<unsigned long>& bitlen, unsigned long maxbitlen)
|
for (size_t i = 0; i < nbits; i++)
|
||||||
{ //make tree given the lengths
|
result += (readBitFromStream(bitp, bits)) << i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
struct HuffmanTree {
|
||||||
|
int makeFromLengths(const std::vector<unsigned long>& bitlen, unsigned long maxbitlen) { // make tree given the lengths
|
||||||
unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
|
unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
|
||||||
std::vector<unsigned long> tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
|
std::vector<unsigned long> tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
|
||||||
for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; //count number of instances of each code length
|
for (unsigned long bits = 0; bits < numcodes; bits++)
|
||||||
for(unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
|
blcount[bitlen[bits]]++; // count number of instances of each code length
|
||||||
for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; //generate all the codes
|
for (unsigned long bits = 1; bits <= maxbitlen; bits++)
|
||||||
tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet
|
nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
|
||||||
|
for (unsigned long n = 0; n < numcodes; n++)
|
||||||
|
if (bitlen[n] != 0)
|
||||||
|
tree1d[n] = nextcode[bitlen[n]]++; // generate all the codes
|
||||||
|
tree2d.clear();
|
||||||
|
tree2d.resize(numcodes * 2, 32767); // 32767 here means the tree2d isn't filled there yet
|
||||||
for (unsigned long n = 0; n < numcodes; n++) // the codes
|
for (unsigned long n = 0; n < numcodes; n++) // the codes
|
||||||
for (unsigned long i = 0; i < bitlen[n]; i++) // the bits for this code
|
for (unsigned long i = 0; i < bitlen[n]; i++) // the bits for this code
|
||||||
{
|
{
|
||||||
unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
|
unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
|
||||||
if(treepos > numcodes - 2) return 55;
|
if (treepos > numcodes - 2)
|
||||||
|
return 55;
|
||||||
if (tree2d[2 * treepos + bit] == 32767) // not yet filled in
|
if (tree2d[2 * treepos + bit] == 32767) // not yet filled in
|
||||||
{
|
{
|
||||||
if(i + 1 == bitlen[n]) { tree2d[2 * treepos + bit] = n; treepos = 0; } //last bit
|
if (i + 1 == bitlen[n]) {
|
||||||
else { tree2d[2 * treepos + bit] = ++nodefilled + numcodes; treepos = nodefilled; } //addresses are encoded as values > numcodes
|
tree2d[2 * treepos + bit] = n;
|
||||||
}
|
treepos = 0;
|
||||||
else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value
|
} // last bit
|
||||||
|
else {
|
||||||
|
tree2d[2 * treepos + bit] = ++nodefilled + numcodes;
|
||||||
|
treepos = nodefilled;
|
||||||
|
} // addresses are encoded as values > numcodes
|
||||||
|
} else
|
||||||
|
treepos = tree2d[2 * treepos + bit] - numcodes; // subtract numcodes from address to get address value
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const
|
int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const { // Decodes a symbol from the tree
|
||||||
{ //Decodes a symbol from the tree
|
|
||||||
unsigned long numcodes = (unsigned long)tree2d.size() / 2;
|
unsigned long numcodes = (unsigned long)tree2d.size() / 2;
|
||||||
if(treepos >= numcodes) return 11; //error: you appeared outside the codetree
|
if (treepos >= numcodes)
|
||||||
|
return 11; // error: you appeared outside the codetree
|
||||||
result = tree2d[2 * treepos + bit];
|
result = tree2d[2 * treepos + bit];
|
||||||
decoded = (result < numcodes);
|
decoded = (result < numcodes);
|
||||||
treepos = decoded ? 0 : result - numcodes;
|
treepos = decoded ? 0 : result - numcodes;
|
||||||
@ -97,219 +110,353 @@ int decodePNG(unsigned char* &out_image, int& image_width, int& image_height, co
|
|||||||
}
|
}
|
||||||
std::vector<unsigned long> tree2d; // 2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree.
|
std::vector<unsigned long> tree2d; // 2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree.
|
||||||
};
|
};
|
||||||
struct Inflator
|
struct Inflator {
|
||||||
{
|
|
||||||
int error;
|
int error;
|
||||||
void inflate(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, size_t inpos = 0)
|
void inflate(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, size_t inpos = 0) {
|
||||||
{
|
|
||||||
size_t bp = 0, pos = 0; // bit pointer and byte pointer
|
size_t bp = 0, pos = 0; // bit pointer and byte pointer
|
||||||
error = 0;
|
error = 0;
|
||||||
unsigned long BFINAL = 0;
|
unsigned long BFINAL = 0;
|
||||||
while(!BFINAL && !error)
|
while (!BFINAL && !error) {
|
||||||
{
|
if (bp >> 3 >= in.size()) {
|
||||||
if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory
|
error = 52;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer will jump past memory
|
||||||
BFINAL = readBitFromStream(bp, &in[inpos]);
|
BFINAL = readBitFromStream(bp, &in[inpos]);
|
||||||
unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
|
unsigned long BTYPE = readBitFromStream(bp, &in[inpos]);
|
||||||
if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE
|
BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
|
||||||
else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size());
|
if (BTYPE == 3) {
|
||||||
else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
|
error = 20;
|
||||||
|
return;
|
||||||
|
} // error: invalid BTYPE
|
||||||
|
else if (BTYPE == 0)
|
||||||
|
inflateNoCompression(out, &in[inpos], bp, pos, in.size());
|
||||||
|
else
|
||||||
|
inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
|
||||||
}
|
}
|
||||||
if(!error) out.resize(pos); //Only now we know the true size of out, resize it to that
|
if (!error)
|
||||||
|
out.resize(pos); // Only now we know the true size of out, resize it to that
|
||||||
}
|
}
|
||||||
void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) // get the tree of a deflated block with fixed tree
|
void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) // get the tree of a deflated block with fixed tree
|
||||||
{
|
{
|
||||||
std::vector<unsigned long> bitlen(288, 8), bitlenD(32, 5);;
|
std::vector<unsigned long> bitlen(288, 8), bitlenD(32, 5);
|
||||||
for(size_t i = 144; i <= 255; i++) bitlen[i] = 9;
|
;
|
||||||
for(size_t i = 256; i <= 279; i++) bitlen[i] = 7;
|
for (size_t i = 144; i <= 255; i++)
|
||||||
|
bitlen[i] = 9;
|
||||||
|
for (size_t i = 256; i <= 279; i++)
|
||||||
|
bitlen[i] = 7;
|
||||||
tree.makeFromLengths(bitlen, 15);
|
tree.makeFromLengths(bitlen, 15);
|
||||||
treeD.makeFromLengths(bitlenD, 15);
|
treeD.makeFromLengths(bitlenD, 15);
|
||||||
}
|
}
|
||||||
HuffmanTree codetree, codetreeD, codelengthcodetree; // the code tree for Huffman codes, dist codes, and code length codes
|
HuffmanTree codetree, codetreeD, codelengthcodetree; // the code tree for Huffman codes, dist codes, and code length codes
|
||||||
unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength)
|
unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength) { // decode a single symbol from given list of bits with given code tree. return value is the symbol
|
||||||
{ //decode a single symbol from given list of bits with given code tree. return value is the symbol
|
bool decoded;
|
||||||
bool decoded; unsigned long ct;
|
unsigned long ct;
|
||||||
for(size_t treepos = 0;;)
|
for (size_t treepos = 0;;) {
|
||||||
{
|
if ((bp & 0x07) == 0 && (bp >> 3) > inlength) {
|
||||||
if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode
|
error = 10;
|
||||||
error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); if(error) return 0; //stop, an error happened
|
return 0;
|
||||||
if(decoded) return ct;
|
} // error: end reached without endcode
|
||||||
|
error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in));
|
||||||
|
if (error)
|
||||||
|
return 0; // stop, an error happened
|
||||||
|
if (decoded)
|
||||||
|
return ct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, size_t inlength)
|
void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, size_t inlength) { // get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
|
||||||
{ //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
|
|
||||||
std::vector<unsigned long> bitlen(288, 0), bitlenD(32, 0);
|
std::vector<unsigned long> bitlen(288, 0), bitlenD(32, 0);
|
||||||
if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory
|
if (bp >> 3 >= inlength - 2) {
|
||||||
|
error = 49;
|
||||||
|
return;
|
||||||
|
} // the bit pointer is or will go past the memory
|
||||||
size_t HLIT = readBitsFromStream(bp, in, 5) + 257; // number of literal/length codes + 257
|
size_t HLIT = readBitsFromStream(bp, in, 5) + 257; // number of literal/length codes + 257
|
||||||
size_t HDIST = readBitsFromStream(bp, in, 5) + 1; // number of dist codes + 1
|
size_t HDIST = readBitsFromStream(bp, in, 5) + 1; // number of dist codes + 1
|
||||||
size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; // number of code length codes + 4
|
size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; // number of code length codes + 4
|
||||||
std::vector<unsigned long> codelengthcode(19); // lengths of tree to decode the lengths of the dynamic tree
|
std::vector<unsigned long> codelengthcode(19); // lengths of tree to decode the lengths of the dynamic tree
|
||||||
for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
|
for (size_t i = 0; i < 19; i++)
|
||||||
error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return;
|
codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
|
||||||
|
error = codelengthcodetree.makeFromLengths(codelengthcode, 7);
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
size_t i = 0, replength;
|
size_t i = 0, replength;
|
||||||
while(i < HLIT + HDIST)
|
while (i < HLIT + HDIST) {
|
||||||
{
|
unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength);
|
||||||
unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return;
|
if (error)
|
||||||
if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code
|
return;
|
||||||
|
if (code <= 15) {
|
||||||
|
if (i < HLIT)
|
||||||
|
bitlen[i++] = code;
|
||||||
|
else
|
||||||
|
bitlenD[i++ - HLIT] = code;
|
||||||
|
} // a length code
|
||||||
else if (code == 16) // repeat previous
|
else if (code == 16) // repeat previous
|
||||||
{
|
{
|
||||||
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
|
if (bp >> 3 >= inlength) {
|
||||||
|
error = 50;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer jumps past memory
|
||||||
replength = 3 + readBitsFromStream(bp, in, 2);
|
replength = 3 + readBitsFromStream(bp, in, 2);
|
||||||
unsigned long value; // set value to the previous code
|
unsigned long value; // set value to the previous code
|
||||||
if((i - 1) < HLIT) value = bitlen[i - 1];
|
if ((i - 1) < HLIT)
|
||||||
else value = bitlenD[i - HLIT - 1];
|
value = bitlen[i - 1];
|
||||||
|
else
|
||||||
|
value = bitlenD[i - HLIT - 1];
|
||||||
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
||||||
{
|
{
|
||||||
if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes
|
if (i >= HLIT + HDIST) {
|
||||||
if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value;
|
error = 13;
|
||||||
|
return;
|
||||||
|
} // error: i is larger than the amount of codes
|
||||||
|
if (i < HLIT)
|
||||||
|
bitlen[i++] = value;
|
||||||
|
else
|
||||||
|
bitlenD[i++ - HLIT] = value;
|
||||||
}
|
}
|
||||||
}
|
} else if (code == 17) // repeat "0" 3-10 times
|
||||||
else if(code == 17) //repeat "0" 3-10 times
|
|
||||||
{
|
{
|
||||||
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
|
if (bp >> 3 >= inlength) {
|
||||||
|
error = 50;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer jumps past memory
|
||||||
replength = 3 + readBitsFromStream(bp, in, 3);
|
replength = 3 + readBitsFromStream(bp, in, 3);
|
||||||
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
||||||
{
|
{
|
||||||
if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes
|
if (i >= HLIT + HDIST) {
|
||||||
if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
|
error = 14;
|
||||||
|
return;
|
||||||
|
} // error: i is larger than the amount of codes
|
||||||
|
if (i < HLIT)
|
||||||
|
bitlen[i++] = 0;
|
||||||
|
else
|
||||||
|
bitlenD[i++ - HLIT] = 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (code == 18) // repeat "0" 11-138 times
|
||||||
else if(code == 18) //repeat "0" 11-138 times
|
|
||||||
{
|
{
|
||||||
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
|
if (bp >> 3 >= inlength) {
|
||||||
|
error = 50;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer jumps past memory
|
||||||
replength = 11 + readBitsFromStream(bp, in, 7);
|
replength = 11 + readBitsFromStream(bp, in, 7);
|
||||||
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
for (size_t n = 0; n < replength; n++) // repeat this value in the next lengths
|
||||||
{
|
{
|
||||||
if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes
|
if (i >= HLIT + HDIST) {
|
||||||
if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
|
error = 15;
|
||||||
|
return;
|
||||||
|
} // error: i is larger than the amount of codes
|
||||||
|
if (i < HLIT)
|
||||||
|
bitlen[i++] = 0;
|
||||||
|
else
|
||||||
|
bitlenD[i++ - HLIT] = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
error = 16;
|
||||||
|
return;
|
||||||
|
} // error: somehow an unexisting code appeared. This can never happen.
|
||||||
}
|
}
|
||||||
else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen.
|
if (bitlen[256] == 0) {
|
||||||
|
error = 64;
|
||||||
|
return;
|
||||||
|
} // the length of the end code 256 must be larger than 0
|
||||||
|
error = tree.makeFromLengths(bitlen, 15);
|
||||||
|
if (error)
|
||||||
|
return; // now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
|
||||||
|
error = treeD.makeFromLengths(bitlenD, 15);
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0
|
void inflateHuffmanBlock(std::vector<unsigned char>& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype) {
|
||||||
error = tree.makeFromLengths(bitlen, 15); if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
|
if (btype == 1) {
|
||||||
error = treeD.makeFromLengths(bitlenD, 15); if(error) return;
|
generateFixedTrees(codetree, codetreeD);
|
||||||
|
} else if (btype == 2) {
|
||||||
|
getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength);
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
void inflateHuffmanBlock(std::vector<unsigned char>& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype)
|
for (;;) {
|
||||||
{
|
unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength);
|
||||||
if(btype == 1) { generateFixedTrees(codetree, codetreeD); }
|
if (error)
|
||||||
else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; }
|
return;
|
||||||
for(;;)
|
if (code == 256)
|
||||||
{
|
return; // end code
|
||||||
unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return;
|
|
||||||
if(code == 256) return; //end code
|
|
||||||
else if (code <= 255) // literal symbol
|
else if (code <= 255) // literal symbol
|
||||||
{
|
{
|
||||||
if(pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room
|
if (pos >= out.size())
|
||||||
|
out.resize((pos + 1) * 2); // reserve more room
|
||||||
out[pos++] = (unsigned char)(code);
|
out[pos++] = (unsigned char)(code);
|
||||||
}
|
} else if (code >= 257 && code <= 285) // length code
|
||||||
else if(code >= 257 && code <= 285) //length code
|
|
||||||
{
|
{
|
||||||
size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
|
size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
|
||||||
if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
|
if ((bp >> 3) >= inlength) {
|
||||||
|
error = 51;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer will jump past memory
|
||||||
length += readBitsFromStream(bp, in, numextrabits);
|
length += readBitsFromStream(bp, in, numextrabits);
|
||||||
unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return;
|
unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength);
|
||||||
if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used)
|
if (error)
|
||||||
|
return;
|
||||||
|
if (codeD > 29) {
|
||||||
|
error = 18;
|
||||||
|
return;
|
||||||
|
} // error: invalid dist code (30-31 are never used)
|
||||||
unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
|
unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
|
||||||
if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
|
if ((bp >> 3) >= inlength) {
|
||||||
|
error = 51;
|
||||||
|
return;
|
||||||
|
} // error, bit pointer will jump past memory
|
||||||
dist += readBitsFromStream(bp, in, numextrabitsD);
|
dist += readBitsFromStream(bp, in, numextrabitsD);
|
||||||
size_t start = pos, back = start - dist; // backwards
|
size_t start = pos, back = start - dist; // backwards
|
||||||
if(pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room
|
if (pos + length >= out.size())
|
||||||
for(size_t i = 0; i < length; i++) { out[pos++] = out[back++]; if(back >= start) back = start - dist; }
|
out.resize((pos + length) * 2); // reserve more room
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
out[pos++] = out[back++];
|
||||||
|
if (back >= start)
|
||||||
|
back = start - dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void inflateNoCompression(std::vector<unsigned char>& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength)
|
}
|
||||||
{
|
void inflateNoCompression(std::vector<unsigned char>& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength) {
|
||||||
while((bp & 0x7) != 0) bp++; //go to first boundary of byte
|
while ((bp & 0x7) != 0)
|
||||||
|
bp++; // go to first boundary of byte
|
||||||
size_t p = bp / 8;
|
size_t p = bp / 8;
|
||||||
if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
|
if (p >= inlength - 4) {
|
||||||
unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4;
|
error = 52;
|
||||||
if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
|
return;
|
||||||
if(pos + LEN >= out.size()) out.resize(pos + LEN);
|
} // error, bit pointer will jump past memory
|
||||||
if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
|
unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3];
|
||||||
for(unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data
|
p += 4;
|
||||||
|
if (LEN + NLEN != 65535) {
|
||||||
|
error = 21;
|
||||||
|
return;
|
||||||
|
} // error: NLEN is not one's complement of LEN
|
||||||
|
if (pos + LEN >= out.size())
|
||||||
|
out.resize(pos + LEN);
|
||||||
|
if (p + LEN > inlength) {
|
||||||
|
error = 23;
|
||||||
|
return;
|
||||||
|
} // error: reading outside of in buffer
|
||||||
|
for (unsigned long n = 0; n < LEN; n++)
|
||||||
|
out[pos++] = in[p++]; // read LEN bytes of literal data
|
||||||
bp = p * 8;
|
bp = p * 8;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) // returns error value
|
int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) // returns error value
|
||||||
{
|
{
|
||||||
Inflator inflator;
|
Inflator inflator;
|
||||||
if(in.size() < 2) { return 53; } //error, size of zlib data too small
|
if (in.size() < 2) {
|
||||||
if((in[0] * 256 + in[1]) % 31 != 0) { return 24; } //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
|
return 53;
|
||||||
|
} // error, size of zlib data too small
|
||||||
|
if ((in[0] * 256 + in[1]) % 31 != 0) {
|
||||||
|
return 24;
|
||||||
|
} // error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
|
||||||
unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
|
unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
|
||||||
if(CM != 8 || CINFO > 7) { return 25; } //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
|
if (CM != 8 || CINFO > 7) {
|
||||||
if(FDICT != 0) { return 26; } //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."
|
return 25;
|
||||||
|
} // error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
|
||||||
|
if (FDICT != 0) {
|
||||||
|
return 26;
|
||||||
|
} // error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."
|
||||||
inflator.inflate(out, in, 2);
|
inflator.inflate(out, in, 2);
|
||||||
return inflator.error; // note: adler32 checksum was skipped and ignored
|
return inflator.error; // note: adler32 checksum was skipped and ignored
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct PNG // nested functions for PNG decoding
|
struct PNG // nested functions for PNG decoding
|
||||||
{
|
{
|
||||||
struct Info
|
struct Info {
|
||||||
{
|
|
||||||
unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b;
|
unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b;
|
||||||
bool key_defined; // is a transparent color key given?
|
bool key_defined; // is a transparent color key given?
|
||||||
std::vector<unsigned char> palette;
|
std::vector<unsigned char> palette;
|
||||||
} info;
|
} info;
|
||||||
int error;
|
int error;
|
||||||
void decode(unsigned char* &out, const unsigned char* in, size_t size, bool convert_to_rgba32)
|
void decode(unsigned char*& out, const unsigned char* in, size_t size, bool convert_to_rgba32) {
|
||||||
{
|
|
||||||
error = 0;
|
error = 0;
|
||||||
if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
|
if (size == 0 || in == 0) {
|
||||||
readPngHeader(&in[0], size); if(error) return;
|
error = 48;
|
||||||
|
return;
|
||||||
|
} // the given data is empty
|
||||||
|
readPngHeader(&in[0], size);
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
size_t pos = 33; // first byte of the first chunk after the header
|
size_t pos = 33; // first byte of the first chunk after the header
|
||||||
std::vector<unsigned char> idat; // the data from idat chunks
|
std::vector<unsigned char> idat; // the data from idat chunks
|
||||||
bool IEND = false, known_type = true;
|
bool IEND = false, known_type = true;
|
||||||
info.key_defined = false;
|
info.key_defined = false;
|
||||||
while (!IEND) // loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
|
while (!IEND) // loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
|
||||||
{
|
{
|
||||||
if(pos + 8 >= size) { error = 30; return; } //error: size of the in buffer too small to contain next chunk
|
if (pos + 8 >= size) {
|
||||||
size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
|
error = 30;
|
||||||
if(chunkLength > 2147483647) { error = 63; return; }
|
return;
|
||||||
if(pos + chunkLength >= size) { error = 35; return; } //error: size of the in buffer too small to contain next chunk
|
} // error: size of the in buffer too small to contain next chunk
|
||||||
|
size_t chunkLength = read32bitInt(&in[pos]);
|
||||||
|
pos += 4;
|
||||||
|
if (chunkLength > 2147483647) {
|
||||||
|
error = 63;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pos + chunkLength >= size) {
|
||||||
|
error = 35;
|
||||||
|
return;
|
||||||
|
} // error: size of the in buffer too small to contain next chunk
|
||||||
if (in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') // IDAT chunk, containing compressed image data
|
if (in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') // IDAT chunk, containing compressed image data
|
||||||
{
|
{
|
||||||
idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
|
idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
|
||||||
pos += (4 + chunkLength);
|
pos += (4 + chunkLength);
|
||||||
}
|
} else if (in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') {
|
||||||
else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') { pos += 4; IEND = true; }
|
pos += 4;
|
||||||
else if(in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') //palette chunk (PLTE)
|
IEND = true;
|
||||||
|
} else if (in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') // palette chunk (PLTE)
|
||||||
{
|
{
|
||||||
pos += 4; // go after the 4 letters
|
pos += 4; // go after the 4 letters
|
||||||
info.palette.resize(4 * (chunkLength / 3));
|
info.palette.resize(4 * (chunkLength / 3));
|
||||||
if(info.palette.size() > (4 * 256)) { error = 38; return; } //error: palette too big
|
if (info.palette.size() > (4 * 256)) {
|
||||||
for(size_t i = 0; i < info.palette.size(); i += 4)
|
error = 38;
|
||||||
{
|
return;
|
||||||
for(size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB
|
} // error: palette too big
|
||||||
|
for (size_t i = 0; i < info.palette.size(); i += 4) {
|
||||||
|
for (size_t j = 0; j < 3; j++)
|
||||||
|
info.palette[i + j] = in[pos++]; // RGB
|
||||||
info.palette[i + 3] = 255; // alpha
|
info.palette[i + 3] = 255; // alpha
|
||||||
}
|
}
|
||||||
}
|
} else if (in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') // palette transparency chunk (tRNS)
|
||||||
else if(in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') //palette transparency chunk (tRNS)
|
|
||||||
{
|
{
|
||||||
pos += 4; // go after the 4 letters
|
pos += 4; // go after the 4 letters
|
||||||
if(info.colorType == 3)
|
if (info.colorType == 3) {
|
||||||
{
|
if (4 * chunkLength > info.palette.size()) {
|
||||||
if(4 * chunkLength > info.palette.size()) { error = 39; return; } //error: more alpha values given than there are palette entries
|
error = 39;
|
||||||
for(size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++];
|
return;
|
||||||
}
|
} // error: more alpha values given than there are palette entries
|
||||||
else if(info.colorType == 0)
|
for (size_t i = 0; i < chunkLength; i++)
|
||||||
{
|
info.palette[4 * i + 3] = in[pos++];
|
||||||
if(chunkLength != 2) { error = 40; return; } //error: this chunk must be 2 bytes for greyscale image
|
} else if (info.colorType == 0) {
|
||||||
info.key_defined = 1; info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
|
if (chunkLength != 2) {
|
||||||
}
|
error = 40;
|
||||||
else if(info.colorType == 2)
|
return;
|
||||||
{
|
} // error: this chunk must be 2 bytes for greyscale image
|
||||||
if(chunkLength != 6) { error = 41; return; } //error: this chunk must be 6 bytes for RGB image
|
|
||||||
info.key_defined = 1;
|
info.key_defined = 1;
|
||||||
info.key_r = 256 * in[pos] + in[pos + 1]; pos += 2;
|
info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1];
|
||||||
info.key_g = 256 * in[pos] + in[pos + 1]; pos += 2;
|
pos += 2;
|
||||||
info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
|
} else if (info.colorType == 2) {
|
||||||
}
|
if (chunkLength != 6) {
|
||||||
else { error = 42; return; } //error: tRNS chunk not allowed for other color models
|
error = 41;
|
||||||
}
|
return;
|
||||||
else //it's not an implemented chunk type, so ignore it: skip over the data
|
} // error: this chunk must be 6 bytes for RGB image
|
||||||
|
info.key_defined = 1;
|
||||||
|
info.key_r = 256 * in[pos] + in[pos + 1];
|
||||||
|
pos += 2;
|
||||||
|
info.key_g = 256 * in[pos] + in[pos + 1];
|
||||||
|
pos += 2;
|
||||||
|
info.key_b = 256 * in[pos] + in[pos + 1];
|
||||||
|
pos += 2;
|
||||||
|
} else {
|
||||||
|
error = 42;
|
||||||
|
return;
|
||||||
|
} // error: tRNS chunk not allowed for other color models
|
||||||
|
} else // it's not an implemented chunk type, so ignore it: skip over the data
|
||||||
{
|
{
|
||||||
if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0)
|
if (!(in[pos + 0] & 32)) {
|
||||||
|
error = 69;
|
||||||
|
return;
|
||||||
|
} // error: unknown critical chunk (5th bit of first byte of chunk type is 0)
|
||||||
pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
|
pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
|
||||||
known_type = false;
|
known_type = false;
|
||||||
}
|
}
|
||||||
@ -318,29 +465,34 @@ int decodePNG(unsigned char* &out_image, int& image_width, int& image_height, co
|
|||||||
unsigned long bpp = getBpp(info);
|
unsigned long bpp = getBpp(info);
|
||||||
std::vector<unsigned char> scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); // now the out buffer will be filled
|
std::vector<unsigned char> scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); // now the out buffer will be filled
|
||||||
Zlib zlib; // decompress with the Zlib decompressor
|
Zlib zlib; // decompress with the Zlib decompressor
|
||||||
error = zlib.decompress(scanlines, idat); if(error) return; //stop if the zlib decompressor returned an error
|
error = zlib.decompress(scanlines, idat);
|
||||||
|
if (error)
|
||||||
|
return; // stop if the zlib decompressor returned an error
|
||||||
size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8;
|
size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8;
|
||||||
out = new unsigned char[outlength + 1]; // time to fill the out buffer
|
out = new unsigned char[outlength + 1]; // time to fill the out buffer
|
||||||
if (info.interlaceMethod == 0) // no interlace, just filter
|
if (info.interlaceMethod == 0) // no interlace, just filter
|
||||||
{
|
{
|
||||||
size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; // length in bytes of a scanline, excluding the filtertype byte
|
size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; // length in bytes of a scanline, excluding the filtertype byte
|
||||||
if (bpp >= 8) // byte per byte
|
if (bpp >= 8) // byte per byte
|
||||||
for(unsigned long y = 0; y < info.height; y++)
|
for (unsigned long y = 0; y < info.height; y++) {
|
||||||
{
|
|
||||||
unsigned long filterType = scanlines[linestart];
|
unsigned long filterType = scanlines[linestart];
|
||||||
const unsigned char* prevline = (y == 0) ? 0 : &out[(y - 1) * info.width * bytewidth];
|
const unsigned char* prevline = (y == 0) ? 0 : &out[(y - 1) * info.width * bytewidth];
|
||||||
unFilterScanline(&out[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
|
unFilterScanline(&out[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength);
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
linestart += (1 + linelength); // go to start of next scanline
|
linestart += (1 + linelength); // go to start of next scanline
|
||||||
}
|
}
|
||||||
else // less than 8 bits per pixel, so fill it up bit per bit
|
else // less than 8 bits per pixel, so fill it up bit per bit
|
||||||
{
|
{
|
||||||
unsigned char* templine = new unsigned char[((info.width * bpp + 7) >> 3) + 1]; // only used if bpp < 8
|
unsigned char* templine = new unsigned char[((info.width * bpp + 7) >> 3) + 1]; // only used if bpp < 8
|
||||||
for(size_t y = 0, obp = 0; y < info.height; y++)
|
for (size_t y = 0, obp = 0; y < info.height; y++) {
|
||||||
{
|
|
||||||
unsigned long filterType = scanlines[linestart];
|
unsigned long filterType = scanlines[linestart];
|
||||||
const unsigned char* prevline = (y == 0) ? 0 : &out[(y - 1) * info.width * bytewidth];
|
const unsigned char* prevline = (y == 0) ? 0 : &out[(y - 1) * info.width * bytewidth];
|
||||||
unFilterScanline(templine, &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
|
unFilterScanline(templine, &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength);
|
||||||
for(size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &templine[0]));
|
if (error)
|
||||||
|
return;
|
||||||
|
for (size_t bp = 0; bp < info.width * bpp;)
|
||||||
|
setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &templine[0]));
|
||||||
linestart += (1 + linelength); // go to start of next scanline
|
linestart += (1 + linelength); // go to start of next scanline
|
||||||
}
|
}
|
||||||
delete[] templine;
|
delete[] templine;
|
||||||
@ -354,149 +506,210 @@ int decodePNG(unsigned char* &out_image, int& image_width, int& image_height, co
|
|||||||
}
|
}
|
||||||
void readPngHeader(const unsigned char* in, size_t inlength) // read the information from the header and store it in the Info
|
void readPngHeader(const unsigned char* in, size_t inlength) // read the information from the header and store it in the Info
|
||||||
{
|
{
|
||||||
if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
|
if (inlength < 29) {
|
||||||
if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature
|
error = 27;
|
||||||
if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; } //error: it doesn't start with a IHDR chunk!
|
return;
|
||||||
info.width = read32bitInt(&in[16]); info.height = read32bitInt(&in[20]);
|
} // error: the data length is smaller than the length of the header
|
||||||
info.bitDepth = in[24]; info.colorType = in[25];
|
if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) {
|
||||||
info.compressionMethod = in[26]; if(in[26] != 0) { error = 32; return; } //error: only compression method 0 is allowed in the specification
|
error = 28;
|
||||||
info.filterMethod = in[27]; if(in[27] != 0) { error = 33; return; } //error: only filter method 0 is allowed in the specification
|
return;
|
||||||
info.interlaceMethod = in[28]; if(in[28] > 1) { error = 34; return; } //error: only interlace methods 0 and 1 exist in the specification
|
} // no PNG signature
|
||||||
|
if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') {
|
||||||
|
error = 29;
|
||||||
|
return;
|
||||||
|
} // error: it doesn't start with a IHDR chunk!
|
||||||
|
info.width = read32bitInt(&in[16]);
|
||||||
|
info.height = read32bitInt(&in[20]);
|
||||||
|
info.bitDepth = in[24];
|
||||||
|
info.colorType = in[25];
|
||||||
|
info.compressionMethod = in[26];
|
||||||
|
if (in[26] != 0) {
|
||||||
|
error = 32;
|
||||||
|
return;
|
||||||
|
} // error: only compression method 0 is allowed in the specification
|
||||||
|
info.filterMethod = in[27];
|
||||||
|
if (in[27] != 0) {
|
||||||
|
error = 33;
|
||||||
|
return;
|
||||||
|
} // error: only filter method 0 is allowed in the specification
|
||||||
|
info.interlaceMethod = in[28];
|
||||||
|
if (in[28] > 1) {
|
||||||
|
error = 34;
|
||||||
|
return;
|
||||||
|
} // error: only interlace methods 0 and 1 exist in the specification
|
||||||
error = checkColorValidity(info.colorType, info.bitDepth);
|
error = checkColorValidity(info.colorType, info.bitDepth);
|
||||||
}
|
}
|
||||||
void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned long filterType, size_t length)
|
void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned long filterType, size_t length) {
|
||||||
{
|
switch (filterType) {
|
||||||
switch(filterType)
|
case 0:
|
||||||
{
|
for (size_t i = 0; i < length; i++)
|
||||||
case 0: for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; break;
|
recon[i] = scanline[i];
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
|
for (size_t i = 0; i < bytewidth; i++)
|
||||||
for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
|
recon[i] = scanline[i];
|
||||||
|
for (size_t i = bytewidth; i < length; i++)
|
||||||
|
recon[i] = scanline[i] + recon[i - bytewidth];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if(precon) for(size_t i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
|
if (precon)
|
||||||
else for(size_t i = 0; i < length; i++) recon[i] = scanline[i];
|
for (size_t i = 0; i < length; i++)
|
||||||
|
recon[i] = scanline[i] + precon[i];
|
||||||
|
else
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
recon[i] = scanline[i];
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if(precon)
|
if (precon) {
|
||||||
{
|
for (size_t i = 0; i < bytewidth; i++)
|
||||||
for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
|
recon[i] = scanline[i] + precon[i] / 2;
|
||||||
for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
|
for (size_t i = bytewidth; i < length; i++)
|
||||||
}
|
recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
|
||||||
else
|
} else {
|
||||||
{
|
for (size_t i = 0; i < bytewidth; i++)
|
||||||
for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
|
recon[i] = scanline[i];
|
||||||
for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
|
for (size_t i = bytewidth; i < length; i++)
|
||||||
|
recon[i] = scanline[i] + recon[i - bytewidth] / 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if(precon)
|
if (precon) {
|
||||||
{
|
for (size_t i = 0; i < bytewidth; i++)
|
||||||
for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + paethPredictor(0, precon[i], 0);
|
recon[i] = scanline[i] + paethPredictor(0, precon[i], 0);
|
||||||
for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]);
|
for (size_t i = bytewidth; i < length; i++)
|
||||||
}
|
recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]);
|
||||||
else
|
} else {
|
||||||
{
|
for (size_t i = 0; i < bytewidth; i++)
|
||||||
for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
|
recon[i] = scanline[i];
|
||||||
for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0);
|
for (size_t i = bytewidth; i < length; i++)
|
||||||
|
recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: error = 36; return; //error: unexisting filter type given
|
default:
|
||||||
|
error = 36;
|
||||||
|
return; // error: unexisting filter type given
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; bitp++; return result;}
|
static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) {
|
||||||
static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits)
|
unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1;
|
||||||
{
|
bitp++;
|
||||||
unsigned long result = 0;
|
|
||||||
for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) { bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++; }
|
static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits) {
|
||||||
|
unsigned long result = 0;
|
||||||
|
for (size_t i = nbits - 1; i < nbits; i--)
|
||||||
|
result += ((readBitFromReversedStream(bitp, bits)) << i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) {
|
||||||
|
bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7)));
|
||||||
|
bitp++;
|
||||||
|
}
|
||||||
unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; }
|
unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; }
|
||||||
int checkColorValidity(unsigned long colorType, unsigned long bd) // return type is a LodePNG error code
|
int checkColorValidity(unsigned long colorType, unsigned long bd) // return type is a LodePNG error code
|
||||||
{
|
{
|
||||||
if((colorType == 2 || colorType == 4 || colorType == 6)) { if(!(bd == 8 || bd == 16)) return 37; else return 0; }
|
if ((colorType == 2 || colorType == 4 || colorType == 6)) {
|
||||||
else if(colorType == 0) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; else return 0; }
|
if (!(bd == 8 || bd == 16))
|
||||||
else if(colorType == 3) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; else return 0; }
|
return 37;
|
||||||
else return 31; //unexisting color type
|
else
|
||||||
|
return 0;
|
||||||
|
} else if (colorType == 0) {
|
||||||
|
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
|
||||||
|
return 37;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else if (colorType == 3) {
|
||||||
|
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
|
||||||
|
return 37;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return 31; // unexisting color type
|
||||||
}
|
}
|
||||||
unsigned long getBpp(const Info& info)
|
unsigned long getBpp(const Info& info) {
|
||||||
{
|
if (info.colorType == 2)
|
||||||
if(info.colorType == 2) return (3 * info.bitDepth);
|
return (3 * info.bitDepth);
|
||||||
else if(info.colorType >= 4) return (info.colorType - 2) * info.bitDepth;
|
else if (info.colorType >= 4)
|
||||||
else return info.bitDepth;
|
return (info.colorType - 2) * info.bitDepth;
|
||||||
|
else
|
||||||
|
return info.bitDepth;
|
||||||
}
|
}
|
||||||
int convert(unsigned char* &out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h)
|
int convert(unsigned char*& out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h) { // converts from any color type to 32-bit. return value = LodePNG error code
|
||||||
{ //converts from any color type to 32-bit. return value = LodePNG error code
|
|
||||||
size_t numpixels = w * h, bp = 0;
|
size_t numpixels = w * h, bp = 0;
|
||||||
out = new unsigned char[numpixels * 4 + 1];
|
out = new unsigned char[numpixels * 4 + 1];
|
||||||
if (infoIn.bitDepth == 8 && infoIn.colorType == 0) // greyscale
|
if (infoIn.bitDepth == 8 && infoIn.colorType == 0) // greyscale
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
|
||||||
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[i];
|
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[i];
|
||||||
out[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255;
|
out[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255;
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth == 8 && infoIn.colorType == 2) // RGB color
|
else if (infoIn.bitDepth == 8 && infoIn.colorType == 2) // RGB color
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
for (size_t c = 0; c < 3; c++)
|
||||||
for(size_t c = 0; c < 3; c++) out[4 * i + c] = in[3 * i + c];
|
out[4 * i + c] = in[3 * i + c];
|
||||||
out[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255;
|
out[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255;
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth == 8 && infoIn.colorType == 3) // indexed color (palette)
|
else if (infoIn.bitDepth == 8 && infoIn.colorType == 3) // indexed color (palette)
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
if (4U * in[i] >= infoIn.palette.size())
|
||||||
if(4U * in[i] >= infoIn.palette.size()) return 46;
|
return 46;
|
||||||
for(size_t c = 0; c < 4; c++) out[4 * i + c] = infoIn.palette[4 * in[i] + c]; //get rgb colors from the palette
|
for (size_t c = 0; c < 4; c++)
|
||||||
|
out[4 * i + c] = infoIn.palette[4 * in[i] + c]; // get rgb colors from the palette
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth == 8 && infoIn.colorType == 4) // greyscale with alpha
|
else if (infoIn.bitDepth == 8 && infoIn.colorType == 4) // greyscale with alpha
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
|
||||||
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[2 * i + 0];
|
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[2 * i + 0];
|
||||||
out[4 * i + 3] = in[2 * i + 1];
|
out[4 * i + 3] = in[2 * i + 1];
|
||||||
}
|
}
|
||||||
else if(infoIn.bitDepth == 8 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out[4 * i + c] = in[4 * i + c]; //RGB with alpha
|
else if (infoIn.bitDepth == 8 && infoIn.colorType == 6)
|
||||||
else if(infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale
|
|
||||||
for (size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++)
|
||||||
{
|
for (size_t c = 0; c < 4; c++)
|
||||||
|
out[4 * i + c] = in[4 * i + c]; // RGB with alpha
|
||||||
|
else if (infoIn.bitDepth == 16 && infoIn.colorType == 0) // greyscale
|
||||||
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[2 * i];
|
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[2 * i];
|
||||||
out[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255;
|
out[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255;
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth == 16 && infoIn.colorType == 2) // RGB color
|
else if (infoIn.bitDepth == 16 && infoIn.colorType == 2) // RGB color
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
for (size_t c = 0; c < 3; c++)
|
||||||
for(size_t c = 0; c < 3; c++) out[4 * i + c] = in[6 * i + 2 * c];
|
out[4 * i + c] = in[6 * i + 2 * c];
|
||||||
out[4 * i + 3] = (infoIn.key_defined && 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn.key_r && 256U * in[6 * i + 2] + in[6 * i + 3] == infoIn.key_g && 256U * in[6 * i + 4] + in[6 * i + 5] == infoIn.key_b) ? 0 : 255;
|
out[4 * i + 3] = (infoIn.key_defined && 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn.key_r && 256U * in[6 * i + 2] + in[6 * i + 3] == infoIn.key_g && 256U * in[6 * i + 4] + in[6 * i + 5] == infoIn.key_b) ? 0 : 255;
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth == 16 && infoIn.colorType == 4) // greyscale with alpha
|
else if (infoIn.bitDepth == 16 && infoIn.colorType == 4) // greyscale with alpha
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
|
||||||
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[4 * i]; // most significant byte
|
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = in[4 * i]; // most significant byte
|
||||||
out[4 * i + 3] = in[4 * i + 2];
|
out[4 * i + 3] = in[4 * i + 2];
|
||||||
}
|
}
|
||||||
else if(infoIn.bitDepth == 16 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha
|
else if (infoIn.bitDepth == 16 && infoIn.colorType == 6)
|
||||||
else if(infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale
|
|
||||||
for (size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++)
|
||||||
{
|
for (size_t c = 0; c < 4; c++)
|
||||||
|
out[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
|
||||||
|
else if (infoIn.bitDepth < 8 && infoIn.colorType == 0) // greyscale
|
||||||
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); // scale value from 0 to 255
|
unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); // scale value from 0 to 255
|
||||||
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = (unsigned char)(value);
|
out[4 * i + 0] = out[4 * i + 1] = out[4 * i + 2] = (unsigned char)(value);
|
||||||
out[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255;
|
out[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255;
|
||||||
}
|
}
|
||||||
else if (infoIn.bitDepth < 8 && infoIn.colorType == 3) // palette
|
else if (infoIn.bitDepth < 8 && infoIn.colorType == 3) // palette
|
||||||
for(size_t i = 0; i < numpixels; i++)
|
for (size_t i = 0; i < numpixels; i++) {
|
||||||
{
|
|
||||||
unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth);
|
unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth);
|
||||||
if(4 * value >= infoIn.palette.size()) return 47;
|
if (4 * value >= infoIn.palette.size())
|
||||||
for(size_t c = 0; c < 4; c++) out[4 * i + c] = infoIn.palette[4 * value + c]; //get rgb colors from the palette
|
return 47;
|
||||||
|
for (size_t c = 0; c < 4; c++)
|
||||||
|
out[4 * i + c] = infoIn.palette[4 * value + c]; // get rgb colors from the palette
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
unsigned char paethPredictor(short a, short b, short c) // Paeth predicter, used by PNG filter type 4
|
unsigned char paethPredictor(short a, short b, short c) // Paeth predicter, used by PNG filter type 4
|
||||||
{
|
{
|
||||||
short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = p > c ? (p - c) : (c - p);
|
short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = p > c ? (p - c) : (c - p);
|
||||||
return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c);
|
return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b
|
||||||
|
: c);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PNG decoder; decoder.decode(out_image, in_png, in_size, convert_to_rgba32);
|
PNG decoder;
|
||||||
image_width = decoder.info.width; image_height = decoder.info.height;
|
decoder.decode(out_image, in_png, in_size, convert_to_rgba32);
|
||||||
|
image_width = decoder.info.width;
|
||||||
|
image_height = decoder.info.height;
|
||||||
return decoder.error;
|
return decoder.error;
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,19 @@
|
|||||||
Copyright (c) 2018 nullworks. All rights reserved.
|
Copyright (c) 2018 nullworks. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glez/texture.hpp>
|
|
||||||
#include <glez/glez.hpp>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <vector>
|
|
||||||
#include <glez/picopng/picopng.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <glez/glez.hpp>
|
||||||
|
#include <glez/picopng/picopng.hpp>
|
||||||
|
#include <glez/texture.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <fstream> // required to load the file
|
#include <fstream> // required to load the file
|
||||||
|
|
||||||
namespace glez
|
namespace glez {
|
||||||
{
|
|
||||||
|
|
||||||
void texture::bind()
|
void texture::bind() {
|
||||||
{
|
|
||||||
if (!bound) {
|
if (!bound) {
|
||||||
glGenTextures(1, &id);
|
glGenTextures(1, &id);
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
@ -62,7 +60,6 @@ texture texture::loadFromFile(const std::string &path) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
texture texture::loadFromMemory(const std::byte* mem, std::size_t size, unsigned w, unsigned h) {
|
texture texture::loadFromMemory(const std::byte* mem, std::size_t size, unsigned w, unsigned h) {
|
||||||
if (size < 1)
|
if (size < 1)
|
||||||
throw std::runtime_error("Unable to load texture from memory!");
|
throw std::runtime_error("Unable to load texture from memory!");
|
||||||
@ -105,4 +102,4 @@ texture& texture::operator=(texture&& var) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glez::detail::texture
|
} // namespace glez
|
||||||
|
Loading…
x
Reference in New Issue
Block a user