mirror of
https://github.com/joel16/VITAlbum.git
synced 2024-11-23 03:29:54 +00:00
textures: Switch to loading animated images and static images from sdl2_image and remove unused libs
This commit is contained in:
parent
217bbc8299
commit
f6710038d9
@ -20,7 +20,7 @@ add_definitions(-DAPP_VERSION="${VITA_VERSION}")
|
||||
add_definitions(
|
||||
-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_DISABLE_DEMO_WINDOWS -DIMGUI_DISABLE_DEBUG_TOOLS
|
||||
-DIMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS -DIMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
|
||||
-DIMGUI_DISABLE_WIN32_FUNCTIONS -DIMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
-DIMGUI_DISABLE_WIN32_FUNCTIONS -DIMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION -DIMGUI_DISABLE_SSE
|
||||
-DIMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS -DIMGUI_ENABLE_FREETYPE
|
||||
)
|
||||
|
||||
@ -32,10 +32,9 @@ find_package(SDL2 REQUIRED)
|
||||
include_directories(
|
||||
${VITASDK}/arm-vita-eabi/include/freetype2/
|
||||
${SDL2_INCLUDE_DIR}
|
||||
libs/giflib
|
||||
${SDL2_IMAGE_INCLUDE_DIRS}
|
||||
libs/imgui
|
||||
libs/imgui/backends
|
||||
libs/libnsbmp
|
||||
libs/libtiff
|
||||
libs
|
||||
include
|
||||
@ -54,7 +53,6 @@ add_executable(${PROJECT_NAME}
|
||||
libs/imgui/backends/imgui_impl_sdl2.cpp
|
||||
libs/imgui/backends/imgui_impl_sdlrenderer2.cpp
|
||||
libs/imgui/misc/freetype/imgui_freetype.cpp
|
||||
libs/libnsbmp/libnsbmp.c
|
||||
source/config.cpp
|
||||
source/fs.cpp
|
||||
source/gui.cpp
|
||||
@ -73,7 +71,6 @@ add_executable(${PROJECT_NAME}
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
freetype
|
||||
bz2
|
||||
gif
|
||||
tiff
|
||||
webpdemux
|
||||
webp
|
||||
@ -85,6 +82,8 @@ target_link_libraries(${PROJECT_NAME}
|
||||
lzma
|
||||
z
|
||||
zstd
|
||||
SDL2_image
|
||||
webpdemux
|
||||
SDL2::SDL2-static
|
||||
SceLibJson_stub
|
||||
)
|
||||
|
@ -3,20 +3,24 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <psp2common/types.h>
|
||||
#include <SDL.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <psp2common/types.h>
|
||||
#include <SDL_image.h>
|
||||
|
||||
typedef struct {
|
||||
SDL_Texture *ptr;
|
||||
SDL_Texture *ptr = nullptr;
|
||||
SDL_Texture **frames = nullptr;
|
||||
IMG_Animation *anim = nullptr;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
SceUInt delay = 0; // microseconds
|
||||
} Tex;
|
||||
|
||||
extern std::vector<Tex> icons;
|
||||
extern unsigned const FOLDER, IMAGE;
|
||||
|
||||
namespace Textures {
|
||||
bool LoadImageFile(const std::string &path, std::vector<Tex> &textures);
|
||||
bool LoadImageFile(const std::string &path, Tex &texture);
|
||||
void Free(Tex &texture);
|
||||
void Init(void);
|
||||
void Exit(void);
|
||||
|
@ -24,7 +24,7 @@ typedef struct {
|
||||
WINDOW_STATES state = WINDOW_STATE_FILEBROWSER;
|
||||
SceOff selected = 0;
|
||||
std::vector<SceIoDirent> entries;
|
||||
std::vector<Tex> textures;
|
||||
Tex texture;
|
||||
unsigned int frame_count = 0;
|
||||
float zoom_factor = 1.0f;
|
||||
} WindowData;
|
||||
|
@ -1,303 +0,0 @@
|
||||
/******************************************************************************
|
||||
|
||||
gif_lib.h - service library for decoding and encoding GIF images
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_H_
|
||||
#define _GIF_LIB_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GIFLIB_MAJOR 5
|
||||
#define GIFLIB_MINOR 2
|
||||
#define GIFLIB_RELEASE 1
|
||||
|
||||
#define GIF_ERROR 0
|
||||
#define GIF_OK 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
|
||||
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char *GifRowType;
|
||||
typedef unsigned char GifByteType;
|
||||
typedef unsigned int GifPrefixType;
|
||||
typedef int GifWord;
|
||||
|
||||
typedef struct GifColorType {
|
||||
GifByteType Red, Green, Blue;
|
||||
} GifColorType;
|
||||
|
||||
typedef struct ColorMapObject {
|
||||
int ColorCount;
|
||||
int BitsPerPixel;
|
||||
bool SortFlag;
|
||||
GifColorType *Colors; /* on malloc(3) heap */
|
||||
} ColorMapObject;
|
||||
|
||||
typedef struct GifImageDesc {
|
||||
GifWord Left, Top, Width, Height; /* Current image dimensions. */
|
||||
bool Interlace; /* Sequential/Interlaced lines. */
|
||||
ColorMapObject *ColorMap; /* The local color map */
|
||||
} GifImageDesc;
|
||||
|
||||
typedef struct ExtensionBlock {
|
||||
int ByteCount;
|
||||
GifByteType *Bytes; /* on malloc(3) heap */
|
||||
int Function; /* The block function code */
|
||||
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
|
||||
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
|
||||
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
|
||||
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block (GIF89) */
|
||||
} ExtensionBlock;
|
||||
|
||||
typedef struct SavedImage {
|
||||
GifImageDesc ImageDesc;
|
||||
GifByteType *RasterBits; /* on malloc(3) heap */
|
||||
int ExtensionBlockCount; /* Count of extensions before image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
|
||||
} SavedImage;
|
||||
|
||||
typedef struct GifFileType {
|
||||
GifWord SWidth, SHeight; /* Size of virtual canvas */
|
||||
GifWord SColorResolution; /* How many colors can we generate? */
|
||||
GifWord SBackGroundColor; /* Background color for virtual canvas */
|
||||
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
|
||||
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
|
||||
int ImageCount; /* Number of current image (both APIs) */
|
||||
GifImageDesc Image; /* Current image (low-level API) */
|
||||
SavedImage *SavedImages; /* Image sequence (high-level API) */
|
||||
int ExtensionBlockCount; /* Count extensions past last image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
|
||||
int Error; /* Last error condition reported */
|
||||
void *UserData; /* hook to attach user data (TVT) */
|
||||
void *Private; /* Don't mess with this! */
|
||||
} GifFileType;
|
||||
|
||||
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED_RECORD_TYPE,
|
||||
SCREEN_DESC_RECORD_TYPE,
|
||||
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||
} GifRecordType;
|
||||
|
||||
/* func type to read gif data from arbitrary sources (TVT) */
|
||||
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
|
||||
|
||||
/* func type to write gif data to arbitrary targets.
|
||||
* Returns count of bytes written. (MRB)
|
||||
*/
|
||||
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
|
||||
|
||||
/******************************************************************************
|
||||
GIF89 structures
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct GraphicsControlBlock {
|
||||
int DisposalMode;
|
||||
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
|
||||
#define DISPOSE_DO_NOT 1 /* Leave image in place */
|
||||
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
|
||||
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
|
||||
bool UserInputFlag; /* User confirmation required before disposal */
|
||||
int DelayTime; /* pre-display delay in 0.01sec units */
|
||||
int TransparentColor; /* Palette index for transparency, -1 if none */
|
||||
#define NO_TRANSPARENT_COLOR -1
|
||||
} GraphicsControlBlock;
|
||||
|
||||
/******************************************************************************
|
||||
GIF encoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *EGifOpenFileName(const char *GifFileName,
|
||||
const bool GifTestExistence, int *Error);
|
||||
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
|
||||
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
|
||||
int EGifSpew(GifFileType * GifFile);
|
||||
const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
|
||||
int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
|
||||
|
||||
#define E_GIF_SUCCEEDED 0
|
||||
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||
#define E_GIF_ERR_WRITE_FAILED 2
|
||||
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const int GifColorRes,
|
||||
const int GifBackGround,
|
||||
const ColorMapObject *GifColorMap);
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
const int GifLeft, const int GifTop,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const bool GifInterlace,
|
||||
const ColorMapObject *GifColorMap);
|
||||
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
|
||||
int GifLineLen);
|
||||
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
|
||||
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
|
||||
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
|
||||
int EGifPutExtensionBlock(GifFileType *GifFile,
|
||||
const int GifExtLen, const void *GifExtension);
|
||||
int EGifPutExtensionTrailer(GifFileType *GifFile);
|
||||
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
|
||||
const int GifExtLen,
|
||||
const void *GifExtension);
|
||||
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||
const GifByteType *GifCodeBlock);
|
||||
int EGifPutCodeNext(GifFileType *GifFile,
|
||||
const GifByteType *GifCodeBlock);
|
||||
|
||||
/******************************************************************************
|
||||
GIF decoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
|
||||
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
|
||||
int DGifSlurp(GifFileType * GifFile);
|
||||
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
|
||||
int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
|
||||
|
||||
#define D_GIF_SUCCEEDED 0
|
||||
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||
#define D_GIF_ERR_READ_FAILED 102
|
||||
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||
#define D_GIF_ERR_WRONG_RECORD 107
|
||||
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||
#define D_GIF_ERR_NOT_READABLE 111
|
||||
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||
int DGifGetImageHeader(GifFileType *GifFile);
|
||||
int DGifGetImageDesc(GifFileType *GifFile);
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||
GifByteType **GifExtension);
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
|
||||
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||
GifByteType **GifCodeBlock);
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||
const char *DGifGetGifVersion(GifFileType *GifFile);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Error handling and reporting.
|
||||
******************************************************************************/
|
||||
extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
|
||||
|
||||
/*****************************************************************************
|
||||
Everything below this point is new after version 1.2, supporting `slurp
|
||||
mode' for doing I/O in two big belts with all the image-bashing in core.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Color map handling from gif_alloc.c
|
||||
******************************************************************************/
|
||||
|
||||
extern ColorMapObject *GifMakeMapObject(int ColorCount,
|
||||
const GifColorType *ColorMap);
|
||||
extern void GifFreeMapObject(ColorMapObject *Object);
|
||||
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[]);
|
||||
extern int GifBitSize(int n);
|
||||
|
||||
/******************************************************************************
|
||||
Support for the in-core structures allocation (slurp mode).
|
||||
******************************************************************************/
|
||||
|
||||
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
|
||||
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len, unsigned char ExtData[]);
|
||||
extern void GifFreeExtensions(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks);
|
||||
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
|
||||
const SavedImage *CopyFrom);
|
||||
extern void GifFreeSavedImages(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
5.x functions for GIF89 graphics control blocks
|
||||
******************************************************************************/
|
||||
|
||||
int DGifExtensionToGCB(const size_t GifExtensionLength,
|
||||
const GifByteType *GifExtension,
|
||||
GraphicsControlBlock *GCB);
|
||||
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
|
||||
GifByteType *GifExtension);
|
||||
|
||||
int DGifSavedExtensionToGCB(GifFileType *GifFile,
|
||||
int ImageIndex,
|
||||
GraphicsControlBlock *GCB);
|
||||
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
|
||||
GifFileType *GifFile,
|
||||
int ImageIndex);
|
||||
|
||||
/******************************************************************************
|
||||
The library's internal utility font
|
||||
******************************************************************************/
|
||||
|
||||
#define GIF_FONT_WIDTH 8
|
||||
#define GIF_FONT_HEIGHT 8
|
||||
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
|
||||
|
||||
extern void GifDrawText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend, const int color);
|
||||
|
||||
extern void GifDrawBox(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawRectangle(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawBoxedText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int border, const int bg, const int fg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* _GIF_LIB_H */
|
||||
|
||||
/* end */
|
Binary file not shown.
@ -1,20 +0,0 @@
|
||||
Copyright (C) 2006 Richard Wilson
|
||||
Copyright (C) 2008 Sean Fox
|
||||
|
||||
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.
|
File diff suppressed because it is too large
Load Diff
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Richard Wilson <richard.wilson@netsurf-browser.org>
|
||||
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
|
||||
*
|
||||
* This file is part of NetSurf's libnsbmp, http://www.netsurf-browser.org/
|
||||
* Licenced under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Bitmap file decoding interface.
|
||||
*/
|
||||
|
||||
#ifndef libnsbmp_h_
|
||||
#define libnsbmp_h_
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* bmp flags */
|
||||
#define BMP_NEW 0
|
||||
/** image is opaque (as opposed to having an alpha mask) */
|
||||
#define BMP_OPAQUE (1 << 0)
|
||||
/** memory should be wiped */
|
||||
#define BMP_CLEAR_MEMORY (1 << 1)
|
||||
|
||||
/**
|
||||
* error return values
|
||||
*/
|
||||
typedef enum {
|
||||
BMP_OK = 0,
|
||||
BMP_INSUFFICIENT_MEMORY = 1,
|
||||
BMP_INSUFFICIENT_DATA = 2,
|
||||
BMP_DATA_ERROR = 3
|
||||
} bmp_result;
|
||||
|
||||
/**
|
||||
* encoding types
|
||||
*/
|
||||
typedef enum {
|
||||
BMP_ENCODING_RGB = 0,
|
||||
BMP_ENCODING_RLE8 = 1,
|
||||
BMP_ENCODING_RLE4 = 2,
|
||||
BMP_ENCODING_BITFIELDS = 3
|
||||
} bmp_encoding;
|
||||
|
||||
/* API for Bitmap callbacks */
|
||||
typedef void* (*bmp_bitmap_cb_create)(int width, int height, unsigned int state);
|
||||
typedef void (*bmp_bitmap_cb_destroy)(void *bitmap);
|
||||
typedef unsigned char* (*bmp_bitmap_cb_get_buffer)(void *bitmap);
|
||||
typedef size_t (*bmp_bitmap_cb_get_bpp)(void *bitmap);
|
||||
|
||||
/**
|
||||
* The Bitmap callbacks function table
|
||||
*/
|
||||
typedef struct bmp_bitmap_callback_vt_s {
|
||||
/** Callback to allocate bitmap storage. */
|
||||
bmp_bitmap_cb_create bitmap_create;
|
||||
/** Called to free bitmap storage. */
|
||||
bmp_bitmap_cb_destroy bitmap_destroy;
|
||||
/** Return a pointer to the pixel data in a bitmap. */
|
||||
bmp_bitmap_cb_get_buffer bitmap_get_buffer;
|
||||
/** Find the width of a pixel row in bytes. */
|
||||
bmp_bitmap_cb_get_bpp bitmap_get_bpp;
|
||||
} bmp_bitmap_callback_vt;
|
||||
|
||||
/**
|
||||
* bitmap image
|
||||
*/
|
||||
typedef struct bmp_image {
|
||||
/** callbacks for bitmap functions */
|
||||
bmp_bitmap_callback_vt bitmap_callbacks;
|
||||
/** pointer to BMP data */
|
||||
uint8_t *bmp_data;
|
||||
/** width of BMP (valid after _analyse) */
|
||||
uint32_t width;
|
||||
/** heigth of BMP (valid after _analyse) */
|
||||
uint32_t height;
|
||||
/** whether the image has been decoded */
|
||||
bool decoded;
|
||||
/** decoded image */
|
||||
void *bitmap;
|
||||
|
||||
/* Internal members are listed below */
|
||||
/** total number of bytes of BMP data available */
|
||||
uint32_t buffer_size;
|
||||
/** pixel encoding type */
|
||||
bmp_encoding encoding;
|
||||
/** offset of bitmap data */
|
||||
uint32_t bitmap_offset;
|
||||
/** bits per pixel */
|
||||
uint16_t bpp;
|
||||
/** number of colours */
|
||||
uint32_t colours;
|
||||
/** colour table */
|
||||
uint32_t *colour_table;
|
||||
/** whether to use bmp's limited transparency */
|
||||
bool limited_trans;
|
||||
/** colour to display for "transparent" pixels when using limited
|
||||
* transparency
|
||||
*/
|
||||
uint32_t trans_colour;
|
||||
/** scanlines are top to bottom */
|
||||
bool reversed;
|
||||
/** image is part of an ICO, mask follows */
|
||||
bool ico;
|
||||
/** true if the bitmap does not contain an alpha channel */
|
||||
bool opaque;
|
||||
/** four bitwise mask */
|
||||
uint32_t mask[4];
|
||||
/** four bitwise shifts */
|
||||
int32_t shift[4];
|
||||
/** colour representing "transparency" in the bitmap */
|
||||
uint32_t transparent_index;
|
||||
} bmp_image;
|
||||
|
||||
typedef struct ico_image {
|
||||
bmp_image bmp;
|
||||
struct ico_image *next;
|
||||
} ico_image;
|
||||
|
||||
/**
|
||||
* icon image collection
|
||||
*/
|
||||
typedef struct ico_collection {
|
||||
/** callbacks for bitmap functions */
|
||||
bmp_bitmap_callback_vt bitmap_callbacks;
|
||||
/** width of largest BMP */
|
||||
uint16_t width;
|
||||
/** heigth of largest BMP */
|
||||
uint16_t height;
|
||||
|
||||
/* Internal members are listed below */
|
||||
/** pointer to ICO data */
|
||||
uint8_t *ico_data;
|
||||
/** total number of bytes of ICO data available */
|
||||
uint32_t buffer_size;
|
||||
/** root of linked list of images */
|
||||
ico_image *first;
|
||||
} ico_collection;
|
||||
|
||||
/**
|
||||
* Initialises bitmap ready for analysing the bitmap.
|
||||
*
|
||||
* \param bmp The Bitmap to initialise
|
||||
* \param callbacks The callbacks the library will call on operations.
|
||||
* \return BMP_OK on success or appropriate error code.
|
||||
*/
|
||||
bmp_result bmp_create(bmp_image *bmp, bmp_bitmap_callback_vt *callbacks);
|
||||
|
||||
/**
|
||||
* Initialises icon ready for analysing the icon
|
||||
*
|
||||
* \param bmp The Bitmap to initialise
|
||||
* \param callbacks The callbacks the library will call on operations.
|
||||
* \return BMP_OK on success or appropriate error code.
|
||||
*/
|
||||
bmp_result ico_collection_create(ico_collection *ico,
|
||||
bmp_bitmap_callback_vt *callbacks);
|
||||
|
||||
/**
|
||||
* Analyse a BMP prior to decoding.
|
||||
*
|
||||
* This will scan the data provided and perform checks to ensure the data is a
|
||||
* valid BMP and prepare the bitmap image structure ready for decode.
|
||||
*
|
||||
* This function must be called and resturn BMP_OK before bmp_decode() as it
|
||||
* prepares the bmp internal state for the decode process.
|
||||
*
|
||||
* \param bmp the BMP image to analyse.
|
||||
* \param size The size of data in cdata.
|
||||
* \param data The bitmap source data.
|
||||
* \return BMP_OK on success or error code on faliure.
|
||||
*/
|
||||
bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data);
|
||||
|
||||
/**
|
||||
* Analyse an ICO prior to decoding.
|
||||
*
|
||||
* This function will scan the data provided and perform checks to ensure the
|
||||
* data is a valid ICO.
|
||||
*
|
||||
* This function must be called before ico_find().
|
||||
*
|
||||
* \param ico the ICO image to analyse
|
||||
* \param size The size of data in cdata.
|
||||
* \param data The bitmap source data.
|
||||
* \return BMP_OK on success
|
||||
*/
|
||||
bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data);
|
||||
|
||||
/**
|
||||
* Decode a BMP
|
||||
*
|
||||
* This function decodes the BMP data such that bmp->bitmap is a valid
|
||||
* image. The state of bmp->decoded is set to TRUE on exit such that it
|
||||
* can easily be identified which BMPs are in a fully decoded state.
|
||||
*
|
||||
* \param bmp the BMP image to decode
|
||||
* \return BMP_OK on success
|
||||
*/
|
||||
bmp_result bmp_decode(bmp_image *bmp);
|
||||
|
||||
/**
|
||||
* Decode a BMP using "limited transparency"
|
||||
*
|
||||
* Bitmaps do not have native transparency support. However, there is a
|
||||
* "trick" that is used in some instances in which the first pixel of the
|
||||
* bitmap becomes the "transparency index". The decoding application can
|
||||
* replace this index with whatever background colour it chooses to
|
||||
* create the illusion of transparency.
|
||||
*
|
||||
* When to use transparency is at the discretion of the decoding
|
||||
* application.
|
||||
*
|
||||
* \param bmp the BMP image to decode
|
||||
* \param colour the colour to use as "transparent"
|
||||
* \return BMP_OK on success
|
||||
*/
|
||||
bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t transparent_colour);
|
||||
|
||||
/**
|
||||
* Finds the closest BMP within an ICO collection
|
||||
*
|
||||
* This function finds the BMP with dimensions as close to a specified set
|
||||
* as possible from the images in the collection.
|
||||
*
|
||||
* \param ico the ICO collection to examine
|
||||
* \param width the preferred width (0 to use ICO header width)
|
||||
* \param height the preferred height (0 to use ICO header height)
|
||||
*/
|
||||
bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height);
|
||||
|
||||
/**
|
||||
* Finalise a BMP prior to destruction.
|
||||
*
|
||||
* \param bmp the BMP image to finalise.
|
||||
*/
|
||||
void bmp_finalise(bmp_image *bmp);
|
||||
|
||||
/**
|
||||
* Finalise an ICO prior to destruction.
|
||||
*
|
||||
* \param ico the ICO image to finalise,
|
||||
*/
|
||||
void ico_finalise(ico_collection *ico);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
|
||||
*
|
||||
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
||||
* Licenced under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _LIBNSBMP_LOG_H_
|
||||
#define _LIBNSBMP_LOG_H_
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define LOG(x) ((void) 0)
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0)
|
||||
# elif defined(__CC_NORCROFT)
|
||||
# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0)
|
||||
# else
|
||||
# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
3008
libs/nanosvg.h
3008
libs/nanosvg.h
File diff suppressed because it is too large
Load Diff
1452
libs/nanosvgrast.h
1452
libs/nanosvgrast.h
File diff suppressed because it is too large
Load Diff
355
libs/stb_image.h
355
libs/stb_image.h
@ -1,4 +1,4 @@
|
||||
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
|
||||
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
@ -48,6 +48,8 @@ LICENSE
|
||||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.30 (2024-05-31) avoid erroneous gcc warning
|
||||
2.29 (2023-05-xx) optimizations
|
||||
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||
2.26 (2020-07-13) many minor fixes
|
||||
@ -1072,8 +1074,8 @@ static int stbi__addints_valid(int a, int b)
|
||||
return a <= INT_MAX - b;
|
||||
}
|
||||
|
||||
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
|
||||
static int stbi__mul2shorts_valid(short a, short b)
|
||||
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
|
||||
static int stbi__mul2shorts_valid(int a, int b)
|
||||
{
|
||||
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
||||
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
||||
@ -3384,13 +3386,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
||||
static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
||||
{
|
||||
// some JPEGs have junk at end, skip over it but if we find what looks
|
||||
// like a valid marker, resume there
|
||||
while (!stbi__at_eof(j->s)) {
|
||||
int x = stbi__get8(j->s);
|
||||
while (x == 255) { // might be a marker
|
||||
stbi_uc x = stbi__get8(j->s);
|
||||
while (x == 0xff) { // might be a marker
|
||||
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
||||
x = stbi__get8(j->s);
|
||||
if (x != 0x00 && x != 0xff) {
|
||||
@ -4176,6 +4178,7 @@ typedef struct
|
||||
{
|
||||
stbi_uc *zbuffer, *zbuffer_end;
|
||||
int num_bits;
|
||||
int hit_zeof_once;
|
||||
stbi__uint32 code_buffer;
|
||||
|
||||
char *zout;
|
||||
@ -4242,9 +4245,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
|
||||
int b,s;
|
||||
if (a->num_bits < 16) {
|
||||
if (stbi__zeof(a)) {
|
||||
return -1; /* report error for unexpected end of data. */
|
||||
if (!a->hit_zeof_once) {
|
||||
// This is the first time we hit eof, insert 16 extra padding btis
|
||||
// to allow us to keep going; if we actually consume any of them
|
||||
// though, that is invalid data. This is caught later.
|
||||
a->hit_zeof_once = 1;
|
||||
a->num_bits += 16; // add 16 implicit zero bits
|
||||
} else {
|
||||
// We already inserted our extra 16 padding bits and are again
|
||||
// out, this stream is actually prematurely terminated.
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
stbi__fill_bits(a);
|
||||
}
|
||||
stbi__fill_bits(a);
|
||||
}
|
||||
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
||||
if (b) {
|
||||
@ -4309,6 +4323,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||
int len,dist;
|
||||
if (z == 256) {
|
||||
a->zout = zout;
|
||||
if (a->hit_zeof_once && a->num_bits < 16) {
|
||||
// The first time we hit zeof, we inserted 16 extra zero bits into our bit
|
||||
// buffer so the decoder can just do its speculative decoding. But if we
|
||||
// actually consumed any of those bits (which is the case when num_bits < 16),
|
||||
// the stream actually read past the end so it is malformed.
|
||||
return stbi__err("unexpected end","Corrupt PNG");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
||||
@ -4320,7 +4341,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||
dist = stbi__zdist_base[z];
|
||||
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
||||
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
||||
if (zout + len > a->zout_end) {
|
||||
if (len > a->zout_end - zout) {
|
||||
if (!stbi__zexpand(a, zout, len)) return 0;
|
||||
zout = a->zout;
|
||||
}
|
||||
@ -4464,6 +4485,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
|
||||
if (!stbi__parse_zlib_header(a)) return 0;
|
||||
a->num_bits = 0;
|
||||
a->code_buffer = 0;
|
||||
a->hit_zeof_once = 0;
|
||||
do {
|
||||
final = stbi__zreceive(a,1);
|
||||
type = stbi__zreceive(a,2);
|
||||
@ -4619,9 +4641,8 @@ enum {
|
||||
STBI__F_up=2,
|
||||
STBI__F_avg=3,
|
||||
STBI__F_paeth=4,
|
||||
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
|
||||
STBI__F_avg_first,
|
||||
STBI__F_paeth_first
|
||||
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
|
||||
STBI__F_avg_first
|
||||
};
|
||||
|
||||
static stbi_uc first_row_filter[5] =
|
||||
@ -4630,29 +4651,56 @@ static stbi_uc first_row_filter[5] =
|
||||
STBI__F_sub,
|
||||
STBI__F_none,
|
||||
STBI__F_avg_first,
|
||||
STBI__F_paeth_first
|
||||
STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
|
||||
};
|
||||
|
||||
static int stbi__paeth(int a, int b, int c)
|
||||
{
|
||||
int p = a + b - c;
|
||||
int pa = abs(p-a);
|
||||
int pb = abs(p-b);
|
||||
int pc = abs(p-c);
|
||||
if (pa <= pb && pa <= pc) return a;
|
||||
if (pb <= pc) return b;
|
||||
return c;
|
||||
// This formulation looks very different from the reference in the PNG spec, but is
|
||||
// actually equivalent and has favorable data dependencies and admits straightforward
|
||||
// generation of branch-free code, which helps performance significantly.
|
||||
int thresh = c*3 - (a + b);
|
||||
int lo = a < b ? a : b;
|
||||
int hi = a < b ? b : a;
|
||||
int t0 = (hi <= thresh) ? lo : c;
|
||||
int t1 = (thresh <= lo) ? hi : t0;
|
||||
return t1;
|
||||
}
|
||||
|
||||
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
||||
|
||||
// adds an extra all-255 alpha channel
|
||||
// dest == src is legal
|
||||
// img_n must be 1 or 3
|
||||
static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
|
||||
{
|
||||
int i;
|
||||
// must process data backwards since we allow dest==src
|
||||
if (img_n == 1) {
|
||||
for (i=x-1; i >= 0; --i) {
|
||||
dest[i*2+1] = 255;
|
||||
dest[i*2+0] = src[i];
|
||||
}
|
||||
} else {
|
||||
STBI_ASSERT(img_n == 3);
|
||||
for (i=x-1; i >= 0; --i) {
|
||||
dest[i*4+3] = 255;
|
||||
dest[i*4+2] = src[i*3+2];
|
||||
dest[i*4+1] = src[i*3+1];
|
||||
dest[i*4+0] = src[i*3+0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the png data from post-deflated data
|
||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
||||
{
|
||||
int bytes = (depth == 16? 2 : 1);
|
||||
int bytes = (depth == 16 ? 2 : 1);
|
||||
stbi__context *s = a->s;
|
||||
stbi__uint32 i,j,stride = x*out_n*bytes;
|
||||
stbi__uint32 img_len, img_width_bytes;
|
||||
stbi_uc *filter_buf;
|
||||
int all_ok = 1;
|
||||
int k;
|
||||
int img_n = s->img_n; // copy it into a local for later
|
||||
|
||||
@ -4664,8 +4712,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
||||
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
||||
|
||||
// note: error exits here don't need to clean up a->out individually,
|
||||
// stbi__do_png always does on error.
|
||||
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
||||
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
||||
if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
|
||||
img_len = (img_width_bytes + 1) * y;
|
||||
|
||||
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
||||
@ -4673,189 +4724,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||
// so just check for raw_len < img_len always.
|
||||
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
|
||||
// Allocate two scan lines worth of filter workspace buffer.
|
||||
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
|
||||
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
|
||||
|
||||
// Filtering for low-bit-depth images
|
||||
if (depth < 8) {
|
||||
filter_bytes = 1;
|
||||
width = img_width_bytes;
|
||||
}
|
||||
|
||||
for (j=0; j < y; ++j) {
|
||||
stbi_uc *cur = a->out + stride*j;
|
||||
stbi_uc *prior;
|
||||
// cur/prior filter buffers alternate
|
||||
stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
|
||||
stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
|
||||
stbi_uc *dest = a->out + stride*j;
|
||||
int nk = width * filter_bytes;
|
||||
int filter = *raw++;
|
||||
|
||||
if (filter > 4)
|
||||
return stbi__err("invalid filter","Corrupt PNG");
|
||||
|
||||
if (depth < 8) {
|
||||
if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
|
||||
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
|
||||
filter_bytes = 1;
|
||||
width = img_width_bytes;
|
||||
// check filter type
|
||||
if (filter > 4) {
|
||||
all_ok = stbi__err("invalid filter","Corrupt PNG");
|
||||
break;
|
||||
}
|
||||
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
|
||||
|
||||
// if first row, use special filter that doesn't sample previous row
|
||||
if (j == 0) filter = first_row_filter[filter];
|
||||
|
||||
// handle first byte explicitly
|
||||
for (k=0; k < filter_bytes; ++k) {
|
||||
switch (filter) {
|
||||
case STBI__F_none : cur[k] = raw[k]; break;
|
||||
case STBI__F_sub : cur[k] = raw[k]; break;
|
||||
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
||||
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
||||
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
||||
}
|
||||
// perform actual filtering
|
||||
switch (filter) {
|
||||
case STBI__F_none:
|
||||
memcpy(cur, raw, nk);
|
||||
break;
|
||||
case STBI__F_sub:
|
||||
memcpy(cur, raw, filter_bytes);
|
||||
for (k = filter_bytes; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
|
||||
break;
|
||||
case STBI__F_up:
|
||||
for (k = 0; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
|
||||
break;
|
||||
case STBI__F_avg:
|
||||
for (k = 0; k < filter_bytes; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
|
||||
for (k = filter_bytes; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
|
||||
break;
|
||||
case STBI__F_paeth:
|
||||
for (k = 0; k < filter_bytes; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
|
||||
for (k = filter_bytes; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
|
||||
break;
|
||||
case STBI__F_avg_first:
|
||||
memcpy(cur, raw, filter_bytes);
|
||||
for (k = filter_bytes; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
|
||||
break;
|
||||
}
|
||||
|
||||
if (depth == 8) {
|
||||
if (img_n != out_n)
|
||||
cur[img_n] = 255; // first pixel
|
||||
raw += img_n;
|
||||
cur += out_n;
|
||||
prior += out_n;
|
||||
} else if (depth == 16) {
|
||||
if (img_n != out_n) {
|
||||
cur[filter_bytes] = 255; // first pixel top byte
|
||||
cur[filter_bytes+1] = 255; // first pixel bottom byte
|
||||
}
|
||||
raw += filter_bytes;
|
||||
cur += output_bytes;
|
||||
prior += output_bytes;
|
||||
} else {
|
||||
raw += 1;
|
||||
cur += 1;
|
||||
prior += 1;
|
||||
}
|
||||
raw += nk;
|
||||
|
||||
// this is a little gross, so that we don't switch per-pixel or per-component
|
||||
if (depth < 8 || img_n == out_n) {
|
||||
int nk = (width - 1)*filter_bytes;
|
||||
#define STBI__CASE(f) \
|
||||
case f: \
|
||||
for (k=0; k < nk; ++k)
|
||||
switch (filter) {
|
||||
// "none" filter turns into a memcpy here; make that explicit.
|
||||
case STBI__F_none: memcpy(cur, raw, nk); break;
|
||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
|
||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
|
||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
|
||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
|
||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
|
||||
}
|
||||
#undef STBI__CASE
|
||||
raw += nk;
|
||||
} else {
|
||||
STBI_ASSERT(img_n+1 == out_n);
|
||||
#define STBI__CASE(f) \
|
||||
case f: \
|
||||
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
|
||||
for (k=0; k < filter_bytes; ++k)
|
||||
switch (filter) {
|
||||
STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
|
||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
|
||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
|
||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
|
||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
|
||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
|
||||
}
|
||||
#undef STBI__CASE
|
||||
|
||||
// the loop above sets the high byte of the pixels' alpha, but for
|
||||
// 16 bit png files we also need the low byte set. we'll do that here.
|
||||
if (depth == 16) {
|
||||
cur = a->out + stride*j; // start at the beginning of the row again
|
||||
for (i=0; i < x; ++i,cur+=output_bytes) {
|
||||
cur[filter_bytes+1] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we make a separate pass to expand bits to pixels; for performance,
|
||||
// this could run two scanlines behind the above code, so it won't
|
||||
// intefere with filtering but will still be in the cache.
|
||||
if (depth < 8) {
|
||||
for (j=0; j < y; ++j) {
|
||||
stbi_uc *cur = a->out + stride*j;
|
||||
stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
|
||||
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
|
||||
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
|
||||
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
|
||||
if (depth < 8) {
|
||||
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
|
||||
stbi_uc *in = cur;
|
||||
stbi_uc *out = dest;
|
||||
stbi_uc inb = 0;
|
||||
stbi__uint32 nsmp = x*img_n;
|
||||
|
||||
// note that the final byte might overshoot and write more data than desired.
|
||||
// we can allocate enough data that this never writes out of memory, but it
|
||||
// could also overwrite the next scanline. can it overwrite non-empty data
|
||||
// on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
|
||||
// so we need to explicitly clamp the final ones
|
||||
|
||||
// expand bits to bytes first
|
||||
if (depth == 4) {
|
||||
for (k=x*img_n; k >= 2; k-=2, ++in) {
|
||||
*cur++ = scale * ((*in >> 4) );
|
||||
*cur++ = scale * ((*in ) & 0x0f);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 1) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 4);
|
||||
inb <<= 4;
|
||||
}
|
||||
if (k > 0) *cur++ = scale * ((*in >> 4) );
|
||||
} else if (depth == 2) {
|
||||
for (k=x*img_n; k >= 4; k-=4, ++in) {
|
||||
*cur++ = scale * ((*in >> 6) );
|
||||
*cur++ = scale * ((*in >> 4) & 0x03);
|
||||
*cur++ = scale * ((*in >> 2) & 0x03);
|
||||
*cur++ = scale * ((*in ) & 0x03);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 3) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 6);
|
||||
inb <<= 2;
|
||||
}
|
||||
if (k > 0) *cur++ = scale * ((*in >> 6) );
|
||||
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
|
||||
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
|
||||
} else if (depth == 1) {
|
||||
for (k=x*img_n; k >= 8; k-=8, ++in) {
|
||||
*cur++ = scale * ((*in >> 7) );
|
||||
*cur++ = scale * ((*in >> 6) & 0x01);
|
||||
*cur++ = scale * ((*in >> 5) & 0x01);
|
||||
*cur++ = scale * ((*in >> 4) & 0x01);
|
||||
*cur++ = scale * ((*in >> 3) & 0x01);
|
||||
*cur++ = scale * ((*in >> 2) & 0x01);
|
||||
*cur++ = scale * ((*in >> 1) & 0x01);
|
||||
*cur++ = scale * ((*in ) & 0x01);
|
||||
} else {
|
||||
STBI_ASSERT(depth == 1);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 7) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 7);
|
||||
inb <<= 1;
|
||||
}
|
||||
if (k > 0) *cur++ = scale * ((*in >> 7) );
|
||||
if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
|
||||
if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
|
||||
if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
|
||||
if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
|
||||
if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
|
||||
if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
|
||||
}
|
||||
if (img_n != out_n) {
|
||||
int q;
|
||||
// insert alpha = 255
|
||||
cur = a->out + stride*j;
|
||||
|
||||
// insert alpha=255 values if desired
|
||||
if (img_n != out_n)
|
||||
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
|
||||
} else if (depth == 8) {
|
||||
if (img_n == out_n)
|
||||
memcpy(dest, cur, x*img_n);
|
||||
else
|
||||
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
|
||||
} else if (depth == 16) {
|
||||
// convert the image data from big-endian to platform-native
|
||||
stbi__uint16 *dest16 = (stbi__uint16*)dest;
|
||||
stbi__uint32 nsmp = x*img_n;
|
||||
|
||||
if (img_n == out_n) {
|
||||
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
|
||||
*dest16 = (cur[0] << 8) | cur[1];
|
||||
} else {
|
||||
STBI_ASSERT(img_n+1 == out_n);
|
||||
if (img_n == 1) {
|
||||
for (q=x-1; q >= 0; --q) {
|
||||
cur[q*2+1] = 255;
|
||||
cur[q*2+0] = cur[q];
|
||||
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
|
||||
dest16[0] = (cur[0] << 8) | cur[1];
|
||||
dest16[1] = 0xffff;
|
||||
}
|
||||
} else {
|
||||
STBI_ASSERT(img_n == 3);
|
||||
for (q=x-1; q >= 0; --q) {
|
||||
cur[q*4+3] = 255;
|
||||
cur[q*4+2] = cur[q*3+2];
|
||||
cur[q*4+1] = cur[q*3+1];
|
||||
cur[q*4+0] = cur[q*3+0];
|
||||
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
|
||||
dest16[0] = (cur[0] << 8) | cur[1];
|
||||
dest16[1] = (cur[2] << 8) | cur[3];
|
||||
dest16[2] = (cur[4] << 8) | cur[5];
|
||||
dest16[3] = 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (depth == 16) {
|
||||
// force the image data from big-endian to platform-native.
|
||||
// this is done in a separate pass due to the decoding relying
|
||||
// on the data being untouched, but could probably be done
|
||||
// per-line during decode if care is taken.
|
||||
stbi_uc *cur = a->out;
|
||||
stbi__uint16 *cur16 = (stbi__uint16*)cur;
|
||||
|
||||
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
|
||||
*cur16 = (cur[0] << 8) | cur[1];
|
||||
}
|
||||
}
|
||||
|
||||
STBI_FREE(filter_buf);
|
||||
if (!all_ok) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -5161,9 +5160,11 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
|
||||
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
|
||||
if (z->depth == 16) {
|
||||
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
|
||||
for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning
|
||||
tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
|
||||
} else {
|
||||
for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
|
||||
for (k = 0; k < s->img_n && k < 3; ++k)
|
||||
tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -7,31 +7,37 @@
|
||||
#include "windows.h"
|
||||
|
||||
namespace Windows {
|
||||
static int delay = 0;
|
||||
static int current_frame = 0;
|
||||
|
||||
void ImageViewer(WindowData &data) {
|
||||
Windows::SetupWindow();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGuiWindowFlags_ filename_flag = !cfg.image_filename? ImGuiWindowFlags_NoTitleBar : ImGuiWindowFlags_None;
|
||||
|
||||
if (ImGui::Begin(data.entries[data.selected].d_name, nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_HorizontalScrollbar | filename_flag)) {
|
||||
if (((data.textures[0].width * data.zoom_factor) <= 960.0f) && ((data.textures[0].height * data.zoom_factor) <= 544.0f))
|
||||
ImGui::SetCursorPos((ImGui::GetContentRegionAvail() - ImVec2((data.textures[0].width * data.zoom_factor),
|
||||
(data.textures[0].height * data.zoom_factor))) * 0.5f);
|
||||
if (((data.texture.width * data.zoom_factor) <= 960.0f) && ((data.texture.height * data.zoom_factor) <= 544.0f))
|
||||
ImGui::SetCursorPos((ImGui::GetContentRegionAvail() - ImVec2((data.texture.width * data.zoom_factor),
|
||||
(data.texture.height * data.zoom_factor))) * 0.5f);
|
||||
|
||||
if (data.textures.size() > 1) {
|
||||
sceKernelDelayThread(data.textures[data.frame_count].delay);
|
||||
if (data.texture.frames) {
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.texture.frames[current_frame]), ImVec2(data.texture.width * data.zoom_factor, data.texture.height * data.zoom_factor));
|
||||
|
||||
if (data.texture.anim) {
|
||||
if (data.texture.anim->delays[current_frame]) {
|
||||
delay = data.texture.anim->delays[current_frame];
|
||||
}
|
||||
else {
|
||||
delay = 100;
|
||||
}
|
||||
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.textures[data.frame_count].ptr), ImVec2(data.textures[0].width * data.zoom_factor,
|
||||
data.textures[0].height * data.zoom_factor));
|
||||
|
||||
data.frame_count++;
|
||||
|
||||
// Reset frame counter
|
||||
if (data.frame_count == data.textures.size() - 1) {
|
||||
data.frame_count = 0;
|
||||
sceKernelDelayThread(delay * 1000);
|
||||
}
|
||||
|
||||
current_frame = (current_frame + 1) % data.texture.anim->count;
|
||||
}
|
||||
else {
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.textures[0].ptr), ImVec2(data.textures[0].width * data.zoom_factor, data.textures[0].height * data.zoom_factor));
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.texture.ptr), ImVec2(data.texture.width * data.zoom_factor, data.texture.height * data.zoom_factor));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ namespace Tabs {
|
||||
}
|
||||
else {
|
||||
std::string path = FS::BuildPath(data.entries[i]);
|
||||
bool ret = Textures::LoadImageFile(path, data.textures);
|
||||
bool ret = Textures::LoadImageFile(path, data.texture);
|
||||
IM_ASSERT(ret);
|
||||
data.state = WINDOW_STATE_IMAGEVIEWER;
|
||||
}
|
||||
|
@ -2,23 +2,6 @@
|
||||
#include <memory>
|
||||
#include <psp2/kernel/clib.h>
|
||||
|
||||
// BMP
|
||||
#include "libnsbmp.h"
|
||||
|
||||
// GIF
|
||||
#include "gif_lib.h"
|
||||
|
||||
// JPEG
|
||||
#include "turbojpeg.h"
|
||||
|
||||
// PCX
|
||||
#define DR_PCX_IMPLEMENTATION
|
||||
#define DR_PCX_NO_STDIO
|
||||
#include "dr_pcx.h"
|
||||
|
||||
// PNG
|
||||
#include <png.h>
|
||||
|
||||
// STB
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_NO_STDIO
|
||||
@ -28,26 +11,15 @@
|
||||
#define STBI_NO_JPEG
|
||||
#define STBI_NO_PIC
|
||||
#define STBI_NO_PNG
|
||||
#define STBI_ONLY_PNM
|
||||
#define STBI_NO_PNM
|
||||
#define STBI_NO_TGA
|
||||
#define STBI_ONLY_PSD
|
||||
#define STBI_ONLY_TGA
|
||||
#include "stb_image.h"
|
||||
|
||||
// SVG
|
||||
#define NANOSVG_ALL_COLOR_KEYWORDS
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvgrast.h"
|
||||
|
||||
// TIFF
|
||||
#include "tiffio.h"
|
||||
#include "tiffiop.h"
|
||||
|
||||
// WEBP
|
||||
#include <webp/decode.h>
|
||||
#include <webp/demux.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
@ -55,94 +27,17 @@
|
||||
#include "textures.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define BYTES_PER_PIXEL 4
|
||||
#define MAX_IMAGE_BYTES (48 * 1024 * 1024)
|
||||
|
||||
std::vector<Tex> icons;
|
||||
unsigned const FOLDER = 0, IMAGE = 1;
|
||||
|
||||
namespace BMP {
|
||||
static void *bitmap_create(int width, int height, [[maybe_unused]] unsigned int state) {
|
||||
/* ensure a stupidly large (>50Megs or so) bitmap is not created */
|
||||
if ((static_cast<long long>(width) * static_cast<long long>(height)) > (MAX_IMAGE_BYTES/BYTES_PER_PIXEL)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::calloc(width * height, BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
static unsigned char *bitmap_get_buffer(void *bitmap) {
|
||||
assert(bitmap);
|
||||
return static_cast<unsigned char*>(bitmap);
|
||||
}
|
||||
|
||||
static size_t bitmap_get_bpp([[maybe_unused]] void *bitmap) {
|
||||
return BYTES_PER_PIXEL;
|
||||
}
|
||||
|
||||
static void bitmap_destroy(void *bitmap) {
|
||||
assert(bitmap);
|
||||
std::free(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
namespace ICO {
|
||||
static void *bitmap_create(int width, int height, [[maybe_unused]] unsigned int state) {
|
||||
return std::calloc(width * height, BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
static unsigned char *bitmap_get_buffer(void *bitmap) {
|
||||
assert(bitmap);
|
||||
return static_cast<unsigned char*>(bitmap);
|
||||
}
|
||||
|
||||
static size_t bitmap_get_bpp([[maybe_unused]] void *bitmap) {
|
||||
return BYTES_PER_PIXEL;
|
||||
}
|
||||
|
||||
static void bitmap_destroy(void *bitmap) {
|
||||
assert(bitmap);
|
||||
std::free(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Textures {
|
||||
int GL_RGB = 3, GL_RGBA = 4;
|
||||
|
||||
static bool Create(unsigned char *data, int format, Tex &texture) {
|
||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(
|
||||
(void *)data,
|
||||
static bool Create(unsigned char *data, Tex &texture) {
|
||||
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(
|
||||
data,
|
||||
texture.width,
|
||||
texture.height,
|
||||
format * 8,
|
||||
format * texture.width,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000
|
||||
);
|
||||
|
||||
if (surface == nullptr) {
|
||||
Log::Error("Failed to create SDL surface: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
texture.ptr = SDL_CreateTextureFromSurface(GUI::GetRenderer(), surface);
|
||||
if ((texture.ptr) == nullptr) {
|
||||
Log::Error("Failed to create SDL texture: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Create(unsigned char *data, int format, Tex &texture, int width, int height) {
|
||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(
|
||||
(void *)data,
|
||||
width,
|
||||
height,
|
||||
format * 8,
|
||||
format * width,
|
||||
32,
|
||||
texture.width * 4,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
@ -157,6 +52,8 @@ namespace Textures {
|
||||
texture.ptr = SDL_CreateTextureFromSurface(GUI::GetRenderer(), surface);
|
||||
if (texture.ptr == nullptr) {
|
||||
Log::Error("Failed to create SDL texture: %s\n", SDL_GetError());
|
||||
SDL_FreeSurface(surface);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
@ -165,272 +62,64 @@ namespace Textures {
|
||||
|
||||
static bool LoadImageOther(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
stbi_uc *image = nullptr;
|
||||
image = stbi_load_from_memory(*data, size, &texture.width, &texture.height, nullptr, BYTES_PER_PIXEL);
|
||||
bool ret = Textures::Create(image, GL_RGBA, texture);
|
||||
image = stbi_load_from_memory(*data, size, &texture.width, &texture.height, nullptr, STBI_rgb_alpha);
|
||||
bool ret = Textures::Create(image, texture);
|
||||
stbi_image_free(image);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageBMP(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
bmp_bitmap_callback_vt bitmap_callbacks = {
|
||||
BMP::bitmap_create,
|
||||
BMP::bitmap_destroy,
|
||||
BMP::bitmap_get_buffer,
|
||||
BMP::bitmap_get_bpp
|
||||
};
|
||||
static bool LoadImageAnim(const std::string &path, Tex &texture) {
|
||||
texture.anim = IMG_LoadAnimation(path.c_str());
|
||||
if (!texture.anim) {
|
||||
Log::Error("Couldn't load %s: %s\n", path.c_str(), SDL_GetError());
|
||||
}
|
||||
|
||||
bmp_result code = BMP_OK;
|
||||
bmp_image bmp;
|
||||
bmp_create(&bmp, &bitmap_callbacks);
|
||||
|
||||
code = bmp_analyse(&bmp, size, *data);
|
||||
if (code != BMP_OK) {
|
||||
Log::Error("bmp_analyse failed: %d\n", code);
|
||||
bmp_finalise(&bmp);
|
||||
texture.width = texture.anim->w;
|
||||
texture.height = texture.anim->h;
|
||||
texture.frames = (SDL_Texture **)SDL_calloc(texture.anim->count, sizeof(*texture.frames));
|
||||
|
||||
if (!texture.frames) {
|
||||
Log::Error("Couldn't allocate textures\n");
|
||||
IMG_FreeAnimation(texture.anim);
|
||||
return false;
|
||||
}
|
||||
|
||||
code = bmp_decode(&bmp);
|
||||
if (code != BMP_OK) {
|
||||
if ((code != BMP_INSUFFICIENT_DATA) && (code != BMP_DATA_ERROR)) {
|
||||
Log::Error("bmp_decode failed: %d\n", code);
|
||||
bmp_finalise(&bmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* skip if the decoded image would be ridiculously large */
|
||||
if ((bmp.width * bmp.height) > 200000) {
|
||||
Log::Error("bmp_decode failed: width*height is over 200000\n");
|
||||
bmp_finalise(&bmp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
texture.width = bmp.width;
|
||||
texture.height = bmp.height;
|
||||
bool ret = Textures::Create(static_cast<unsigned char*>(bmp.bitmap), GL_RGBA, texture);
|
||||
bmp_finalise(&bmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageGIF(const std::string &path, std::vector<Tex> &textures) {
|
||||
bool ret = false;
|
||||
int error = 0;
|
||||
GifFileType *gif = DGifOpenFileName(path.c_str(), &error);
|
||||
|
||||
if (!gif) {
|
||||
Log::Error("DGifOpenFileName failed: %d\n", error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (DGifSlurp(gif) != GIF_OK) {
|
||||
Log::Error("DGifSlurp failed: %d\n", gif->Error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gif->ImageCount <= 0) {
|
||||
Log::Error("Gif does not contain any images.\n");
|
||||
return ret;
|
||||
|
||||
for (int i = 0; i < texture.anim->count; ++i) {
|
||||
texture.frames[i] = SDL_CreateTextureFromSurface(GUI::GetRenderer(), texture.anim->frames[i]);
|
||||
}
|
||||
|
||||
textures.resize(gif->ImageCount);
|
||||
|
||||
// seiken's example code from:
|
||||
// https://forums.somethingawful.com/showthread.php?threadid=2773485&userid=0&perpage=40&pagenumber=487#post465199820
|
||||
textures[0].width = gif->SWidth;
|
||||
textures[0].height = gif->SHeight;
|
||||
std::unique_ptr<SceUInt32[]> pixels(new SceUInt32[textures[0].width * textures[0].height]);
|
||||
|
||||
for (int i = 0; i < textures[0].width * textures[0].height; ++i) {
|
||||
pixels[i] = gif->SBackGroundColor;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gif->ImageCount; ++i) {
|
||||
const SavedImage &frame = gif->SavedImages[i];
|
||||
bool transparency = false;
|
||||
unsigned char transparency_byte = 0;
|
||||
|
||||
// Delay time in hundredths of a second.
|
||||
int delay_time = 1;
|
||||
for (int j = 0; j < frame.ExtensionBlockCount; ++j) {
|
||||
const ExtensionBlock &block = frame.ExtensionBlocks[j];
|
||||
|
||||
if (block.Function != GRAPHICS_EXT_FUNC_CODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Here's the metadata for this frame.
|
||||
char dispose = (block.Bytes[0] >> 2) & 7;
|
||||
transparency = block.Bytes[0] & 1;
|
||||
delay_time = block.Bytes[1] + (block.Bytes[2] << 8);
|
||||
transparency_byte = block.Bytes[3];
|
||||
|
||||
if (dispose == 2) {
|
||||
// Clear the canvas.
|
||||
for (int k = 0; k < textures[0].width * textures[0].height; ++k)
|
||||
pixels[k] = gif->SBackGroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
// Colour map for this frame.
|
||||
ColorMapObject *map = frame.ImageDesc.ColorMap ? frame.ImageDesc.ColorMap : gif->SColorMap;
|
||||
|
||||
// Region this frame draws to.
|
||||
int fw = frame.ImageDesc.Width;
|
||||
int fh = frame.ImageDesc.Height;
|
||||
int fl = frame.ImageDesc.Left;
|
||||
int ft = frame.ImageDesc.Top;
|
||||
|
||||
for (int y = 0; y < std::min(textures[0].height, fh); ++y) {
|
||||
for (int x = 0; x < std::min(textures[0].width, fw); ++x) {
|
||||
unsigned char byte = frame.RasterBits[x + y * fw];
|
||||
|
||||
// Transparent pixel.
|
||||
if (transparency && byte == transparency_byte) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Draw to canvas.
|
||||
const GifColorType &c = map->Colors[byte];
|
||||
pixels[fl + x + (ft + y) * textures[0].width] = c.Red | (c.Green << 8) | (c.Blue << 16) | (0xff << 24);
|
||||
}
|
||||
}
|
||||
|
||||
textures[i].delay = delay_time * 10000;
|
||||
|
||||
// Here's the actual frame, pixels.get() is now a pointer to the 32-bit RGBA
|
||||
// data for this frame you might expect.
|
||||
ret = Textures::Create(reinterpret_cast<unsigned char*>(pixels.get()), GL_RGBA, textures[i], textures[0].width, textures[0].height);
|
||||
}
|
||||
|
||||
if (DGifCloseFile(gif, &error) != GIF_OK) {
|
||||
Log::Error("DGifCloseFile failed: %d\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadImageICO(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
bmp_bitmap_callback_vt bitmap_callbacks = {
|
||||
ICO::bitmap_create,
|
||||
ICO::bitmap_destroy,
|
||||
ICO::bitmap_get_buffer,
|
||||
ICO::bitmap_get_bpp
|
||||
};
|
||||
|
||||
SceUInt16 width = 0, height = 0;
|
||||
ico_collection ico;
|
||||
bmp_result code = BMP_OK;
|
||||
bmp_image *bmp;
|
||||
static bool LoadImage(const std::string &path, Tex &texture) {
|
||||
texture.ptr = IMG_LoadTexture(GUI::GetRenderer(), path.c_str());
|
||||
|
||||
ico_collection_create(&ico, &bitmap_callbacks);
|
||||
|
||||
code = ico_analyse(&ico, size, *data);
|
||||
if (code != BMP_OK) {
|
||||
Log::Error("ico_analyse failed: %d\n", code);
|
||||
ico_finalise(&ico);
|
||||
if (!texture.ptr) {
|
||||
Log::Error("Couldn't load %s: %s\n", path.c_str(), SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bmp = ico_find(&ico, width, height);
|
||||
assert(bmp);
|
||||
|
||||
code = bmp_decode(bmp);
|
||||
if (code != BMP_OK) {
|
||||
if ((code != BMP_INSUFFICIENT_DATA) && (code != BMP_DATA_ERROR)) {
|
||||
Log::Error("bmp_decode failed: %d\n", code);
|
||||
ico_finalise(&ico);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* skip if the decoded image would be ridiculously large */
|
||||
if ((bmp->width * bmp->height) > 200000) {
|
||||
Log::Error("bmp_decode failed: width*height is over 200000\n");
|
||||
ico_finalise(&ico);
|
||||
delete[] *data;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
texture.width = bmp->width;
|
||||
texture.height = bmp->height;
|
||||
bool ret = Textures::Create(static_cast<unsigned char*>(bmp->bitmap), GL_RGBA, texture);
|
||||
ico_finalise(&ico);
|
||||
return ret;
|
||||
SDL_QueryTexture(texture.ptr, nullptr, nullptr, &texture.width, &texture.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadImageJPEG(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
tjhandle jpeg = tjInitDecompress();
|
||||
int jpegsubsamp = 0;
|
||||
|
||||
if (R_FAILED(tjDecompressHeader2(jpeg, *data, size, &texture.width, &texture.height, &jpegsubsamp))) {
|
||||
Log::Error("tjDecompressHeader2 failed: %s\n", tjGetErrorStr());
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<unsigned char[]> buffer(new unsigned char[texture.width * texture.height * 3]);
|
||||
if (R_FAILED(tjDecompress2(jpeg, *data, size, buffer.get(), texture.width, 0, texture.height, TJPF_RGB, TJFLAG_FASTDCT))) {
|
||||
Log::Error("tjDecompress2 failed: %s\n", tjGetErrorStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = Textures::Create(buffer.get(), GL_RGB, texture);
|
||||
tjDestroy(jpeg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImagePCX(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
*data = drpcx_load_memory(*data, size, DRPCX_FALSE, &texture.width, &texture.height, nullptr, BYTES_PER_PIXEL);
|
||||
bool ret = Textures::Create(*data, GL_RGBA, texture);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImagePNG(unsigned char **data, SceOff &size, Tex &texture) {
|
||||
bool ret = false;
|
||||
png_image image;
|
||||
sceClibMemset(&image, 0, (sizeof image));
|
||||
image.version = PNG_IMAGE_VERSION;
|
||||
|
||||
if (png_image_begin_read_from_memory(&image, *data, size) != 0) {
|
||||
image.format = PNG_FORMAT_RGBA;
|
||||
std::unique_ptr<png_byte[]> buffer(new png_byte[PNG_IMAGE_SIZE(image)]);
|
||||
|
||||
if (png_image_finish_read(&image, nullptr, buffer.get(), 0, nullptr) != 0) {
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
ret = Textures::Create(buffer.get(), GL_RGBA, texture);
|
||||
png_image_free(&image);
|
||||
void Free(Tex &texture) {
|
||||
if (texture.frames) {
|
||||
for (int i = 0; i < texture.anim->count; ++i) {
|
||||
SDL_DestroyTexture(texture.frames[i]);
|
||||
}
|
||||
else {
|
||||
Log::Error("png_image_finish_read failed: %s\n", image.message);
|
||||
png_image_free(&image);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log::Error("png_image_begin_read_from_memory failed: %s\n", image.message);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageSVG(unsigned char **data, Tex &texture) {
|
||||
NSVGimage *svg;
|
||||
svg = nsvgParse(reinterpret_cast<char *>(*data), "px", 96);
|
||||
|
||||
texture.width = svg->width;
|
||||
texture.height = svg->height;
|
||||
|
||||
NSVGrasterizer *rasterizer = nsvgCreateRasterizer();
|
||||
std::unique_ptr<unsigned char[]> buffer(new unsigned char[texture.width * texture.height * BYTES_PER_PIXEL]);
|
||||
nsvgRasterize(rasterizer, svg, 0, 0, 1, buffer.get(), texture.width, texture.height, texture.width * BYTES_PER_PIXEL);
|
||||
|
||||
bool ret = Textures::Create(buffer.get(), GL_RGBA, texture);
|
||||
IMG_FreeAnimation(texture.anim);
|
||||
|
||||
nsvgDelete(svg);
|
||||
nsvgDeleteRasterizer(rasterizer);
|
||||
return ret;
|
||||
// Not sure why we need to specify this? I'd assume Destroy/Free would set it to NULL
|
||||
texture.frames = nullptr;
|
||||
texture.anim = nullptr;
|
||||
}
|
||||
|
||||
if (texture.ptr) {
|
||||
SDL_DestroyTexture(texture.ptr);
|
||||
texture.ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool LoadImageTIFF(const std::string &path, Tex &texture) {
|
||||
@ -446,15 +135,17 @@ namespace Textures {
|
||||
raster = (SceUInt32 *)_TIFFCheckMalloc(tif, pixel_count, sizeof(SceUInt32), "raster buffer");
|
||||
if (raster != nullptr) {
|
||||
if (TIFFReadRGBAImageOriented(tif, texture.width, texture.height, raster, ORIENTATION_TOPLEFT)) {
|
||||
Textures::Create(reinterpret_cast<unsigned char*>(raster), GL_RGBA, texture);
|
||||
Textures::Create(reinterpret_cast<unsigned char*>(raster), texture);
|
||||
_TIFFfree(raster);
|
||||
}
|
||||
else
|
||||
else {
|
||||
Log::Error("TIFFReadRGBAImage failed\n");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
else {
|
||||
Log::Error("_TIFFmalloc failed\n");
|
||||
}
|
||||
|
||||
TIFFClose(tif);
|
||||
return true;
|
||||
@ -466,111 +157,30 @@ namespace Textures {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LoadImageWEBP(unsigned char **data, SceOff &size, std::vector<Tex> &textures) {
|
||||
bool ret = false;
|
||||
VP8StatusCode status = VP8_STATUS_OK;
|
||||
WebPBitstreamFeatures features = {0};
|
||||
|
||||
status = WebPGetFeatures(*data, size, &features);
|
||||
if (status != VP8_STATUS_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (features.has_animation) {
|
||||
int frame_index = 0, prev_timestamp = 0;
|
||||
WebPData webp_data = {0};
|
||||
WebPAnimDecoder *dec = {0};
|
||||
WebPAnimInfo info = {0};
|
||||
|
||||
WebPDataInit(&webp_data);
|
||||
webp_data.bytes = *data;
|
||||
webp_data.size = size;
|
||||
|
||||
dec = WebPAnimDecoderNew(&webp_data, nullptr);
|
||||
if (dec == nullptr)
|
||||
return ret;
|
||||
|
||||
if (!WebPAnimDecoderGetInfo(dec, &info)) {
|
||||
WebPAnimDecoderDelete(dec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
textures.resize(info.frame_count);
|
||||
textures[0].width = info.canvas_width;
|
||||
textures[0].height = info.canvas_height;
|
||||
|
||||
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
||||
unsigned char *frame_rgba = nullptr;
|
||||
int timestamp = 0;
|
||||
|
||||
if (!WebPAnimDecoderGetNext(dec, &frame_rgba, ×tamp)) {
|
||||
WebPAnimDecoderDelete(dec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
textures[frame_index].delay = (timestamp - prev_timestamp) * 1000;
|
||||
ret = Textures::Create(frame_rgba, GL_RGBA, textures[frame_index], textures[0].width, textures[0].height);
|
||||
++frame_index;
|
||||
prev_timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*data = WebPDecodeRGBA(*data, size, &textures[0].width, &textures[0].height);
|
||||
ret = Textures::Create(*data, GL_RGBA, textures[0]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Free(Tex &texture) {
|
||||
SDL_DestroyTexture(texture.ptr);
|
||||
}
|
||||
|
||||
bool LoadImageFile(const std::string &path, std::vector<Tex> &textures) {
|
||||
bool LoadImageFile(const std::string &path, Tex &texture) {
|
||||
bool ret = false;
|
||||
std::string ext = FS::GetFileExt(path);
|
||||
|
||||
// Resize to 1 initially. If the file is a GIF it will be resized accordingly.
|
||||
textures.resize(1);
|
||||
|
||||
// Because TIFF does not load via buffer, but directly from the path.
|
||||
if (ext == ".TIFF") {
|
||||
ret = Textures::LoadImageTIFF(path, textures[0]);
|
||||
if ((ext == ".GIF") || (ext == ".WEBP")) {
|
||||
ret = Textures::LoadImageAnim(path, texture);
|
||||
}
|
||||
else if (ext == ".GIF") {
|
||||
ret = Textures::LoadImageGIF(path, textures);
|
||||
else if ((ext == ".BMP") || (ext == ".JPEG") || (ext == ".JPG") || (ext == ".LBM") || (ext == ".PCX") ||
|
||||
(ext == ".PNG") || (ext == ".PNM") || (ext == ".PPM") || (ext == ".PGM") || (ext == ".PBM") ||
|
||||
(ext == ".QOI") || (ext == ".TGA") || (ext == ".XCF") || (ext == ".XPM") || (ext == ".SVG")) {
|
||||
ret = Textures::LoadImage(path, texture);
|
||||
}
|
||||
else if (ext == ".TIFF") {
|
||||
ret = Textures::LoadImageTIFF(path, texture);
|
||||
}
|
||||
else {
|
||||
unsigned char *data = nullptr;
|
||||
SceOff size = 0;
|
||||
FS::ReadFile(path, &data, size);
|
||||
|
||||
if (ext == ".BMP") {
|
||||
ret = Textures::LoadImageBMP(&data, size, textures[0]);
|
||||
|
||||
if (ext == ".PSD") {
|
||||
ret = Textures::LoadImageOther(&data, size, texture);
|
||||
}
|
||||
else if ((ext == ".PGM") || (ext == ".PPM") || (ext == ".PSD") || (ext == ".TGA")) {
|
||||
ret = Textures::LoadImageOther(&data, size, textures[0]);
|
||||
}
|
||||
else if (ext == ".ICO") {
|
||||
ret = Textures::LoadImageICO(&data, size, textures[0]);
|
||||
}
|
||||
else if ((ext == ".JPG") || (ext == ".JPEG")) {
|
||||
ret = Textures::LoadImageJPEG(&data, size, textures[0]);
|
||||
}
|
||||
else if (ext == ".PCX") {
|
||||
ret = Textures::LoadImagePCX(&data, size, textures[0]);
|
||||
}
|
||||
else if (ext == ".PNG") {
|
||||
ret = Textures::LoadImagePNG(&data, size, textures[0]);
|
||||
}
|
||||
else if (ext == ".SVG") {
|
||||
ret = Textures::LoadImageSVG(&data, textures[0]);
|
||||
}
|
||||
else if (ext == ".WEBP") {
|
||||
ret = Textures::LoadImageWEBP(&data, size, textures);
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -578,30 +188,17 @@ namespace Textures {
|
||||
|
||||
void Init(void) {
|
||||
const int num_icons = 2;
|
||||
unsigned char *data[num_icons] = { nullptr, nullptr };
|
||||
SceOff size[num_icons] = { 0, 0 };
|
||||
std::string filenames[num_icons] = {
|
||||
"app0:res/folder.png",
|
||||
"app0:res/image.png"
|
||||
};
|
||||
|
||||
for (int i = 0; i < num_icons; i++) {
|
||||
if (R_FAILED(FS::ReadFile(filenames[i], &data[i], size[i]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Tex texture;
|
||||
bool ret = Textures::LoadImage(filenames[i], texture);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
icons.resize(num_icons);
|
||||
bool ret = Textures::LoadImagePNG(&data[0], size[0], icons[FOLDER]);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
ret = Textures::LoadImagePNG(&data[1], size[1], icons[IMAGE]);
|
||||
IM_ASSERT(ret);
|
||||
|
||||
for (int i = 0; i < num_icons; i++) {
|
||||
if (data[i]) {
|
||||
delete[] data[i];
|
||||
}
|
||||
icons.push_back(texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,7 @@ namespace Windows {
|
||||
};
|
||||
|
||||
static void ClearTextures(WindowData &data) {
|
||||
for (unsigned int i = 0; i < data.textures.size(); i++) {
|
||||
Textures::Free(data.textures[i]);
|
||||
}
|
||||
|
||||
data.textures.clear();
|
||||
data.frame_count = 0;
|
||||
Textures::Free(data.texture);
|
||||
}
|
||||
|
||||
static bool HandleScroll(WindowData &data, int index) {
|
||||
@ -38,7 +33,7 @@ namespace Windows {
|
||||
else {
|
||||
data.selected = index;
|
||||
std::string path = FS::BuildPath(data.entries[index]);
|
||||
bool ret = Textures::LoadImageFile(path, data.textures);
|
||||
bool ret = Textures::LoadImageFile(path, data.texture);
|
||||
IM_ASSERT(ret);
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user