textures: Switch to loading animated images and static images from sdl2_image and remove unused libs

This commit is contained in:
Joel16 2024-10-13 11:11:23 -04:00
parent 217bbc8299
commit f6710038d9
16 changed files with 282 additions and 7136 deletions

View File

@ -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
)

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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, &timestamp)) {
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);
}
}

View File

@ -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;
}