1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-03 12:21:20 +00:00

Simplified image library. Added PCX support using dr_pcx

This commit is contained in:
Samuel Gomes 2022-08-13 01:37:59 +05:30 committed by Matthew Kilgore
parent 09f2546e35
commit d3da6da2fa
39 changed files with 3386 additions and 26897 deletions

View file

@ -1,10 +0,0 @@
Copyright (c) 2005, The EasyBMP Project (http://easybmp.sourceforge.net)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,86 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP.h *
* date added: 01-31-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Main include file *
* *
*************************************************/
#ifdef _MSC_VER
// MS Visual Studio gives warnings when using
// fopen. But fopen_s is not going to work well
// with most compilers, and fopen_s uses different
// syntax than fopen. (i.e., a macro won't work)
// So, we'lll use this:
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <iostream>
#include <cmath>
#include <cctype>
#include <cstring>
#ifndef EasyBMP
#define EasyBMP
#ifdef __BCPLUSPLUS__
// The Borland compiler must use this because something
// is wrong with their cstdio file.
#include <stdio.h>
#else
#include <cstdio>
#endif
#ifdef __GNUC__
// If g++ specific code is ever required, this is
// where it goes.
#endif
#ifdef __INTEL_COMPILER
// If Intel specific code is ever required, this is
// where it goes.
#endif
#ifndef _DefaultXPelsPerMeter_
#define _DefaultXPelsPerMeter_
#define DefaultXPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#ifndef _DefaultYPelsPerMeter_
#define _DefaultYPelsPerMeter_
#define DefaultYPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#include "EasyBMP_DataStructures.h"
#include "EasyBMP_BMP.h"
#include "EasyBMP_VariousBMPutilities.h"
#ifndef _EasyBMP_Version_
#define _EasyBMP_Version_ 1.06
#define _EasyBMP_Version_Integer_ 106
#define _EasyBMP_Version_String_ "1.06"
#endif
#ifndef _EasyBMPwarnings_
#define _EasyBMPwarnings_
#endif
void SetEasyBMPwarningsOff( void );
void SetEasyBMPwarningsOn( void );
bool GetEasyBMPwarningState( void );
#endif

View file

@ -1,86 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines BMP class *
* *
*************************************************/
#ifndef _EasyBMP_BMP_h_
#define _EasyBMP_BMP_h_
bool SafeFread( char* buffer, int size, int number, FILE* fp );
bool EasyBMPcheckDataSize( void );
class BMP
{private:
int BitDepth;
int Width;
int Height;
RGBApixel** Pixels;
RGBApixel* Colors;
int XPelsPerMeter;
int YPelsPerMeter;
ebmpBYTE* MetaData1;
int SizeOfMetaData1;
ebmpBYTE* MetaData2;
int SizeOfMetaData2;
bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
ebmpBYTE FindClosestColor( RGBApixel& input );
public:
int TellBitDepth( void );
int TellWidth( void );
int TellHeight( void );
int TellNumberOfColors( void );
void SetDPI( int HorizontalDPI, int VerticalDPI );
int TellVerticalDPI( void );
int TellHorizontalDPI( void );
BMP();
BMP( BMP& Input );
~BMP();
RGBApixel* operator()(int i,int j);
RGBApixel GetPixel( int i, int j ) const;
bool SetPixel( int i, int j, RGBApixel NewPixel );
bool CreateStandardColorTable( void );
bool SetSize( int NewWidth, int NewHeight );
bool SetBitDepth( int NewDepth );
bool WriteToFile( const char* FileName );
bool ReadFromFile( const char* FileName );
RGBApixel GetColor( int ColorNumber );
bool SetColor( int ColorNumber, RGBApixel NewColor );
};
#endif

View file

@ -1,821 +0,0 @@
EasyBMP Cross-Platform Windows Bitmap Library: Change Log
Library Author(s): Paul Macklin
Library License: BSD (revised). See the BSD_(revised)_license.txt
file for further information.
Copyright: 2005-6 by the EasyBMP Project
Email: macklin01@users.sourceforge.net
Support: http://easybmp.sourceforge.net
All changes by Paul Macklin unless otherwise noted.
*--------------------------------------------------------------------*
Version: 0.50
Date: 1-31-2005
None! (first release)
*--------------------------------------------------------------------*
Version: 0.51
Date: 2-14-2005
Added full 32-bit BMP file support
Took out annoying "colors: " message from BMP8 initialization
from scratch
Added more license and copyright info to each file
Added change log to library
To do next:
Should update the error messages for the initializations
Should simplify the reading and writing code
*--------------------------------------------------------------------*
Version: 0.52
Date: 2-19-2005
Fixed a minor bug in the MakeGreyscalePalette function where the
0 color turned out to be (255,255,255), rather than (0,0,0)
Updated standard colors for 4-bit, 8-bit, and 24-bit
*--------------------------------------------------------------------*
Version: 0.53
Date: 2-27-2005
Fixed unsigned / signed problem that VS.net shows
Tried fix of line 186 in EasyBMP_BMP4.h file. If it works,
I'll apply it consistently. I think that VS.net wants us
to clear char* blah, then char = new blah [size], just
like the old days for g++.
Removed EasyBMP_StandardColors.h from standard package
*--------------------------------------------------------------------*
Version: 0.54
Date: 2-27-2005
The fix of line 186 in EasyBMP_BMP4.h file appears to have
worked. I applied it through the remainder of the code.
Hopefully, this should ensure Visual Studio.Net compati-
bility.
Fixed some typos in the comment lines
*--------------------------------------------------------------------*
Version: 0.55
Date: 5-2-2005
Introduced RGBApixel struct.
Introduced BMFH, BMIH, and BMP classes.
Deprecated all old code to *_legacy.h.
Rewrote EasyBMP_VariousBMPutilities.h to use the new
BMP class.
*--------------------------------------------------------------------*
Version: 0.56
Date: 5-4-2005
Made Width, Height, and BitDepth private members and added
functions for accessing them.
Made a new function, SetBitDepth, as the only means to
change the bit depth. It will create/resize a palette as
necessary. This simplifies the WriteToFile code, as well as
any palette altering algorithms. (All algorithms can now
assume that a properly-sized palette exists.) This will
help improve code stability greatly.
Made a new function, SetSize, as the only way to change the
width and height of the image.
Eliminated useless HasPalette and NumberOfColors members,
and added TellNumberOfColors() function.
Updated EasyBMP_VariousBMPutilities.h to respect privacy
of data members.
*--------------------------------------------------------------------*
Version: 0.57
Date: 5-8-2005
Removed fclose(fp) lines from EasyBMP_BMP.h and
EasyBMP_VariousBMPutilities.h whenever ( !fp ) occurs,
to avoid a crash when trying to close a non-existant file.
Added a line to set bmfh.bfType = 0; to getBMFH() routine
in the case where ( !fp ) occurs, so that a nonexistant file
doesn't falsely show up as a bitmap file.
Made error messages in BMP::ReadFromFile(char*) more meaningful,
since Argh! doesn't help much. :-)
Made ReadFromFile operations safer: can deal more effectively
with corrupted and/or truncated files by adding the new
SafeFread() wrapper function.
Moved all change-log entries to the change log to make the source
file tidier.
Removed all references to Palettes; renamed them to ColorTables.
*--------------------------------------------------------------------*
Version: 0.58
Date: 5-13-2005
Rewrote ReadFromFile() to fix program crashes on reading 4-bit
files. (*grumble* I can't believe there was such a bug in such
a late version! */grumble*)
Added support to ReadFromFile() for reading 1-bit files.
Rewrote ReadFromFile() to avoid trying to read bitmap files of
depths other than 1, 4, 8, 24, and 32 bits.
Tested reading 4-bit files of width 0,1,2, and 3 (modulo 4),
and 1-bit files of width 0,1,2,3,4,5,6, and 7 (modulo 8)
*--------------------------------------------------------------------*
Version: 0.59
Date: 5-15-2005
Made ReadFromFile() more robust. Evidently, reading to the
same temp variable all the time made it unstable when reading
many files. I would never have guessed. I instead declare BMIH
and BMFH objects and read directly to their members. This appears
to be more stable when dealing with many ReadFromFile() calls.
On a related note, made sure to not call SetSize( Width,Height),
which is a bit recursive, as well as SetBitDepth( BitDepth ).
This appears to help stability, since these two functions were
create precisely for the purpose of setting those variables
values safely.
Made use of the boolean return value in SafeFread() to detect
when files are obviously corrupted. Used this to have an early
catch in ReadFromFile() and set it to a 1x1 1-bit image and
exit.
Made ReadFromFile() stricter, in that it only reads recognized
bit depths (1,4,8,24,32). Any other bit depth will prompt the
routine to terminate and set it to a 1x1 1-bit file.
Added write support for 1-bit files.
Rewrote WriteToFile() for 4,8-bit files to match methods used
for reading them.
Revised CreateStandardColorTable() and
CreateGreyscaleColorTable() to add support for 1-bit files.
Rewrote WriteToFile() to be stricter in only writing known bit
depths (1,4,8,24,32) and ignoring all others.
*--------------------------------------------------------------------*
Version: 0.60
Date: 5-21-2005
Deprecated *_legacy.h files.
Tested library extensivey in linux with good results.
Made CreateGreyscaleColorTable() stricter, in that it exits
if supplied a bit depth other than 1, 4, or 8.
Made cosmetic changes in EasyBMP_DataStructures.h to
improve readability.
Made SetBitDepth() stricter, in that it will never allow a bitmap
to be set to an unsupported bit depth. Only bit depths of 1, 4,
8, 24, or 32 are accepted.
Made SetSize() stricter, in that it will not allow negative
widths or heights.
Made cosmetic changes in EasyBMP_BMP.h to improve readability.
Added a check in ReadFromFile() to see if the requested width or
height is negative, a good sign of file corruption. In such a
case, the file is set to a blank 1x1 1-bit file.
Added code to ReadFromFile() to set size to 1x1 and bit depth to
1-bit if the file was not found.
*--------------------------------------------------------------------*
Version: 0.61
Date: 5-22-2005
Fixed awIndex typo in WriteToFile().
Replaced double BestDistance comparisons in WriteToFile()
with int BestDistances (so as to do integer operations,
rather than double operations). This gave a roughly 100%
speedup in 8-bit, 4-bit, and 1-bit write operations on
unoptimized (no compiler flags) code and a 30% speedup
on optimized code.
Removed checks like if( BestDistance < 1 ){ k=256; } .. from
WriteToFile(), as they give more overhead than savings in my
testing. For 8-bit files, there was a slight gain by putting
it back in with another method:
while( k < 256 && BestDistance > 0 ).
Redefined StepSize in CreateGreyscaleColorTable() to give a
better range of greys in 4-bit mode. As it was, white was not
in the color table. (Colors were spaced by 256/16 = 16). Now,
colors are spaced by (255-1)/(16-1) = 17, which gives the full
range.
*--------------------------------------------------------------------*
Version: 0.62
Date: 5-25-2005
Added endianess check function IsBigEndian() to
EasyBMP_DataStructures.h file.
Added functions to swap bytes in WORD and DWORD multibyte
variables to EasyBMP_DataStructures.h file for future big-endian
support.
Added functions to switch endianess to BMFH and BMIH objects
to EasyBMP_DataStructures.h file.
Added endianess checks to ReadFromFile() and WriteToFile()
functions in EasyBMP_BMP.h file, along with endianess conversions
where necessary.
Added endianess checks and conversions to GetBMFH() and GetBMIH()
functions in EasyBMP_VariousBMPutilities.h file.
Rewrote GetBitmapInfo() function to use GetBMFH() and GetBMIH()
functions instead. (In EasyBMP_VariousBMPutilities.h.) This
cuts down on the redundancy in the code.
Renamed GetBitmapInfo() to DisplayBitmapInfo() in the
EasyBMP_VariousBMPutilities.h file.
With these changes, big-endian architectures should be supported,
including IBM PowerPC, Sun Sparc, Motorola 86k, etc., and
including Mac OSX.
*--------------------------------------------------------------------*
Version: 0.63
Date: 7-20-2005
Added IntPow(int,int) function to help compiling with std
namespace. Besides, integer operations are faster and more
accurate.
Moved Square(double), IntSquare(int), and IntPow(int,int) to
EasyBMP_DataStructures.h
Simplified and cleaned up code in
Create4bitColorTable( RGBApixel**).
Changed safety check in BMP.ReadFromFile(char*) to set size to
1 x 1 if width or height is non-positive, rather than simply
negative.
Added bounds checking to BMP.operator()(int,int) to automatically
truncate requested pixel if out of bounds. Also added a warning
to cue the user in. :-)
Made error messages more consistent in format.
Simplified and cleaned up code in
Create4bitColorTable( RGBApixel**).
Added #include <iostream.h> to EasyBMP.h, since EasyBMP uses
cout, etc.
Simplified and cleaned up code in
Create1bitColorTable( RGBApixel**).
Changed BMP.SetSize(int,int) to disallow non-positive widths and
heights, rather than simply negative widths and heights. Such
function calls are now ignored.
*--------------------------------------------------------------------*
Version: 0.64
Date: 8-2-2005
Changed "include <iostream.h>" to "include <iostream>" for
ANSI-C++ compliance, as well as for better compatibility with the
std namespace and VC++. (Thanks, Tommy Li!)
Added some #ifndef pragmas to each header so that it should be
fine to incluce EasyBMP.h in multiple files in larger projects.
Added "using namespace std" inside any function that used C++
math or I/O operations. I avoided putting "using namespace std"
anywhere with global scope for maximum compatibility with C++
software in the wild.
Added includes for <cmath> and <cstdio> to EasyBMP.h
Removed unused temporary variables (TempWORD and TempDWORD) from
EasyBMP_BMP.h for cleaner compiling. If I see any more such
unused variables, I'll remove them, too.
*--------------------------------------------------------------------*
Version: 0.65
Date: 8-13-2005
Moved implementations of BMP::BMP(), BMP::~BMP(), and
BMP::operator()(int,int) outside of the class. This should help
for eventually moving everything into a separate cpp file.
Made RGBApixel** Pixels a private data member of the class
BMP.
Added function void BMP::SetColor(int,RGBApixel) to BMP class
to allow safe method of changing a color in the color table.
Added function RGBApixel BMP::GetColor(int) to BMP class
to allow safe method of retrieving a color in the color
table.
Cleaned up error messages in EasyBMP_BMP.h
Cleaned up error messages in EasyBMP_VariousBMPutilities.h
*--------------------------------------------------------------------*
Version: 0.66
Date: 8-18-2005
EasyBMP_StandardColorTables.h was removed from the library.
CreateStandardColorTable(RGBApixel**,int) was changed to
CreateStandardColorTable() and made a member function of BMP.
All other CreateStandardColorTable functions are now unnecessary
and have been removed.
CreateGreyscaleColorTable(RGBApixel**,int) was changed to
CreateStandardColorTable( BMP& ) and moved to
EasyBMP_VariousBMPutilities.h.
RGBApixel* Colors was made a private data member of the BMP
class.
CreateGreyscaleColorTable( BMP& ) was renamed to
CreateGrayscaleColorTable( BMP& ).
*--------------------------------------------------------------------*
Version: 0.67
Date: 9-14-2005
Made the EasyBMP custom math functions in
EasyBMP_DataStructures.h inline. (Square,IntSquare,IntPow).
This should make those function calls faster while improving
compatibility with compiling DLL's.
Separated the code from SafeFread() in EasyBMP_BMP.h to
improve compatibility with compiling DLL's.
Removed #define _WINGDI_H from EasyBMP_DataStructures.h to
improve compatibility with win32 applications. Instead,
there's an extra #ifndef _SELF_DEFINED_BMP_DATA_TYPES
conditional added.
_SELF_DEFINED_BMP_DATA_TYPES renamed to _SELF_DEFINED_WINGDI
in EasyBMP_DataStructures.h.
All bit-flipping functions (IsBigEndian, FlipWORD,
FlipDWORD) in EasyBMP_DataStructures.h were made inline
to improve execution speed and improve compatibility with
compiling DLL's.
All code was separated from function declarations in
EasyBMP_VariousBMPutilities.h to improve compatibility
with compiling DLL's.
Updated and cleaned up layout of EasyBMP_ChangeLog.txt.
Updated contact and support information in library files.
Corrected the LGPL license version.
*--------------------------------------------------------------------*
Version: 0.68
Date: 10-9-2005
Changed references to FILE to std::FILE in the SafeFread function
in EasyBMP_BMP.h to improve compatibility with Borland's compiler.
Removed a few assignments in EasyBMP_BMP.h that weren't used to
improve efficiency and reduce Borland warnings.
Changed calls like NotCorrupted = SafeFread() to
NotCorrupted &= SafeFread() in BMP::ReadFromFile() in EasyBMP_BMP.h
to improve robustness. Now, if the NotCorrupted bit is ever set
to false, it stays false, meaning that the function won't "forget"
that it encountered file corruption.
*--------------------------------------------------------------------*
Version: 0.69
Date: 10-19-2005
Changed BMP::WriteToFile( char* ) to BMP::WriteToFile(const char*)
in EasyBMP_BMP.h to respond to a feature request.
Changed BMP::ReadFromFile( char* ) to BMP::ReadToFile(const char*)
in EasyBMP_BMP.h to respond to a feature request.
Made BMP::ReadFromFile() and BMP::WriteToFile() in EasyBMP_BMP.h
return true/false to indicate success/failure in the operations.
These functions previously returned void.
Made BMP::SetSize() and BMP::SetBitDepth() in EasyBMP_BMP.h
return true/false to indicate success/failure in the operations.
These functions previously returned void.
Made BMP::SetColor() and BMP::CreateStandardColorTable() in
EasyBMP_BMP.h return true/false to indicate success/failure in the
operations. These functions previously returned void.
Made CreateGrayscaleColorTable() in EasyBMP_VariousBMPutilities.h
return true/false to indicate success/failure in the operations.
This function previously returned void.
Changed the char* argument GetBMFH( char* ), GetBMIH( char* ),
DisplayBitmapInfo( char* ), and GetBitmapColorDepth( char* ) in
EasyBMP_VariousBMPutilities.h to const char* for cleaner, safer
programming.
*--------------------------------------------------------------------*
Version: 0.70
Date: 10-19-2005
Found and fixed error in BMP::ReadFromFile() in the check for only
reading support bit depths.
Changed license from LGPL to BSD (revised/modified) to simplify
licensing issues and resolve any lingering licensing questions.
Fixed compiler error when using MSVC++.
Improved fix to allow compiling with Borland without breaking
Borland support.
Added a few lines to EasyBMP.h to make it easier to tailor code
to specific compilers. (For future use as needed.)
Added a few lines to EasyBMP_BMP.h (in BMP::ReadFromFile(),
BMP::WriteToFile(), and BMP::SetBitDepth()) to eventually add
support for 16-bit files.
*--------------------------------------------------------------------*
Version: 0.71
Date: 11-01-2005
Cleaned up comments in BMP::ReadFromFile() in EasyBMP_BMP.h
Added endian-safe read support for 16-bit files that are in the
standard 5-5-5 format (not specified in bit fields)
Added endian-safe read support for 16-bit files that use bit
fields, including 5-6-5 files.
Added endian-safe write support for 16-bit files. Uses the 5-6-5
encoding scheme to maximize the utility of the bits used.
Added a check for compression in BMP::ReadFromFile(). Because
file compression is beyond the scope of EasyBMP, such files are
not supported, and EasyBMP now properly detects these situations
and exits with an error.
Added a check for files that attempt to use bit fields but are not
16-bit files to BMP::ReadFromFile(). Such files are not supported.
Added a check to BMP::ReadFromFile() for files that use unknown
values of bmih.biCompression, such as old OS2 bitmaps. Such files
are not supported.
Removed "switching endianness" messages from EasyBMP_BMP.h
Added support for indexed (1, 4, and 8-bit) files that don't
specify all the colors.
Added support for reading files that include extra meta data before
the pixels. This data is skipped.
Added enclosing #ifndef EasyBMP ... lines to EasyBMP.h as a
further safeguard when EasyBMP is included in multiple cpp
files.
*--------------------------------------------------------------------*
Version: 1.00
Date: 02-06-2006
First Production/Stable release.
Corrected typographical errors in the comment sections of all
files.
Updated copyright on all files.
Removed extraneous comment in BMIH::BMIH() function in
EasyBMP_DataStructures.h file.
Replaced instances of \n with the more modern endl in
EasyBMP_DataStructures.h, EasyBMP_BMP.h, and
EasyBMP_VariousBMPutilities.h.
Added placeholder MetaData1 and MetaData2 data members to the
BMP class for potential future use.
Removed extraneous comments from EasyBMP_BMP.h.
Removed warning messages for switching endianness from
EasyBMP_VariousBMPutilities.h.
Updated copyright in EasyBMP_ChangeLog.txt file.
Fixed formatting issues in EasyBMP_ChangeLog.txt file.
Added DefaultXpelsPerMeter and DefaultYpelsPerMeter in
EasyBMP.h. These will default to 96 dpi.
Changed BMP::WriteToFile() to use DefaultXpelsPerMeter and
DefaultYpelsPerMeter when writing the BMIH structure.
Added XpelsPerMeter and YpelsPerMeter data members to BMP
class so that horizontal and vertical resolution are handled
properly. Currently, upon reading a file, the stated resolutions
are preserved, and upon writing, if no resolutions are given,
the defaults (of 96 DPI) are used.
Added function void BMP::SetDPI(int,int) to set the horizontal
and vertical resolutions.
Removed some unnecessary code from GetBitmapColorDepth() in
EasyBMP_VariousBMPutilities.h.
Fixed a bug in RangedPixelToPixelCopyTransparent() and
RangedPixelToPixelCopy() in EasyBMP_VariousBMPutilities.h which
caused copies to be truncated by an extra row or column in
certain circumstances.
Fixed a bug in RangedPixelToPixelCopyTransparent() and
RangedPixelToPixelCopy() in EasyBMP_VariousBMPutilities.h which
checked the wrong variable (FromT instead of FromB) to see if
it was out of range.
Added extra checks to RangedPixelToPixelCopyTransparent() and
RangedPixelToPixelCopy() in EasyBMP_VariousBMPutilities.h to
prevent attempted access of out-of-range pixels.
*--------------------------------------------------------------------*
Version: 1.01
Date: 03-31-2006
Made only the short functions Square, IntSquare, IsBigEndian,
FlipWORD, and FlipDWORD inline functions in
EasyBMP_DataStructures.h.
Moved all code (other than inline functions) to EasyBMP.cpp.
Changed DefaultXPelsPerMeter and DefaultYPelsPerMeter to #define
lines in EasyBMP.h to make the library compatible with
with the header-code split.
Removed memory hole in ~BMP() where "delete Colors;" was used
instead of "delete [] Colors;". Likewise with MetaData1 and
MetaData2.
Fixed memory leak in BMP::SetBitDepth() by changing to
delete [] Colors;
Removed potential memory leak in BMP::WriteToFile() in 24- and
32-bit writing where szTemp wasn't delete at the end of a row.
Fixed bug where XPelsPerMeter and YPelsPerMeter weren't
properly initialized in the BMP::BMP() constructor, leading
to strange horizontal and vertical resolutions.
Fixed memory leak in BMP::ReadFromFile() where TempSkipBYTE
wasn't deleted.
Fixed memory leak in BMP::ReadFromFile() where szTemp wasn't
deleted.
Added BMP::TellVerticalDPI() and BMP::TellHorizontalDPI()
functions to give this information. If those values have
not yet been set, then they are first set to the EasyBMP
defaults of 96 dpi.
Set uninitialized RGBApixel values to white (255,255,255,0)
in a few functions for the BMP class.
Added a sample cpp application and makefile.
*--------------------------------------------------------------------*
Version: 1.02
Date: 05-29-2006
Inserted a line into EasyBMP.h to suppress the Visual Studio
warnings. We'll keep using the C++ standard fopen for now
until fopen_s becomes a real standard.
Moved the code sample and makefile to a subdirectory, so that
unzipping EasyBMP#_##.zip into a project directory doesn't
overwrite any crucial makefiles.
Improved SafeFread() to check if the proper amount of data
could be read.
Dramatically cleaned up ReadFromFile() code for 1 and 4
bpp files.
Fixed a typo (draw.o) in the sample makefile.
Modified ReadFromFile() to use buffering when reading the pixel
data. This should substantially improve disk access performance.
Only 16 bpp files are read in the old, slower way.
Changed DWORD from unsigned long to unsigned int. This should
fix the issue where 64-bit machines see DWORD as an 8-byte
data type, rather than 4 bytes. (Thank you to Bas Wegh!)
Renamed BYTE, WORD, and DWORD data types to ebmpBYTE, ebmpWORD,
and ebmpDWORD to eliminate the possibility of conflict with
windows applications, particularly with 64-bit windows, which
likely uses 8 byte DWORDS.
Modified WriteToFile() to use buffering when reading the pixel
data. This should substantially improve disk access performance.
Only 16 bpp files are read in the old, slower way.
Added new function, EasyBMPcheckDataSize(), to check that
the ebmpBYTE, ebmpWORD, and ebmpDWORD types have the correct
type.
Added some new macros of the EasyBMP version number for easier
version checking. New versions include _EasyBMP_Version_
(a double), _EasyBMP_Version_String_ (a char* version), and
_EasyBMP_Version_Integer_ (an integer version, e.g., 102).
*--------------------------------------------------------------------*
Version: 1.03
Date: 06-20-2006
Inserted a line into EasyBMP.h to suppress the Visual Studio
Added a check to BMP.SetColor() to ensure that the color table
is defined before attempting to set a color entry.
Added a check to BMP.GetColor() to ensure that the color table
is defined before attempting to retrieve a color entry.
Simplified the conditional in BMP.WriteToFile() from
if( BitDepth == 1 || BitDepth == 4 || ... ) to the simpler
if( BitDepth != 16 ).
Removed the old, unused code for writing 1- and 4-bit files
from BMP.WriteToFile().
Removed the line Colors = new RGBApixel [NumberOfColors]; in
BMP.ReadFromFile(). This operation is already covered by the
earlier SetBitDepth() call, and may contribute to a memory
leak. Furthermore, for files that had fewer than expected
number of colors (e.g., an 8-bit file with 236 colors), it
lead to memory access errors in BMP.GetColor() and BMP.SetColor().
(In fact, this is the main motivation for release 1.03.)
Added a warning when BMP.ReadFromFile() encounters an under-
specified color table, and code to pad the table with white
entries.
Added screen output on EasyBMP version and project website to
the code sample.
*--------------------------------------------------------------------*
Version: 1.04
Date: 07-22-2006
Removed the assignment to the integer i in IntPow() to eliminate a
Borland compiler warning.
Removed the assignment to the integer i in the Read##bitRow()
functions to eliminate Borland compiler warnings.
Removed the assignment to ZeroWORD in line 478 of EasyBMP.cpp in
BMP::WriteToFile() to eliminate Borland compiler warnings.
Removed the assignment to ZeroWORD in line 825 of EasyBMP.cpp in
BMP::ReadFromFile() to eliminate Borland compiler warnings.
The Borland warnings about conditions always being false are
incorrect. (Lines 1587, 1594, and 1601.) Likewise, the Borland
warnings about unreachable code (lines 1589, 1596, and 1603) are
incorrect. This code serves as a protection on unexpected hardware
where the data types may not be of the correct size, and helps to
future-proof EasyBMP. The first time this type of error was
encountered was on 64-bit CPUs, where the size of the DWORD was
larger than assumed when writing EasyBMP. Therefore, we will not
"correct" these "errors" detected by Borland. If they bother you,
compile with the -w-8008 and -w-8066 options.
Borland issues warnings about argc and argv being unused in the
sample project. These are silly warnings and will be ignored. If
this warning bothers you, compile with the -w-8057 option.
Modified the sample makefile so that EasyBMP.o depends upon
EasyBMP.cpp and EasyBMP*.h in the current working directory, rather
than the parent directory.
Added a global EasyBMPwarnings boolean variable, and functions
SetEasyBMPwarningsOn() and SetEasyBMPwarningsOff() to enable and
disable EasyBMP warnings and errors. Note that this will not
disable error checking or any other EasyBMP behavior, other than
cout output of the warning and error messages.
Added the function GetEasyBMPwarningState() to query the EasyBMP
warning state. (Either warnings are enabled or disabled.)
Removed old commented code (Write1bitRow()) from EasyBMP.cpp.
Replaced the 24-bit EasyBMPbackground.bmp image in the code sample
with a dithered 8-bit version to reduce the download size of the
core library.
*--------------------------------------------------------------------*
Version: 1.05
Date: 11-01-2006
Renamed BytesRead to ItemsRead in the SafeFread() function in
EasyBMP.cpp for greater clarity.
Added a copy constructor to the BMP class. However, note that
passing by value is not recommended practice. (Passing by refer-
ence is much faster, and consumes less memory.)
Added a new function:
bool Rescale( BMP& InputImage, char mode, int NewDimension );
to resize an image. The mode variables are as follows:
'P': resizes the image to a new percentage of the old size,
e.g., 42%, 13%, etc.
example: Rescale( SomeImage, 'p', 42 );
'W': resizes the image such that the new width is as specified.
example: Rescale( SomeImage, 'W', 100 );
'H': resizes the image such that the new height is as specified.
example: Rescale( SomeImage, 'H', 100 );
'F': resizes the image to fit in a square of specified size.
example: Rescale( SomeImage, 'F', 100 ); // fits in 100x100
// box
All rescaling is done with bilinear interpolation.
*--------------------------------------------------------------------*
Version: 1.06
Date: 12-01-2006
Added includes for <cctype> and <cstring> to EasyBMP.h. These are
used and should have been included all along. This should help
with Intel icc compiling.
Fixed the && bug in the copy constructor. (Thank you to user
fcnature!)
Added image scaling to the supplied code sample.
Added GetPixle() and SetPixel() functions for future use. These
will be added to enable more careful use of the const keyword.
*--------------------------------------------------------------------*

View file

@ -1,104 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_DataStructures.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines basic data structures for *
* the BMP class *
* *
*************************************************/
#ifndef _EasyBMP_Custom_Math_Functions_
#define _EasyBMP_Custom_Math_Functions_
inline double Square( double number )
{ return number*number; }
inline int IntSquare( int number )
{ return number*number; }
#endif
int IntPow( int base, int exponent );
#ifndef _EasyBMP_Defined_WINGDI
#define _EasyBMP_Defined_WINGDI
typedef unsigned char ebmpBYTE;
typedef unsigned short ebmpWORD;
typedef unsigned int ebmpDWORD;
#endif
#ifndef _EasyBMP_DataStructures_h_
#define _EasyBMP_DataStructures_h_
inline bool IsBigEndian()
{
short word = 0x0001;
if((*(char *)& word) != 0x01 )
{ return true; }
return false;
}
inline ebmpWORD FlipWORD( ebmpWORD in )
{ return ( (in >> 8) | (in << 8) ); }
inline ebmpDWORD FlipDWORD( ebmpDWORD in )
{
return ( ((in&0xFF000000)>>24) | ((in&0x000000FF)<<24) |
((in&0x00FF0000)>>8 ) | ((in&0x0000FF00)<<8 ) );
}
// it's easier to use a struct than a class
// because we can read/write all four of the bytes
// at once (as we can count on them being continuous
// in memory
typedef struct RGBApixel {
ebmpBYTE Blue;
ebmpBYTE Green;
ebmpBYTE Red;
ebmpBYTE Alpha;
} RGBApixel;
class BMFH{
public:
ebmpWORD bfType;
ebmpDWORD bfSize;
ebmpWORD bfReserved1;
ebmpWORD bfReserved2;
ebmpDWORD bfOffBits;
BMFH();
void display( void );
void SwitchEndianess( void );
};
class BMIH{
public:
ebmpDWORD biSize;
ebmpDWORD biWidth;
ebmpDWORD biHeight;
ebmpWORD biPlanes;
ebmpWORD biBitCount;
ebmpDWORD biCompression;
ebmpDWORD biSizeImage;
ebmpDWORD biXPelsPerMeter;
ebmpDWORD biYPelsPerMeter;
ebmpDWORD biClrUsed;
ebmpDWORD biClrImportant;
BMIH();
void display( void );
void SwitchEndianess( void );
};
#endif

View file

@ -1,43 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Various utilities. *
* *
*************************************************/
#ifndef _EasyBMP_VariousBMPutilities_h_
#define _EasyBMP_VariousBMPutilities_h_
BMFH GetBMFH( const char* szFileNameIn );
BMIH GetBMIH( const char* szFileNameIn );
void DisplayBitmapInfo( const char* szFileNameIn );
int GetBitmapColorDepth( const char* szFileNameIn );
void PixelToPixelCopy( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY);
void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY,
RGBApixel& Transparent );
void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY );
void RangedPixelToPixelCopyTransparent(
BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY ,
RGBApixel& Transparent );
bool CreateGrayscaleColorTable( BMP& InputImage );
bool Rescale( BMP& InputImage , char mode, int NewDimension );
#endif

View file

@ -1,44 +0,0 @@
#ifdef QB64_BACKSLASH_FILESYSTEM
# include "src\\EasyBMP.cpp"
#else
# include "src/EasyBMP.cpp"
#endif
uint8 *image_decode_bmp(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
BMP bm;
if (!bm.ReadFromMemory((char *)content, bytes)) {
return NULL;
}
int32 h, w;
h = bm.TellHeight();
w = bm.TellWidth();
uint8 *out;
out = (uint8 *)malloc(h * w * 4);
uint8 *o;
int32 x2, y2;
o = out;
for (y2 = 0; y2 < h; y2++) {
for (x2 = 0; x2 < w; x2++) {
*o = bm(x2, y2)->Blue;
o++;
*o = bm(x2, y2)->Green;
o++;
*o = bm(x2, y2)->Red;
o++;
*o = 255;
o++;
}
}
*result = 1 + 2;
*x = w;
*y = h;
return out;
}

File diff suppressed because it is too large Load diff

View file

@ -1,86 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP.h *
* date added: 01-31-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Main include file *
* *
*************************************************/
#ifdef _MSC_VER
// MS Visual Studio gives warnings when using
// fopen. But fopen_s is not going to work well
// with most compilers, and fopen_s uses different
// syntax than fopen. (i.e., a macro won't work)
// So, we'lll use this:
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <iostream>
#include <cmath>
#include <cctype>
#include <cstring>
#ifndef EasyBMP
#define EasyBMP
#ifdef __BCPLUSPLUS__
// The Borland compiler must use this because something
// is wrong with their cstdio file.
#include <stdio.h>
#else
#include <cstdio>
#endif
#ifdef __GNUC__
// If g++ specific code is ever required, this is
// where it goes.
#endif
#ifdef __INTEL_COMPILER
// If Intel specific code is ever required, this is
// where it goes.
#endif
#ifndef _DefaultXPelsPerMeter_
#define _DefaultXPelsPerMeter_
#define DefaultXPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#ifndef _DefaultYPelsPerMeter_
#define _DefaultYPelsPerMeter_
#define DefaultYPelsPerMeter 3780
// set to a default of 96 dpi
#endif
#include "EasyBMP_DataStructures.h"
#include "EasyBMP_BMP.h"
#include "EasyBMP_VariousBMPutilities.h"
#ifndef _EasyBMP_Version_
#define _EasyBMP_Version_ 1.06
#define _EasyBMP_Version_Integer_ 106
#define _EasyBMP_Version_String_ "1.06"
#endif
#ifndef _EasyBMPwarnings_
#define _EasyBMPwarnings_
#endif
void SetEasyBMPwarningsOff( void );
void SetEasyBMPwarningsOn( void );
bool GetEasyBMPwarningState( void );
#endif

View file

@ -1,86 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines BMP class *
* *
*************************************************/
#ifndef _EasyBMP_BMP_h_
#define _EasyBMP_BMP_h_
bool SafeFread( char* buffer, int size, int number, FILE* fp );
bool EasyBMPcheckDataSize( void );
class BMP
{private:
int BitDepth;
int Width;
int Height;
RGBApixel** Pixels;
RGBApixel* Colors;
int XPelsPerMeter;
int YPelsPerMeter;
ebmpBYTE* MetaData1;
int SizeOfMetaData1;
ebmpBYTE* MetaData2;
int SizeOfMetaData2;
bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Read1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
bool Write1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );
ebmpBYTE FindClosestColor( RGBApixel& input );
public:
int TellBitDepth( void );
int TellWidth( void );
int TellHeight( void );
int TellNumberOfColors( void );
void SetDPI( int HorizontalDPI, int VerticalDPI );
int TellVerticalDPI( void );
int TellHorizontalDPI( void );
BMP();
BMP( BMP& Input );
~BMP();
RGBApixel* operator()(int i,int j);
RGBApixel GetPixel( int i, int j ) const;
bool SetPixel( int i, int j, RGBApixel NewPixel );
bool CreateStandardColorTable( void );
bool SetSize( int NewWidth, int NewHeight );
bool SetBitDepth( int NewDepth );
bool WriteToFile( const char* FileName );
bool ReadFromFile( const char* FileName );
bool ReadFromMemory ( const char* memory, int size );
RGBApixel GetColor( int ColorNumber );
bool SetColor( int ColorNumber, RGBApixel NewColor );
};
#endif

View file

@ -1,104 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_DataStructures.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Defines basic data structures for *
* the BMP class *
* *
*************************************************/
#ifndef _EasyBMP_Custom_Math_Functions_
#define _EasyBMP_Custom_Math_Functions_
inline double Square( double number )
{ return number*number; }
inline int IntSquare( int number )
{ return number*number; }
#endif
int IntPow( int base, int exponent );
#ifndef _EasyBMP_Defined_WINGDI
#define _EasyBMP_Defined_WINGDI
typedef unsigned char ebmpBYTE;
typedef unsigned short ebmpWORD;
typedef unsigned int ebmpDWORD;
#endif
#ifndef _EasyBMP_DataStructures_h_
#define _EasyBMP_DataStructures_h_
inline bool IsBigEndian()
{
short word = 0x0001;
if((*(char *)& word) != 0x01 )
{ return true; }
return false;
}
inline ebmpWORD FlipWORD( ebmpWORD in )
{ return ( (in >> 8) | (in << 8) ); }
inline ebmpDWORD FlipDWORD( ebmpDWORD in )
{
return ( ((in&0xFF000000)>>24) | ((in&0x000000FF)<<24) |
((in&0x00FF0000)>>8 ) | ((in&0x0000FF00)<<8 ) );
}
// it's easier to use a struct than a class
// because we can read/write all four of the bytes
// at once (as we can count on them being continuous
// in memory
typedef struct RGBApixel {
ebmpBYTE Blue;
ebmpBYTE Green;
ebmpBYTE Red;
ebmpBYTE Alpha;
} RGBApixel;
class BMFH{
public:
ebmpWORD bfType;
ebmpDWORD bfSize;
ebmpWORD bfReserved1;
ebmpWORD bfReserved2;
ebmpDWORD bfOffBits;
BMFH();
void display( void );
void SwitchEndianess( void );
};
class BMIH{
public:
ebmpDWORD biSize;
ebmpDWORD biWidth;
ebmpDWORD biHeight;
ebmpWORD biPlanes;
ebmpWORD biBitCount;
ebmpDWORD biCompression;
ebmpDWORD biSizeImage;
ebmpDWORD biXPelsPerMeter;
ebmpDWORD biYPelsPerMeter;
ebmpDWORD biClrUsed;
ebmpDWORD biClrImportant;
BMIH();
void display( void );
void SwitchEndianess( void );
};
#endif

View file

@ -1,43 +0,0 @@
/*************************************************
* *
* EasyBMP Cross-Platform Windows Bitmap Library *
* *
* Author: Paul Macklin *
* email: macklin01@users.sourceforge.net *
* support: http://easybmp.sourceforge.net *
* *
* file: EasyBMP_VariousBMPutilities.h *
* date added: 05-02-2005 *
* date modified: 12-01-2006 *
* version: 1.06 *
* *
* License: BSD (revised/modified) *
* Copyright: 2005-6 by the EasyBMP Project *
* *
* description: Various utilities. *
* *
*************************************************/
#ifndef _EasyBMP_VariousBMPutilities_h_
#define _EasyBMP_VariousBMPutilities_h_
BMFH GetBMFH( const char* szFileNameIn );
BMIH GetBMIH( const char* szFileNameIn );
void DisplayBitmapInfo( const char* szFileNameIn );
int GetBitmapColorDepth( const char* szFileNameIn );
void PixelToPixelCopy( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY);
void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,
BMP& To, int ToX, int ToY,
RGBApixel& Transparent );
void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY );
void RangedPixelToPixelCopyTransparent(
BMP& From, int FromL , int FromR, int FromB, int FromT,
BMP& To, int ToX, int ToY ,
RGBApixel& Transparent );
bool CreateGrayscaleColorTable( BMP& InputImage );
bool Rescale( BMP& InputImage , char mode, int NewDimension );
#endif

View file

@ -1,916 +0,0 @@
// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder
// version 1.3.5 (2016-11-14)
// Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>
// published under the terms of the MIT license
//
// 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.
///////////////////////////////////////////////////////////////////////////////
// DOCUMENTATION SECTION //
// read this if you want to know what this is all about //
///////////////////////////////////////////////////////////////////////////////
// INTRODUCTION
// ============
//
// This is a minimal decoder for baseline JPEG images. It accepts memory dumps
// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit
// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files
// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are
// not supported. All YCbCr subsampling schemes with power-of-two ratios are
// supported, as are restart intervals. Progressive or lossless JPEG is not
// supported.
// Summed up, NanoJPEG should be able to decode all images from digital cameras
// and most common forms of other non-progressive JPEG images.
// The decoder is not optimized for speed, it's optimized for simplicity and
// small code. Image quality should be at a reasonable level. A bicubic chroma
// upsampling filter ensures that subsampled YCbCr images are rendered in
// decent quality. The decoder is not meant to deal with broken JPEG files in
// a graceful manner; if anything is wrong with the bitstream, decoding will
// simply fail.
// The code should work with every modern C compiler without problems and
// should not emit any warnings. It uses only (at least) 32-bit integer
// arithmetic and is supposed to be endianness independent and 64-bit clean.
// However, it is not thread-safe.
// COMPILE-TIME CONFIGURATION
// ==========================
//
// The following aspects of NanoJPEG can be controlled with preprocessor
// defines:
//
// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example
// program.
// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header
// file for NanoJPEG. Example:
// #define _NJ_INCLUDE_HEADER_ONLY
// #include "nanojpeg.c"
// int main(void) {
// njInit();
// // your code here
// njDone();
// }
// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy()
// functions from the standard C library (default).
// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode,
// external functions njAlloc(), njFreeMem(),
// njFillMem() and njCopyMem() need to be defined
// and implemented somewhere.
// NJ_USE_WIN32=0 = Normal mode (default).
// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and
// NJ_USE_LIBC=0, NanoJPEG will use its own
// implementations of the required C library
// functions (default if compiling with MSVC and
// NJ_USE_LIBC=0).
// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter
// (default).
// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling
// (bad quality, but faster and less code).
// API
// ===
//
// For API documentation, read the "header section" below.
// EXAMPLE
// =======
//
// A few pages below, you can find an example program that uses NanoJPEG to
// convert JPEG files into PGM or PPM. To compile it, use something like
// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c
// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)
// The only thing you might need is -Wno-shift-negative-value, because this
// code relies on the target machine using two's complement arithmetic, but
// the C standard does not, even though *any* practically useful machine
// nowadays uses two's complement.
///////////////////////////////////////////////////////////////////////////////
// HEADER SECTION //
// copy and pase this into nanojpeg.h if you want //
///////////////////////////////////////////////////////////////////////////////
#ifndef _NANOJPEG_H
#define _NANOJPEG_H
// nj_result_t: Result codes for njDecode().
typedef enum _nj_result {
NJ_OK = 0, // no error, decoding successful
NJ_NO_JPEG, // not a JPEG file
NJ_UNSUPPORTED, // unsupported format
NJ_OUT_OF_MEM, // out of memory
NJ_INTERNAL_ERR, // internal error
NJ_SYNTAX_ERROR, // syntax error
__NJ_FINISHED, // used internally, will never be reported
} nj_result_t;
// njInit: Initialize NanoJPEG.
// For safety reasons, this should be called at least one time before using
// using any of the other NanoJPEG functions.
void njInit(void);
// njDecode: Decode a JPEG image.
// Decodes a memory dump of a JPEG file into internal buffers.
// Parameters:
// jpeg = The pointer to the memory dump.
// size = The size of the JPEG file.
// Return value: The error code in case of failure, or NJ_OK (zero) on success.
nj_result_t njDecode(const void* jpeg, const int size);
// njGetWidth: Return the width (in pixels) of the most recently decoded
// image. If njDecode() failed, the result of njGetWidth() is undefined.
int njGetWidth(void);
// njGetHeight: Return the height (in pixels) of the most recently decoded
// image. If njDecode() failed, the result of njGetHeight() is undefined.
int njGetHeight(void);
// njIsColor: Return 1 if the most recently decoded image is a color image
// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
// of njGetWidth() is undefined.
int njIsColor(void);
// njGetImage: Returns the decoded image data.
// Returns a pointer to the most recently image. The memory layout it byte-
// oriented, top-down, without any padding between lines. Pixels of color
// images will be stored as three consecutive bytes for the red, green and
// blue channels. This data format is thus compatible with the PGM or PPM
// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
// If njDecode() failed, the result of njGetImage() is undefined.
unsigned char* njGetImage(void);
// njGetImageSize: Returns the size (in bytes) of the image data returned
// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
// undefined.
int njGetImageSize(void);
// njDone: Uninitialize NanoJPEG.
// Resets NanoJPEG's internal state and frees all memory that has been
// allocated at run-time by NanoJPEG. It is still possible to decode another
// image after a njDone() call.
void njDone(void);
#endif//_NANOJPEG_H
///////////////////////////////////////////////////////////////////////////////
// CONFIGURATION SECTION //
// adjust the default settings for the NJ_ defines here //
///////////////////////////////////////////////////////////////////////////////
#ifndef NJ_USE_LIBC
#define NJ_USE_LIBC 1
#endif
#ifndef NJ_USE_WIN32
#ifdef _MSC_VER
#define NJ_USE_WIN32 (!NJ_USE_LIBC)
#else
#define NJ_USE_WIN32 0
#endif
#endif
#ifndef NJ_CHROMA_FILTER
#define NJ_CHROMA_FILTER 1
#endif
///////////////////////////////////////////////////////////////////////////////
// EXAMPLE PROGRAM //
// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) //
///////////////////////////////////////////////////////////////////////////////
#ifdef _NJ_EXAMPLE_PROGRAM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
int size;
char *buf;
FILE *f;
if (argc < 2) {
printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
return 2;
}
f = fopen(argv[1], "rb");
if (!f) {
printf("Error opening the input file.\n");
return 1;
}
fseek(f, 0, SEEK_END);
size = (int) ftell(f);
buf = (char*) malloc(size);
fseek(f, 0, SEEK_SET);
size = (int) fread(buf, 1, size, f);
fclose(f);
njInit();
if (njDecode(buf, size)) {
free((void*)buf);
printf("Error decoding the input file.\n");
return 1;
}
free((void*)buf);
f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
if (!f) {
printf("Error opening the output file.\n");
return 1;
}
fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
fwrite(njGetImage(), 1, njGetImageSize(), f);
fclose(f);
njDone();
return 0;
}
#endif
///////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION SECTION //
// you may stop reading here //
///////////////////////////////////////////////////////////////////////////////
#ifndef _NJ_INCLUDE_HEADER_ONLY
#ifdef _MSC_VER
#define NJ_INLINE static __inline
#define NJ_FORCE_INLINE static __forceinline
#else
#define NJ_INLINE static inline
#define NJ_FORCE_INLINE static inline
#endif
#if NJ_USE_LIBC
#include <stdlib.h>
#include <string.h>
#define njAllocMem malloc
#define njFreeMem free
#define njFillMem memset
#define njCopyMem memcpy
#elif NJ_USE_WIN32
#include <windows.h>
#define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
#define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
mov edi, block
mov al, value
mov ecx, count
rep stosb
} }
NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
mov edi, dest
mov esi, src
mov ecx, count
rep movsb
} }
#else
extern void* njAllocMem(int size);
extern void njFreeMem(void* block);
extern void njFillMem(void* block, unsigned char byte, int size);
extern void njCopyMem(void* dest, const void* src, int size);
#endif
typedef struct _nj_code {
unsigned char bits, code;
} nj_vlc_code_t;
typedef struct _nj_cmp {
int cid;
int ssx, ssy;
int width, height;
int stride;
int qtsel;
int actabsel, dctabsel;
int dcpred;
unsigned char *pixels;
} nj_component_t;
typedef struct _nj_ctx {
nj_result_t error;
const unsigned char *pos;
int size;
int length;
int width, height;
int mbwidth, mbheight;
int mbsizex, mbsizey;
int ncomp;
nj_component_t comp[3];
int qtused, qtavail;
unsigned char qtab[4][64];
nj_vlc_code_t vlctab[4][65536];
int buf, bufbits;
int block[64];
int rstinterval;
unsigned char *rgb;
} nj_context_t;
static nj_context_t nj;
static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
NJ_FORCE_INLINE unsigned char njClip(const int x) {
return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
}
#define W1 2841
#define W2 2676
#define W3 2408
#define W5 1609
#define W6 1108
#define W7 565
NJ_INLINE void njRowIDCT(int* blk) {
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
if (!((x1 = blk[4] << 11)
| (x2 = blk[6])
| (x3 = blk[2])
| (x4 = blk[1])
| (x5 = blk[7])
| (x6 = blk[5])
| (x7 = blk[3])))
{
blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;
return;
}
x0 = (blk[0] << 11) + 128;
x8 = W7 * (x4 + x5);
x4 = x8 + (W1 - W7) * x4;
x5 = x8 - (W1 + W7) * x5;
x8 = W3 * (x6 + x7);
x6 = x8 - (W3 - W5) * x6;
x7 = x8 - (W3 + W5) * x7;
x8 = x0 + x1;
x0 -= x1;
x1 = W6 * (x3 + x2);
x2 = x1 - (W2 + W6) * x2;
x3 = x1 + (W2 - W6) * x3;
x1 = x4 + x6;
x4 -= x6;
x6 = x5 + x7;
x5 -= x7;
x7 = x8 + x3;
x8 -= x3;
x3 = x0 + x2;
x0 -= x2;
x2 = (181 * (x4 + x5) + 128) >> 8;
x4 = (181 * (x4 - x5) + 128) >> 8;
blk[0] = (x7 + x1) >> 8;
blk[1] = (x3 + x2) >> 8;
blk[2] = (x0 + x4) >> 8;
blk[3] = (x8 + x6) >> 8;
blk[4] = (x8 - x6) >> 8;
blk[5] = (x0 - x4) >> 8;
blk[6] = (x3 - x2) >> 8;
blk[7] = (x7 - x1) >> 8;
}
NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
if (!((x1 = blk[8*4] << 8)
| (x2 = blk[8*6])
| (x3 = blk[8*2])
| (x4 = blk[8*1])
| (x5 = blk[8*7])
| (x6 = blk[8*5])
| (x7 = blk[8*3])))
{
x1 = njClip(((blk[0] + 32) >> 6) + 128);
for (x0 = 8; x0; --x0) {
*out = (unsigned char) x1;
out += stride;
}
return;
}
x0 = (blk[0] << 8) + 8192;
x8 = W7 * (x4 + x5) + 4;
x4 = (x8 + (W1 - W7) * x4) >> 3;
x5 = (x8 - (W1 + W7) * x5) >> 3;
x8 = W3 * (x6 + x7) + 4;
x6 = (x8 - (W3 - W5) * x6) >> 3;
x7 = (x8 - (W3 + W5) * x7) >> 3;
x8 = x0 + x1;
x0 -= x1;
x1 = W6 * (x3 + x2) + 4;
x2 = (x1 - (W2 + W6) * x2) >> 3;
x3 = (x1 + (W2 - W6) * x3) >> 3;
x1 = x4 + x6;
x4 -= x6;
x6 = x5 + x7;
x5 -= x7;
x7 = x8 + x3;
x8 -= x3;
x3 = x0 + x2;
x0 -= x2;
x2 = (181 * (x4 + x5) + 128) >> 8;
x4 = (181 * (x4 - x5) + 128) >> 8;
*out = njClip(((x7 + x1) >> 14) + 128); out += stride;
*out = njClip(((x3 + x2) >> 14) + 128); out += stride;
*out = njClip(((x0 + x4) >> 14) + 128); out += stride;
*out = njClip(((x8 + x6) >> 14) + 128); out += stride;
*out = njClip(((x8 - x6) >> 14) + 128); out += stride;
*out = njClip(((x0 - x4) >> 14) + 128); out += stride;
*out = njClip(((x3 - x2) >> 14) + 128); out += stride;
*out = njClip(((x7 - x1) >> 14) + 128);
}
#define njThrow(e) do { nj.error = e; return; } while (0)
#define njCheckError() do { if (nj.error) return; } while (0)
static int njShowBits(int bits) {
unsigned char newbyte;
if (!bits) return 0;
while (nj.bufbits < bits) {
if (nj.size <= 0) {
nj.buf = (nj.buf << 8) | 0xFF;
nj.bufbits += 8;
continue;
}
newbyte = *nj.pos++;
nj.size--;
nj.bufbits += 8;
nj.buf = (nj.buf << 8) | newbyte;
if (newbyte == 0xFF) {
if (nj.size) {
unsigned char marker = *nj.pos++;
nj.size--;
switch (marker) {
case 0x00:
case 0xFF:
break;
case 0xD9: nj.size = 0; break;
default:
if ((marker & 0xF8) != 0xD0)
nj.error = NJ_SYNTAX_ERROR;
else {
nj.buf = (nj.buf << 8) | marker;
nj.bufbits += 8;
}
}
} else
nj.error = NJ_SYNTAX_ERROR;
}
}
return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);
}
NJ_INLINE void njSkipBits(int bits) {
if (nj.bufbits < bits)
(void) njShowBits(bits);
nj.bufbits -= bits;
}
NJ_INLINE int njGetBits(int bits) {
int res = njShowBits(bits);
njSkipBits(bits);
return res;
}
NJ_INLINE void njByteAlign(void) {
nj.bufbits &= 0xF8;
}
static void njSkip(int count) {
nj.pos += count;
nj.size -= count;
nj.length -= count;
if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;
}
NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
return (pos[0] << 8) | pos[1];
}
static void njDecodeLength(void) {
if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);
nj.length = njDecode16(nj.pos);
if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);
njSkip(2);
}
NJ_INLINE void njSkipMarker(void) {
njDecodeLength();
njSkip(nj.length);
}
NJ_INLINE void njDecodeSOF(void) {
int i, ssxmax = 0, ssymax = 0;
nj_component_t* c;
njDecodeLength();
njCheckError();
if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);
nj.height = njDecode16(nj.pos+1);
nj.width = njDecode16(nj.pos+3);
if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);
nj.ncomp = nj.pos[5];
njSkip(6);
switch (nj.ncomp) {
case 1:
case 3:
break;
default:
njThrow(NJ_UNSUPPORTED);
}
if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
c->cid = nj.pos[0];
if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);
if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);
if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);
njSkip(3);
nj.qtused |= 1 << c->qtsel;
if (c->ssx > ssxmax) ssxmax = c->ssx;
if (c->ssy > ssymax) ssymax = c->ssy;
}
if (nj.ncomp == 1) {
c = nj.comp;
c->ssx = c->ssy = ssxmax = ssymax = 1;
}
nj.mbsizex = ssxmax << 3;
nj.mbsizey = ssymax << 3;
nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;
nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;
c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;
c->stride = nj.mbwidth * c->ssx << 3;
if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);
if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM);
}
if (nj.ncomp == 3) {
nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);
if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);
}
njSkip(nj.length);
}
NJ_INLINE void njDecodeDHT(void) {
int codelen, currcnt, remain, spread, i, j;
nj_vlc_code_t *vlc;
static unsigned char counts[16];
njDecodeLength();
njCheckError();
while (nj.length >= 17) {
i = nj.pos[0];
if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);
if (i & 0x02) njThrow(NJ_UNSUPPORTED);
i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value
for (codelen = 1; codelen <= 16; ++codelen)
counts[codelen - 1] = nj.pos[codelen];
njSkip(17);
vlc = &nj.vlctab[i][0];
remain = spread = 65536;
for (codelen = 1; codelen <= 16; ++codelen) {
spread >>= 1;
currcnt = counts[codelen - 1];
if (!currcnt) continue;
if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);
remain -= currcnt << (16 - codelen);
if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
for (i = 0; i < currcnt; ++i) {
register unsigned char code = nj.pos[i];
for (j = spread; j; --j) {
vlc->bits = (unsigned char) codelen;
vlc->code = code;
++vlc;
}
}
njSkip(currcnt);
}
while (remain--) {
vlc->bits = 0;
++vlc;
}
}
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
}
NJ_INLINE void njDecodeDQT(void) {
int i;
unsigned char *t;
njDecodeLength();
njCheckError();
while (nj.length >= 65) {
i = nj.pos[0];
if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);
nj.qtavail |= 1 << i;
t = &nj.qtab[i][0];
for (i = 0; i < 64; ++i)
t[i] = nj.pos[i + 1];
njSkip(65);
}
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
}
NJ_INLINE void njDecodeDRI(void) {
njDecodeLength();
njCheckError();
if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);
nj.rstinterval = njDecode16(nj.pos);
njSkip(nj.length);
}
static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {
int value = njShowBits(16);
int bits = vlc[value].bits;
if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }
njSkipBits(bits);
value = vlc[value].code;
if (code) *code = (unsigned char) value;
bits = value & 15;
if (!bits) return 0;
value = njGetBits(bits);
if (value < (1 << (bits - 1)))
value += ((-1) << bits) + 1;
return value;
}
NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {
unsigned char code = 0;
int value, coef = 0;
njFillMem(nj.block, 0, sizeof(nj.block));
c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);
nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];
do {
value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);
if (!code) break; // EOB
if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);
coef += (code >> 4) + 1;
if (coef > 63) njThrow(NJ_SYNTAX_ERROR);
nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];
} while (coef < 63);
for (coef = 0; coef < 64; coef += 8)
njRowIDCT(&nj.block[coef]);
for (coef = 0; coef < 8; ++coef)
njColIDCT(&nj.block[coef], &out[coef], c->stride);
}
NJ_INLINE void njDecodeScan(void) {
int i, mbx, mby, sbx, sby;
int rstcount = nj.rstinterval, nextrst = 0;
nj_component_t* c;
njDecodeLength();
njCheckError();
if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);
njSkip(1);
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);
c->dctabsel = nj.pos[1] >> 4;
c->actabsel = (nj.pos[1] & 1) | 2;
njSkip(2);
}
if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);
njSkip(nj.length);
for (mbx = mby = 0;;) {
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c)
for (sby = 0; sby < c->ssy; ++sby)
for (sbx = 0; sbx < c->ssx; ++sbx) {
njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]);
njCheckError();
}
if (++mbx >= nj.mbwidth) {
mbx = 0;
if (++mby >= nj.mbheight) break;
}
if (nj.rstinterval && !(--rstcount)) {
njByteAlign();
i = njGetBits(16);
if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);
nextrst = (nextrst + 1) & 7;
rstcount = nj.rstinterval;
for (i = 0; i < 3; ++i)
nj.comp[i].dcpred = 0;
}
}
nj.error = __NJ_FINISHED;
}
#if NJ_CHROMA_FILTER
#define CF4A (-9)
#define CF4B (111)
#define CF4C (29)
#define CF4D (-3)
#define CF3A (28)
#define CF3B (109)
#define CF3C (-9)
#define CF3X (104)
#define CF3Y (27)
#define CF3Z (-3)
#define CF2A (139)
#define CF2B (-11)
#define CF(x) njClip(((x) + 64) >> 7)
NJ_INLINE void njUpsampleH(nj_component_t* c) {
const int xmax = c->width - 3;
unsigned char *out, *lin, *lout;
int x, y;
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
if (!out) njThrow(NJ_OUT_OF_MEM);
lin = c->pixels;
lout = out;
for (y = c->height; y; --y) {
lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);
lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);
lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);
for (x = 0; x < xmax; ++x) {
lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);
lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);
}
lin += c->stride;
lout += c->width << 1;
lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);
lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);
lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);
}
c->width <<= 1;
c->stride = c->width;
njFreeMem((void*)c->pixels);
c->pixels = out;
}
NJ_INLINE void njUpsampleV(nj_component_t* c) {
const int w = c->width, s1 = c->stride, s2 = s1 + s1;
unsigned char *out, *cin, *cout;
int x, y;
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
if (!out) njThrow(NJ_OUT_OF_MEM);
for (x = 0; x < w; ++x) {
cin = &c->pixels[x];
cout = &out[x];
*cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w;
*cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w;
*cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w;
cin += s1;
for (y = c->height - 3; y; --y) {
*cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w;
*cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w;
cin += s1;
}
cin += s1;
*cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w;
*cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w;
*cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);
}
c->height <<= 1;
c->stride = c->width;
njFreeMem((void*) c->pixels);
c->pixels = out;
}
#else
NJ_INLINE void njUpsample(nj_component_t* c) {
int x, y, xshift = 0, yshift = 0;
unsigned char *out, *lin, *lout;
while (c->width < nj.width) { c->width <<= 1; ++xshift; }
while (c->height < nj.height) { c->height <<= 1; ++yshift; }
out = (unsigned char*) njAllocMem(c->width * c->height);
if (!out) njThrow(NJ_OUT_OF_MEM);
lin = c->pixels;
lout = out;
for (y = 0; y < c->height; ++y) {
lin = &c->pixels[(y >> yshift) * c->stride];
for (x = 0; x < c->width; ++x)
lout[x] = lin[x >> xshift];
lout += c->width;
}
c->stride = c->width;
njFreeMem((void*) c->pixels);
c->pixels = out;
}
#endif
NJ_INLINE void njConvert(void) {
int i;
nj_component_t* c;
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
#if NJ_CHROMA_FILTER
while ((c->width < nj.width) || (c->height < nj.height)) {
if (c->width < nj.width) njUpsampleH(c);
njCheckError();
if (c->height < nj.height) njUpsampleV(c);
njCheckError();
}
#else
if ((c->width < nj.width) || (c->height < nj.height))
njUpsample(c);
#endif
if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);
}
if (nj.ncomp == 3) {
// convert to RGB
int x, yy;
unsigned char *prgb = nj.rgb;
const unsigned char *py = nj.comp[0].pixels;
const unsigned char *pcb = nj.comp[1].pixels;
const unsigned char *pcr = nj.comp[2].pixels;
for (yy = nj.height; yy; --yy) {
for (x = 0; x < nj.width; ++x) {
register int y = py[x] << 8;
register int cb = pcb[x] - 128;
register int cr = pcr[x] - 128;
*prgb++ = njClip((y + 359 * cr + 128) >> 8);
*prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8);
*prgb++ = njClip((y + 454 * cb + 128) >> 8);
}
py += nj.comp[0].stride;
pcb += nj.comp[1].stride;
pcr += nj.comp[2].stride;
}
} else if (nj.comp[0].width != nj.comp[0].stride) {
// grayscale -> only remove stride
unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];
unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];
int y;
for (y = nj.comp[0].height - 1; y; --y) {
njCopyMem(pout, pin, nj.comp[0].width);
pin += nj.comp[0].stride;
pout += nj.comp[0].width;
}
nj.comp[0].stride = nj.comp[0].width;
}
}
void njInit(void) {
njFillMem(&nj, 0, sizeof(nj_context_t));
}
void njDone(void) {
int i;
for (i = 0; i < 3; ++i)
if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);
if (nj.rgb) njFreeMem((void*) nj.rgb);
njInit();
}
nj_result_t njDecode(const void* jpeg, const int size) {
njDone();
nj.pos = (const unsigned char*) jpeg;
nj.size = size & 0x7FFFFFFF;
if (nj.size < 2) return NJ_NO_JPEG;
if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;
njSkip(2);
while (!nj.error) {
if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;
njSkip(2);
switch (nj.pos[-1]) {
case 0xC0: njDecodeSOF(); break;
case 0xC4: njDecodeDHT(); break;
case 0xDB: njDecodeDQT(); break;
case 0xDD: njDecodeDRI(); break;
case 0xDA: njDecodeScan(); break;
case 0xFE: njSkipMarker(); break;
default:
if ((nj.pos[-1] & 0xF0) == 0xE0)
njSkipMarker();
else
return NJ_UNSUPPORTED;
}
}
if (nj.error != __NJ_FINISHED) return nj.error;
nj.error = NJ_OK;
njConvert();
return nj.error;
}
int njGetWidth(void) { return nj.width; }
int njGetHeight(void) { return nj.height; }
int njIsColor(void) { return (nj.ncomp != 1); }
unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; }
#endif // _NJ_INCLUDE_HEADER_ONLY

View file

@ -1 +0,0 @@
-http://keyj.emphy.de/nanojpeg/

View file

@ -1,64 +0,0 @@
#ifdef QB64_BACKSLASH_FILESYSTEM
# include "src\\nanojpeg.c"
#else
# include "src/nanojpeg.c"
#endif
uint8 *image_decode_jpg(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
static int32 init = 0;
if (!init) {
init = 1;
njInit();
}
if (njDecode(content, bytes))
return NULL;
static uint8 *si;
si = (uint8 *)njGetImage();
static int32 w, h;
w = njGetWidth();
h = njGetHeight();
static uint8 *di;
if (njIsColor) { // RGB
// Create a buffer large enough to store image
if (w * h * 3 != njGetImageSize())
return NULL;
di = (uint8 *)malloc(w * h * 4);
// RGB->BGRA
static int32 c;
c = w * h;
while (c--) {
di[c * 4 + 2] = si[c * 3]; // red
di[c * 4 + 1] = si[c * 3 + 1]; // green
di[c * 4] = si[c * 3 + 2]; // blue
di[c * 4 + 3] = 255; // alpha
}
} else { // Greyscale
// Create a buffer large enough to store image
if (w * h != njGetImageSize())
return NULL;
di = (uint8 *)malloc(w * h * 4);
// Greyscale->BGRA
static int32 c;
c = w * h;
while (c--) {
di[c * 4 + 2] = si[c]; // red
di[c * 4 + 1] = si[c]; // green
di[c * 4] = si[c]; // blue
di[c * 4 + 3] = 255; // alpha
}
}
*result = 1 + 2;
*x = w;
*y = h;
return di;
}

View file

@ -1,916 +0,0 @@
// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder
// version 1.3.5 (2016-11-14)
// Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>
// published under the terms of the MIT license
//
// 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.
///////////////////////////////////////////////////////////////////////////////
// DOCUMENTATION SECTION //
// read this if you want to know what this is all about //
///////////////////////////////////////////////////////////////////////////////
// INTRODUCTION
// ============
//
// This is a minimal decoder for baseline JPEG images. It accepts memory dumps
// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit
// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files
// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are
// not supported. All YCbCr subsampling schemes with power-of-two ratios are
// supported, as are restart intervals. Progressive or lossless JPEG is not
// supported.
// Summed up, NanoJPEG should be able to decode all images from digital cameras
// and most common forms of other non-progressive JPEG images.
// The decoder is not optimized for speed, it's optimized for simplicity and
// small code. Image quality should be at a reasonable level. A bicubic chroma
// upsampling filter ensures that subsampled YCbCr images are rendered in
// decent quality. The decoder is not meant to deal with broken JPEG files in
// a graceful manner; if anything is wrong with the bitstream, decoding will
// simply fail.
// The code should work with every modern C compiler without problems and
// should not emit any warnings. It uses only (at least) 32-bit integer
// arithmetic and is supposed to be endianness independent and 64-bit clean.
// However, it is not thread-safe.
// COMPILE-TIME CONFIGURATION
// ==========================
//
// The following aspects of NanoJPEG can be controlled with preprocessor
// defines:
//
// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example
// program.
// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header
// file for NanoJPEG. Example:
// #define _NJ_INCLUDE_HEADER_ONLY
// #include "nanojpeg.c"
// int main(void) {
// njInit();
// // your code here
// njDone();
// }
// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy()
// functions from the standard C library (default).
// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode,
// external functions njAlloc(), njFreeMem(),
// njFillMem() and njCopyMem() need to be defined
// and implemented somewhere.
// NJ_USE_WIN32=0 = Normal mode (default).
// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and
// NJ_USE_LIBC=0, NanoJPEG will use its own
// implementations of the required C library
// functions (default if compiling with MSVC and
// NJ_USE_LIBC=0).
// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter
// (default).
// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling
// (bad quality, but faster and less code).
// API
// ===
//
// For API documentation, read the "header section" below.
// EXAMPLE
// =======
//
// A few pages below, you can find an example program that uses NanoJPEG to
// convert JPEG files into PGM or PPM. To compile it, use something like
// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c
// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)
// The only thing you might need is -Wno-shift-negative-value, because this
// code relies on the target machine using two's complement arithmetic, but
// the C standard does not, even though *any* practically useful machine
// nowadays uses two's complement.
///////////////////////////////////////////////////////////////////////////////
// HEADER SECTION //
// copy and pase this into nanojpeg.h if you want //
///////////////////////////////////////////////////////////////////////////////
#ifndef _NANOJPEG_H
#define _NANOJPEG_H
// nj_result_t: Result codes for njDecode().
typedef enum _nj_result {
NJ_OK = 0, // no error, decoding successful
NJ_NO_JPEG, // not a JPEG file
NJ_UNSUPPORTED, // unsupported format
NJ_OUT_OF_MEM, // out of memory
NJ_INTERNAL_ERR, // internal error
NJ_SYNTAX_ERROR, // syntax error
__NJ_FINISHED, // used internally, will never be reported
} nj_result_t;
// njInit: Initialize NanoJPEG.
// For safety reasons, this should be called at least one time before using
// using any of the other NanoJPEG functions.
void njInit(void);
// njDecode: Decode a JPEG image.
// Decodes a memory dump of a JPEG file into internal buffers.
// Parameters:
// jpeg = The pointer to the memory dump.
// size = The size of the JPEG file.
// Return value: The error code in case of failure, or NJ_OK (zero) on success.
nj_result_t njDecode(const void* jpeg, const int size);
// njGetWidth: Return the width (in pixels) of the most recently decoded
// image. If njDecode() failed, the result of njGetWidth() is undefined.
int njGetWidth(void);
// njGetHeight: Return the height (in pixels) of the most recently decoded
// image. If njDecode() failed, the result of njGetHeight() is undefined.
int njGetHeight(void);
// njIsColor: Return 1 if the most recently decoded image is a color image
// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
// of njGetWidth() is undefined.
int njIsColor(void);
// njGetImage: Returns the decoded image data.
// Returns a pointer to the most recently image. The memory layout it byte-
// oriented, top-down, without any padding between lines. Pixels of color
// images will be stored as three consecutive bytes for the red, green and
// blue channels. This data format is thus compatible with the PGM or PPM
// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
// If njDecode() failed, the result of njGetImage() is undefined.
unsigned char* njGetImage(void);
// njGetImageSize: Returns the size (in bytes) of the image data returned
// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
// undefined.
int njGetImageSize(void);
// njDone: Uninitialize NanoJPEG.
// Resets NanoJPEG's internal state and frees all memory that has been
// allocated at run-time by NanoJPEG. It is still possible to decode another
// image after a njDone() call.
void njDone(void);
#endif//_NANOJPEG_H
///////////////////////////////////////////////////////////////////////////////
// CONFIGURATION SECTION //
// adjust the default settings for the NJ_ defines here //
///////////////////////////////////////////////////////////////////////////////
#ifndef NJ_USE_LIBC
#define NJ_USE_LIBC 1
#endif
#ifndef NJ_USE_WIN32
#ifdef _MSC_VER
#define NJ_USE_WIN32 (!NJ_USE_LIBC)
#else
#define NJ_USE_WIN32 0
#endif
#endif
#ifndef NJ_CHROMA_FILTER
#define NJ_CHROMA_FILTER 1
#endif
///////////////////////////////////////////////////////////////////////////////
// EXAMPLE PROGRAM //
// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) //
///////////////////////////////////////////////////////////////////////////////
#ifdef _NJ_EXAMPLE_PROGRAM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
int size;
char *buf;
FILE *f;
if (argc < 2) {
printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
return 2;
}
f = fopen(argv[1], "rb");
if (!f) {
printf("Error opening the input file.\n");
return 1;
}
fseek(f, 0, SEEK_END);
size = (int) ftell(f);
buf = (char*) malloc(size);
fseek(f, 0, SEEK_SET);
size = (int) fread(buf, 1, size, f);
fclose(f);
njInit();
if (njDecode(buf, size)) {
free((void*)buf);
printf("Error decoding the input file.\n");
return 1;
}
free((void*)buf);
f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
if (!f) {
printf("Error opening the output file.\n");
return 1;
}
fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
fwrite(njGetImage(), 1, njGetImageSize(), f);
fclose(f);
njDone();
return 0;
}
#endif
///////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION SECTION //
// you may stop reading here //
///////////////////////////////////////////////////////////////////////////////
#ifndef _NJ_INCLUDE_HEADER_ONLY
#ifdef _MSC_VER
#define NJ_INLINE static __inline
#define NJ_FORCE_INLINE static __forceinline
#else
#define NJ_INLINE static inline
#define NJ_FORCE_INLINE static inline
#endif
#if NJ_USE_LIBC
#include <stdlib.h>
#include <string.h>
#define njAllocMem malloc
#define njFreeMem free
#define njFillMem memset
#define njCopyMem memcpy
#elif NJ_USE_WIN32
#include <windows.h>
#define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
#define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
mov edi, block
mov al, value
mov ecx, count
rep stosb
} }
NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
mov edi, dest
mov esi, src
mov ecx, count
rep movsb
} }
#else
extern void* njAllocMem(int size);
extern void njFreeMem(void* block);
extern void njFillMem(void* block, unsigned char byte, int size);
extern void njCopyMem(void* dest, const void* src, int size);
#endif
typedef struct _nj_code {
unsigned char bits, code;
} nj_vlc_code_t;
typedef struct _nj_cmp {
int cid;
int ssx, ssy;
int width, height;
int stride;
int qtsel;
int actabsel, dctabsel;
int dcpred;
unsigned char *pixels;
} nj_component_t;
typedef struct _nj_ctx {
nj_result_t error;
const unsigned char *pos;
int size;
int length;
int width, height;
int mbwidth, mbheight;
int mbsizex, mbsizey;
int ncomp;
nj_component_t comp[3];
int qtused, qtavail;
unsigned char qtab[4][64];
nj_vlc_code_t vlctab[4][65536];
int buf, bufbits;
int block[64];
int rstinterval;
unsigned char *rgb;
} nj_context_t;
static nj_context_t nj;
static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
NJ_FORCE_INLINE unsigned char njClip(const int x) {
return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
}
#define W1 2841
#define W2 2676
#define W3 2408
#define W5 1609
#define W6 1108
#define W7 565
NJ_INLINE void njRowIDCT(int* blk) {
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
if (!((x1 = blk[4] << 11)
| (x2 = blk[6])
| (x3 = blk[2])
| (x4 = blk[1])
| (x5 = blk[7])
| (x6 = blk[5])
| (x7 = blk[3])))
{
blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;
return;
}
x0 = (blk[0] << 11) + 128;
x8 = W7 * (x4 + x5);
x4 = x8 + (W1 - W7) * x4;
x5 = x8 - (W1 + W7) * x5;
x8 = W3 * (x6 + x7);
x6 = x8 - (W3 - W5) * x6;
x7 = x8 - (W3 + W5) * x7;
x8 = x0 + x1;
x0 -= x1;
x1 = W6 * (x3 + x2);
x2 = x1 - (W2 + W6) * x2;
x3 = x1 + (W2 - W6) * x3;
x1 = x4 + x6;
x4 -= x6;
x6 = x5 + x7;
x5 -= x7;
x7 = x8 + x3;
x8 -= x3;
x3 = x0 + x2;
x0 -= x2;
x2 = (181 * (x4 + x5) + 128) >> 8;
x4 = (181 * (x4 - x5) + 128) >> 8;
blk[0] = (x7 + x1) >> 8;
blk[1] = (x3 + x2) >> 8;
blk[2] = (x0 + x4) >> 8;
blk[3] = (x8 + x6) >> 8;
blk[4] = (x8 - x6) >> 8;
blk[5] = (x0 - x4) >> 8;
blk[6] = (x3 - x2) >> 8;
blk[7] = (x7 - x1) >> 8;
}
NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
if (!((x1 = blk[8*4] << 8)
| (x2 = blk[8*6])
| (x3 = blk[8*2])
| (x4 = blk[8*1])
| (x5 = blk[8*7])
| (x6 = blk[8*5])
| (x7 = blk[8*3])))
{
x1 = njClip(((blk[0] + 32) >> 6) + 128);
for (x0 = 8; x0; --x0) {
*out = (unsigned char) x1;
out += stride;
}
return;
}
x0 = (blk[0] << 8) + 8192;
x8 = W7 * (x4 + x5) + 4;
x4 = (x8 + (W1 - W7) * x4) >> 3;
x5 = (x8 - (W1 + W7) * x5) >> 3;
x8 = W3 * (x6 + x7) + 4;
x6 = (x8 - (W3 - W5) * x6) >> 3;
x7 = (x8 - (W3 + W5) * x7) >> 3;
x8 = x0 + x1;
x0 -= x1;
x1 = W6 * (x3 + x2) + 4;
x2 = (x1 - (W2 + W6) * x2) >> 3;
x3 = (x1 + (W2 - W6) * x3) >> 3;
x1 = x4 + x6;
x4 -= x6;
x6 = x5 + x7;
x5 -= x7;
x7 = x8 + x3;
x8 -= x3;
x3 = x0 + x2;
x0 -= x2;
x2 = (181 * (x4 + x5) + 128) >> 8;
x4 = (181 * (x4 - x5) + 128) >> 8;
*out = njClip(((x7 + x1) >> 14) + 128); out += stride;
*out = njClip(((x3 + x2) >> 14) + 128); out += stride;
*out = njClip(((x0 + x4) >> 14) + 128); out += stride;
*out = njClip(((x8 + x6) >> 14) + 128); out += stride;
*out = njClip(((x8 - x6) >> 14) + 128); out += stride;
*out = njClip(((x0 - x4) >> 14) + 128); out += stride;
*out = njClip(((x3 - x2) >> 14) + 128); out += stride;
*out = njClip(((x7 - x1) >> 14) + 128);
}
#define njThrow(e) do { nj.error = e; return; } while (0)
#define njCheckError() do { if (nj.error) return; } while (0)
static int njShowBits(int bits) {
unsigned char newbyte;
if (!bits) return 0;
while (nj.bufbits < bits) {
if (nj.size <= 0) {
nj.buf = (nj.buf << 8) | 0xFF;
nj.bufbits += 8;
continue;
}
newbyte = *nj.pos++;
nj.size--;
nj.bufbits += 8;
nj.buf = (nj.buf << 8) | newbyte;
if (newbyte == 0xFF) {
if (nj.size) {
unsigned char marker = *nj.pos++;
nj.size--;
switch (marker) {
case 0x00:
case 0xFF:
break;
case 0xD9: nj.size = 0; break;
default:
if ((marker & 0xF8) != 0xD0)
nj.error = NJ_SYNTAX_ERROR;
else {
nj.buf = (nj.buf << 8) | marker;
nj.bufbits += 8;
}
}
} else
nj.error = NJ_SYNTAX_ERROR;
}
}
return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);
}
NJ_INLINE void njSkipBits(int bits) {
if (nj.bufbits < bits)
(void) njShowBits(bits);
nj.bufbits -= bits;
}
NJ_INLINE int njGetBits(int bits) {
int res = njShowBits(bits);
njSkipBits(bits);
return res;
}
NJ_INLINE void njByteAlign(void) {
nj.bufbits &= 0xF8;
}
static void njSkip(int count) {
nj.pos += count;
nj.size -= count;
nj.length -= count;
if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;
}
NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
return (pos[0] << 8) | pos[1];
}
static void njDecodeLength(void) {
if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);
nj.length = njDecode16(nj.pos);
if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);
njSkip(2);
}
NJ_INLINE void njSkipMarker(void) {
njDecodeLength();
njSkip(nj.length);
}
NJ_INLINE void njDecodeSOF(void) {
int i, ssxmax = 0, ssymax = 0;
nj_component_t* c;
njDecodeLength();
njCheckError();
if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);
nj.height = njDecode16(nj.pos+1);
nj.width = njDecode16(nj.pos+3);
if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);
nj.ncomp = nj.pos[5];
njSkip(6);
switch (nj.ncomp) {
case 1:
case 3:
break;
default:
njThrow(NJ_UNSUPPORTED);
}
if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
c->cid = nj.pos[0];
if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);
if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);
if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);
njSkip(3);
nj.qtused |= 1 << c->qtsel;
if (c->ssx > ssxmax) ssxmax = c->ssx;
if (c->ssy > ssymax) ssymax = c->ssy;
}
if (nj.ncomp == 1) {
c = nj.comp;
c->ssx = c->ssy = ssxmax = ssymax = 1;
}
nj.mbsizex = ssxmax << 3;
nj.mbsizey = ssymax << 3;
nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;
nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;
c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;
c->stride = nj.mbwidth * c->ssx << 3;
if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);
if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM);
}
if (nj.ncomp == 3) {
nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);
if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);
}
njSkip(nj.length);
}
NJ_INLINE void njDecodeDHT(void) {
int codelen, currcnt, remain, spread, i, j;
nj_vlc_code_t *vlc;
static unsigned char counts[16];
njDecodeLength();
njCheckError();
while (nj.length >= 17) {
i = nj.pos[0];
if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);
if (i & 0x02) njThrow(NJ_UNSUPPORTED);
i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value
for (codelen = 1; codelen <= 16; ++codelen)
counts[codelen - 1] = nj.pos[codelen];
njSkip(17);
vlc = &nj.vlctab[i][0];
remain = spread = 65536;
for (codelen = 1; codelen <= 16; ++codelen) {
spread >>= 1;
currcnt = counts[codelen - 1];
if (!currcnt) continue;
if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);
remain -= currcnt << (16 - codelen);
if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
for (i = 0; i < currcnt; ++i) {
register unsigned char code = nj.pos[i];
for (j = spread; j; --j) {
vlc->bits = (unsigned char) codelen;
vlc->code = code;
++vlc;
}
}
njSkip(currcnt);
}
while (remain--) {
vlc->bits = 0;
++vlc;
}
}
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
}
NJ_INLINE void njDecodeDQT(void) {
int i;
unsigned char *t;
njDecodeLength();
njCheckError();
while (nj.length >= 65) {
i = nj.pos[0];
if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);
nj.qtavail |= 1 << i;
t = &nj.qtab[i][0];
for (i = 0; i < 64; ++i)
t[i] = nj.pos[i + 1];
njSkip(65);
}
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
}
NJ_INLINE void njDecodeDRI(void) {
njDecodeLength();
njCheckError();
if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);
nj.rstinterval = njDecode16(nj.pos);
njSkip(nj.length);
}
static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {
int value = njShowBits(16);
int bits = vlc[value].bits;
if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }
njSkipBits(bits);
value = vlc[value].code;
if (code) *code = (unsigned char) value;
bits = value & 15;
if (!bits) return 0;
value = njGetBits(bits);
if (value < (1 << (bits - 1)))
value += ((-1) << bits) + 1;
return value;
}
NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {
unsigned char code = 0;
int value, coef = 0;
njFillMem(nj.block, 0, sizeof(nj.block));
c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);
nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];
do {
value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);
if (!code) break; // EOB
if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);
coef += (code >> 4) + 1;
if (coef > 63) njThrow(NJ_SYNTAX_ERROR);
nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];
} while (coef < 63);
for (coef = 0; coef < 64; coef += 8)
njRowIDCT(&nj.block[coef]);
for (coef = 0; coef < 8; ++coef)
njColIDCT(&nj.block[coef], &out[coef], c->stride);
}
NJ_INLINE void njDecodeScan(void) {
int i, mbx, mby, sbx, sby;
int rstcount = nj.rstinterval, nextrst = 0;
nj_component_t* c;
njDecodeLength();
njCheckError();
if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);
njSkip(1);
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);
if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);
c->dctabsel = nj.pos[1] >> 4;
c->actabsel = (nj.pos[1] & 1) | 2;
njSkip(2);
}
if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);
njSkip(nj.length);
for (mbx = mby = 0;;) {
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c)
for (sby = 0; sby < c->ssy; ++sby)
for (sbx = 0; sbx < c->ssx; ++sbx) {
njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]);
njCheckError();
}
if (++mbx >= nj.mbwidth) {
mbx = 0;
if (++mby >= nj.mbheight) break;
}
if (nj.rstinterval && !(--rstcount)) {
njByteAlign();
i = njGetBits(16);
if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);
nextrst = (nextrst + 1) & 7;
rstcount = nj.rstinterval;
for (i = 0; i < 3; ++i)
nj.comp[i].dcpred = 0;
}
}
nj.error = __NJ_FINISHED;
}
#if NJ_CHROMA_FILTER
#define CF4A (-9)
#define CF4B (111)
#define CF4C (29)
#define CF4D (-3)
#define CF3A (28)
#define CF3B (109)
#define CF3C (-9)
#define CF3X (104)
#define CF3Y (27)
#define CF3Z (-3)
#define CF2A (139)
#define CF2B (-11)
#define CF(x) njClip(((x) + 64) >> 7)
NJ_INLINE void njUpsampleH(nj_component_t* c) {
const int xmax = c->width - 3;
unsigned char *out, *lin, *lout;
int x, y;
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
if (!out) njThrow(NJ_OUT_OF_MEM);
lin = c->pixels;
lout = out;
for (y = c->height; y; --y) {
lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);
lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);
lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);
for (x = 0; x < xmax; ++x) {
lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);
lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);
}
lin += c->stride;
lout += c->width << 1;
lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);
lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);
lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);
}
c->width <<= 1;
c->stride = c->width;
njFreeMem((void*)c->pixels);
c->pixels = out;
}
NJ_INLINE void njUpsampleV(nj_component_t* c) {
const int w = c->width, s1 = c->stride, s2 = s1 + s1;
unsigned char *out, *cin, *cout;
int x, y;
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
if (!out) njThrow(NJ_OUT_OF_MEM);
for (x = 0; x < w; ++x) {
cin = &c->pixels[x];
cout = &out[x];
*cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w;
*cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w;
*cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w;
cin += s1;
for (y = c->height - 3; y; --y) {
*cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w;
*cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w;
cin += s1;
}
cin += s1;
*cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w;
*cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w;
*cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);
}
c->height <<= 1;
c->stride = c->width;
njFreeMem((void*) c->pixels);
c->pixels = out;
}
#else
NJ_INLINE void njUpsample(nj_component_t* c) {
int x, y, xshift = 0, yshift = 0;
unsigned char *out, *lin, *lout;
while (c->width < nj.width) { c->width <<= 1; ++xshift; }
while (c->height < nj.height) { c->height <<= 1; ++yshift; }
out = (unsigned char*) njAllocMem(c->width * c->height);
if (!out) njThrow(NJ_OUT_OF_MEM);
lin = c->pixels;
lout = out;
for (y = 0; y < c->height; ++y) {
lin = &c->pixels[(y >> yshift) * c->stride];
for (x = 0; x < c->width; ++x)
lout[x] = lin[x >> xshift];
lout += c->width;
}
c->stride = c->width;
njFreeMem((void*) c->pixels);
c->pixels = out;
}
#endif
NJ_INLINE void njConvert(void) {
int i;
nj_component_t* c;
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
#if NJ_CHROMA_FILTER
while ((c->width < nj.width) || (c->height < nj.height)) {
if (c->width < nj.width) njUpsampleH(c);
njCheckError();
if (c->height < nj.height) njUpsampleV(c);
njCheckError();
}
#else
if ((c->width < nj.width) || (c->height < nj.height))
njUpsample(c);
#endif
if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);
}
if (nj.ncomp == 3) {
// convert to RGB
int x, yy;
unsigned char *prgb = nj.rgb;
const unsigned char *py = nj.comp[0].pixels;
const unsigned char *pcb = nj.comp[1].pixels;
const unsigned char *pcr = nj.comp[2].pixels;
for (yy = nj.height; yy; --yy) {
for (x = 0; x < nj.width; ++x) {
register int y = py[x] << 8;
register int cb = pcb[x] - 128;
register int cr = pcr[x] - 128;
*prgb++ = njClip((y + 359 * cr + 128) >> 8);
*prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8);
*prgb++ = njClip((y + 454 * cb + 128) >> 8);
}
py += nj.comp[0].stride;
pcb += nj.comp[1].stride;
pcr += nj.comp[2].stride;
}
} else if (nj.comp[0].width != nj.comp[0].stride) {
// grayscale -> only remove stride
unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];
unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];
int y;
for (y = nj.comp[0].height - 1; y; --y) {
njCopyMem(pout, pin, nj.comp[0].width);
pin += nj.comp[0].stride;
pout += nj.comp[0].width;
}
nj.comp[0].stride = nj.comp[0].width;
}
}
void njInit(void) {
njFillMem(&nj, 0, sizeof(nj_context_t));
}
void njDone(void) {
int i;
for (i = 0; i < 3; ++i)
if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);
if (nj.rgb) njFreeMem((void*) nj.rgb);
njInit();
}
nj_result_t njDecode(const void* jpeg, const int size) {
njDone();
nj.pos = (const unsigned char*) jpeg;
nj.size = size & 0x7FFFFFFF;
if (nj.size < 2) return NJ_NO_JPEG;
if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;
njSkip(2);
while (!nj.error) {
if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;
njSkip(2);
switch (nj.pos[-1]) {
case 0xC0: njDecodeSOF(); break;
case 0xC4: njDecodeDHT(); break;
case 0xDB: njDecodeDQT(); break;
case 0xDD: njDecodeDRI(); break;
case 0xDA: njDecodeScan(); break;
case 0xFE: njSkipMarker(); break;
default:
if ((nj.pos[-1] & 0xF0) == 0xE0)
njSkipMarker();
else
return NJ_UNSUPPORTED;
}
}
if (nj.error != __NJ_FINISHED) return nj.error;
nj.error = NJ_OK;
njConvert();
return nj.error;
}
int njGetWidth(void) { return nj.width; }
int njGetHeight(void) { return nj.height; }
int njIsColor(void) { return (nj.ncomp != 1); }
unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; }
#endif // _NJ_INCLUDE_HEADER_ONLY

View file

@ -1 +0,0 @@
https://github.com/nothings/stb

View file

@ -1,97 +0,0 @@
// DOCUMENTATION
//
// Limitations:
// - no 16-bit-per-channel PNG
// - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding
// - no 1-bit BMP
// - GIF always returns *comp=4
//
// Basic usage (see HDR discussion below for HDR usage):
// int x,y,n;
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// // ... process data if not NULL ...
// // ... x = width, y = height, n = # 8-bit components per pixel ...
// // ... replace '0' with '1'..'4' to force that many components per pixel
// // ... but 'n' will always be the number that it would have been if you said 0
// stbi_image_free(data)
//
// Standard parameters:
// int *x -- outputs image width in pixels
// int *y -- outputs image height in pixels
// int *comp -- outputs # of image components in image file
// int req_comp -- if non-zero, # of image components requested in result
//
// The return value from an image loader is an 'unsigned char *' which points
// to the pixel data, or NULL on an allocation failure or if the image is
// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
// with each pixel consisting of N interleaved 8-bit components; the first
// pixel pointed to is top-left-most in the image. There is no padding between
// image scanlines or between pixels, regardless of format. The number of
// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
// If req_comp is non-zero, *comp has the number of components that _would_
// have been output otherwise. E.g. if you set req_comp to 4, you will always
// get RGBA output, but you can check *comp to see if it's trivially opaque
// because e.g. there were only 3 channels in the source image.
//
// An output image with N components has the following components interleaved
// in this order in each pixel:
//
// N=#comp components
// 1 grey
// 2 grey, alpha
// 3 red, green, blue
// 4 red, green, blue, alpha
//
// If image loading fails for any reason, the return value will be NULL,
// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
// can be queried for an extremely brief, end-user unfriendly explanation
// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// more user-friendly ones.
//
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
// STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
// STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp);
// STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp);
#define STB_IMAGE_IMPLEMENTATION
#ifdef QB64_BACKSLASH_FILESYSTEM
# include "src\\stb_image.h"
#else
# include "src/stb_image.h"
#endif
uint8 *image_decode_other(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
int32 h = 0, w = 0;
uint8 *out;
int comp = 0;
out = stbi_load_from_memory(content, bytes, &w, &h, &comp, 4);
if (out == NULL)
return NULL;
// RGBA->BGRA
uint8 *cp = out;
int32 x2, y2;
int32 r, g, b, a;
for (y2 = 0; y2 < h; y2++) {
for (x2 = 0; x2 < w; x2++) {
r = cp[0];
b = cp[2];
cp[0] = b;
cp[2] = r;
cp += 4;
}
}
*result = 1 + 2;
*x = w;
*y = h;
return out;
}

View file

@ -0,0 +1,35 @@
#define DR_PCX_IMPLEMENTATION
#include "src/dr_pcx.h "
uint8 *image_decode_pcx(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
int32 h = 0, w = 0;
uint8 *out;
int comp = 0;
out = drpcx_load_memory(content, bytes, DRPCX_FALSE, &w, &h, &comp, 4);
if (out == NULL)
return NULL;
// RGBA->BGRA
uint8 *cp = out;
int32 x2, y2;
int32 r, g, b, a;
for (y2 = 0; y2 < h; y2++) {
for (x2 = 0; x2 < w; x2++) {
r = cp[0];
b = cp[2];
cp[0] = b;
cp[2] = r;
cp += 4;
}
}
*result = 1 + 2;
*x = w;
*y = h;
return out;
}

View file

@ -0,0 +1,793 @@
// PCX image loader. Public domain. See "unlicense" statement at the end of this file.
// dr_pcx - v0.3.1 - 2018-09-11
//
// David Reid - mackron@gmail.com
// USAGE
//
// dr_pcx is a single-file library. To use it, do something like the following in one .c file.
// #define DR_PCX_IMPLEMENTATION
// #include "dr_pcx.h"
//
// You can then #include this file in other parts of the program as you would with any other header file. Do something like
// the following to load and decode an image:
//
// int width;
// int height;
// int components
// drpcx_uint8* pImageData = drpcx_load_file("my_image.pcx", DRPCX_FALSE, &width, &height, &components, 0);
// if (pImageData == NULL) {
// // Failed to load image.
// }
//
// ...
//
// drpcx_free(pImageData);
//
// The boolean parameter (second argument in the above example) is whether or not the image should be flipped upside down.
//
//
//
// OPTIONS
// #define these options before including this file.
//
// #define DR_PCX_NO_STDIO
// Disable drpcx_load_file().
//
//
//
// QUICK NOTES
// - 2-bpp/4-plane and 4-bpp/1-plane formats have not been tested.
#ifndef dr_pcx_h
#define dr_pcx_h
#include <stddef.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef signed char drpcx_int8;
typedef unsigned char drpcx_uint8;
typedef signed short drpcx_int16;
typedef unsigned short drpcx_uint16;
typedef signed int drpcx_int32;
typedef unsigned int drpcx_uint32;
typedef signed __int64 drpcx_int64;
typedef unsigned __int64 drpcx_uint64;
#else
#include <stdint.h>
typedef int8_t drpcx_int8;
typedef uint8_t drpcx_uint8;
typedef int16_t drpcx_int16;
typedef uint16_t drpcx_uint16;
typedef int32_t drpcx_int32;
typedef uint32_t drpcx_uint32;
typedef int64_t drpcx_int64;
typedef uint64_t drpcx_uint64;
#endif
typedef drpcx_uint8 drpcx_bool8;
typedef drpcx_uint32 drpcx_bool32;
#define DRPCX_TRUE 1
#define DRPCX_FALSE 0
#ifdef __cplusplus
extern "C" {
#endif
// Callback for when data is read. Return value is the number of bytes actually read.
typedef size_t (* drpcx_read_proc)(void* userData, void* bufferOut, size_t bytesToRead);
// Loads a PCX file using the given callbacks.
drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
// Frees memory returned by drpcx_load() and family.
void drpcx_free(void* pReturnValueFromLoad);
#ifndef DR_PCX_NO_STDIO
// Loads an PCX file from an actual file.
drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
#endif
// Helper for loading an PCX file from a block of memory.
drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
#ifdef __cplusplus
}
#endif
#endif // dr_pcx_h
///////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
///////////////////////////////////////////////////////////////////////////////
#ifdef DR_PCX_IMPLEMENTATION
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifndef DR_PCX_NO_STDIO
#include <stdio.h>
static size_t drpcx__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
{
return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
}
drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
{
FILE* pFile;
#ifdef _MSC_VER
if (fopen_s(&pFile, filename, "rb") != 0) {
return NULL;
}
#else
pFile = fopen(filename, "rb");
if (pFile == NULL) {
return NULL;
}
#endif
drpcx_uint8* pImageData = drpcx_load(drpcx__on_read_stdio, pFile, flipped, x, y, internalComponents, desiredComponents);
fclose(pFile);
return pImageData;
}
#endif // DR_PCX_NO_STDIO
typedef struct
{
// A pointer to the beginning of the data. We use a char as the type here for easy offsetting.
const unsigned char* data;
size_t dataSize;
size_t currentReadPos;
} drpcx_memory;
static size_t drpcx__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
{
drpcx_memory* memory = (drpcx_memory*)pUserData;
assert(memory != NULL);
assert(memory->dataSize >= memory->currentReadPos);
size_t bytesRemaining = memory->dataSize - memory->currentReadPos;
if (bytesToRead > bytesRemaining) {
bytesToRead = bytesRemaining;
}
if (bytesToRead > 0) {
memcpy(bufferOut, memory->data + memory->currentReadPos, bytesToRead);
memory->currentReadPos += bytesToRead;
}
return bytesToRead;
}
drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
{
drpcx_memory memory;
memory.data = (const unsigned char*)data;
memory.dataSize = dataSize;
memory.currentReadPos = 0;
return drpcx_load(drpcx__on_read_memory, &memory, flipped, x, y, internalComponents, desiredComponents);
}
typedef struct
{
drpcx_uint8 header;
drpcx_uint8 version;
drpcx_uint8 encoding;
drpcx_uint8 bpp;
drpcx_uint16 left;
drpcx_uint16 top;
drpcx_uint16 right;
drpcx_uint16 bottom;
drpcx_uint16 hres;
drpcx_uint16 vres;
drpcx_uint8 palette16[48];
drpcx_uint8 reserved1;
drpcx_uint8 bitPlanes;
drpcx_uint16 bytesPerLine;
drpcx_uint16 paletteType;
drpcx_uint16 screenSizeH;
drpcx_uint16 screenSizeV;
drpcx_uint8 reserved2[54];
} drpcx_header;
typedef struct
{
drpcx_read_proc onRead;
void* pUserData;
drpcx_bool32 flipped;
drpcx_header header;
drpcx_uint32 width;
drpcx_uint32 height;
drpcx_uint32 components; // 3 = RGB; 4 = RGBA. Only 3 and 4 are supported.
drpcx_uint8* pImageData;
} drpcx;
static drpcx_uint8 drpcx__read_byte(drpcx* pPCX)
{
drpcx_uint8 byte = 0;
pPCX->onRead(pPCX->pUserData, &byte, 1);
return byte;
}
static drpcx_uint8* drpcx__row_ptr(drpcx* pPCX, drpcx_uint32 row)
{
drpcx_uint32 stride = pPCX->width * pPCX->components;
drpcx_uint8* pRow = pPCX->pImageData;
if (pPCX->flipped) {
pRow += (pPCX->height - row - 1) * stride;
} else {
pRow += row * stride;
}
return pRow;
}
static drpcx_uint8 drpcx__rle(drpcx* pPCX, drpcx_uint8* pRLEValueOut)
{
drpcx_uint8 rleCount;
drpcx_uint8 rleValue;
rleValue = drpcx__read_byte(pPCX);
if ((rleValue & 0xC0) == 0xC0) {
rleCount = rleValue & 0x3F;
rleValue = drpcx__read_byte(pPCX);
} else {
rleCount = 1;
}
*pRLEValueOut = rleValue;
return rleCount;
}
drpcx_bool32 drpcx__decode_1bit(drpcx* pPCX)
{
drpcx_uint8 rleCount = 0;
drpcx_uint8 rleValue = 0;
switch (pPCX->header.bitPlanes)
{
case 1:
{
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
drpcx_uint8 mask = (1 << (7 - bit));
drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
pRow[0] = paletteIndex * 255;
pRow[1] = paletteIndex * 255;
pRow[2] = paletteIndex * 255;
pRow += 3;
}
}
}
return DRPCX_TRUE;
} break;
case 2:
case 3:
case 4:
{
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
drpcx_uint8 mask = (1 << (7 - bit));
drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
pRow[0] |= ((paletteIndex & 0x01) << c);
pRow += pPCX->components;
}
}
}
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
drpcx_uint8 paletteIndex = pRow[0];
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
}
pRow += pPCX->components;
}
}
return DRPCX_TRUE;
}
default: return DRPCX_FALSE;
}
}
drpcx_bool32 drpcx__decode_2bit(drpcx* pPCX)
{
drpcx_uint8 rleCount = 0;
drpcx_uint8 rleValue = 0;
switch (pPCX->header.bitPlanes)
{
case 1:
{
drpcx_uint8 paletteCGA[48];
paletteCGA[ 0] = 0x00; paletteCGA[ 1] = 0x00; paletteCGA[ 2] = 0x00; // #000000
paletteCGA[ 3] = 0x00; paletteCGA[ 4] = 0x00; paletteCGA[ 5] = 0xAA; // #0000AA
paletteCGA[ 6] = 0x00; paletteCGA[ 7] = 0xAA; paletteCGA[ 8] = 0x00; // #00AA00
paletteCGA[ 9] = 0x00; paletteCGA[10] = 0xAA; paletteCGA[11] = 0xAA; // #00AAAA
paletteCGA[12] = 0xAA; paletteCGA[13] = 0x00; paletteCGA[14] = 0x00; // #AA0000
paletteCGA[15] = 0xAA; paletteCGA[16] = 0x00; paletteCGA[17] = 0xAA; // #AA00AA
paletteCGA[18] = 0xAA; paletteCGA[19] = 0x55; paletteCGA[20] = 0x00; // #AA5500
paletteCGA[21] = 0xAA; paletteCGA[22] = 0xAA; paletteCGA[23] = 0xAA; // #AAAAAA
paletteCGA[24] = 0x55; paletteCGA[25] = 0x55; paletteCGA[26] = 0x55; // #555555
paletteCGA[27] = 0x55; paletteCGA[28] = 0x55; paletteCGA[29] = 0xFF; // #5555FF
paletteCGA[30] = 0x55; paletteCGA[31] = 0xFF; paletteCGA[32] = 0x55; // #55FF55
paletteCGA[33] = 0x55; paletteCGA[34] = 0xFF; paletteCGA[35] = 0xFF; // #55FFFF
paletteCGA[36] = 0xFF; paletteCGA[37] = 0x55; paletteCGA[38] = 0x55; // #FF5555
paletteCGA[39] = 0xFF; paletteCGA[40] = 0x55; paletteCGA[41] = 0xFF; // #FF55FF
paletteCGA[42] = 0xFF; paletteCGA[43] = 0xFF; paletteCGA[44] = 0x55; // #FFFF55
paletteCGA[45] = 0xFF; paletteCGA[46] = 0xFF; paletteCGA[47] = 0xFF; // #FFFFFF
drpcx_uint8 cgaBGColor = pPCX->header.palette16[0] >> 4;
drpcx_uint8 i = (pPCX->header.palette16[3] & 0x20) >> 5;
drpcx_uint8 p = (pPCX->header.palette16[3] & 0x40) >> 6;
//drpcx_uint8 c = (pPCX->header.palette16[3] & 0x80) >> 7; // Color or monochrome. How is monochrome handled?
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
for (int bit = 0; bit < 4; ++bit) {
if (x*4 + bit < pPCX->width) {
drpcx_uint8 mask = (3 << ((3 - bit) * 2));
drpcx_uint8 paletteIndex = (rleValue & mask) >> ((3 - bit) * 2);
drpcx_uint8 cgaIndex;
if (paletteIndex == 0) { // Background.
cgaIndex = cgaBGColor;
} else { // Foreground
cgaIndex = (((paletteIndex << 1) + p) + (i << 3));
}
pRow[0] = paletteCGA[cgaIndex*3 + 0];
pRow[1] = paletteCGA[cgaIndex*3 + 1];
pRow[2] = paletteCGA[cgaIndex*3 + 2];
pRow += 3;
}
}
}
}
// TODO: According to http://www.fysnet.net/pcxfile.htm, we should use the palette at the end of the file
// instead of the standard CGA palette if the version is equal to 5. With my test files the palette
// at the end of the file does not exist. Research this one.
if (pPCX->header.version == 5) {
drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
if (paletteMarker == 0x0C) {
// TODO: Implement Me.
}
}
return DRPCX_TRUE;
};
case 4:
{
// NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
// TODO: Test Me.
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
for (int bitpair = 0; (bitpair < 4) && ((x*4 + bitpair) < pPCX->width); ++bitpair) {
drpcx_uint8 mask = (4 << (3 - bitpair));
drpcx_uint8 paletteIndex = (rleValue & mask) >> (3 - bitpair);
pRow[0] |= ((paletteIndex & 0x03) << (c*2));
pRow += pPCX->components;
}
}
}
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
drpcx_uint8 paletteIndex = pRow[0];
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
}
pRow += pPCX->components;
}
}
return DRPCX_TRUE;
};
default: return DRPCX_FALSE;
}
}
drpcx_bool32 drpcx__decode_4bit(drpcx* pPCX)
{
// NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
// TODO: Test Me.
if (pPCX->header.bitPlanes > 1) {
return DRPCX_FALSE;
}
drpcx_uint8 rleCount = 0;
drpcx_uint8 rleValue = 0;
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
for (int nibble = 0; (nibble < 2) && ((x*2 + nibble) < pPCX->width); ++nibble)
{
drpcx_uint8 mask = (4 << (1 - nibble));
drpcx_uint8 paletteIndex = (rleValue & mask) >> (1 - nibble);
pRow[0] |= ((paletteIndex & 0x0F) << (c*4));
pRow += pPCX->components;
}
}
}
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
drpcx_uint8 paletteIndex = pRow[0];
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
}
pRow += pPCX->components;
}
}
return DRPCX_TRUE;
}
drpcx_bool32 drpcx__decode_8bit(drpcx* pPCX)
{
drpcx_uint8 rleCount = 0;
drpcx_uint8 rleValue = 0;
drpcx_uint32 stride = pPCX->width * pPCX->components;
switch (pPCX->header.bitPlanes)
{
case 1:
{
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
if (x < pPCX->width) {
pRow[0] = rleValue;
pRow[1] = rleValue;
pRow[2] = rleValue;
pRow += 3;
}
}
}
// At this point we can know if we are dealing with a palette or a grayscale image by checking the next byte. If it's equal to 0x0C, we
// need to do a simple palette lookup.
drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
if (paletteMarker == 0x0C) {
// A palette is present - we need to do a second pass.
drpcx_uint8 palette256[768];
if (pPCX->onRead(pPCX->pUserData, palette256, sizeof(palette256)) != sizeof(palette256)) {
return DRPCX_FALSE;
}
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
drpcx_uint8* pRow = pPCX->pImageData + (y * stride);
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
drpcx_uint8 index = pRow[0];
pRow[0] = palette256[index*3 + 0];
pRow[1] = palette256[index*3 + 1];
pRow[2] = palette256[index*3 + 2];
pRow += 3;
}
}
}
return DRPCX_TRUE;
}
case 3:
case 4:
{
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
if (rleCount == 0) {
rleCount = drpcx__rle(pPCX, &rleValue);
}
rleCount -= 1;
if (x < pPCX->width) {
pRow[c] = rleValue;
pRow += pPCX->components;
}
}
}
}
return DRPCX_TRUE;
}
}
return DRPCX_TRUE;
}
drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
{
if (onRead == NULL) return NULL;
if (desiredComponents > 4) return NULL;
drpcx pcx;
pcx.onRead = onRead;
pcx.pUserData = pUserData;
pcx.flipped = flipped;
if (onRead(pUserData, &pcx.header, sizeof(pcx.header)) != sizeof(pcx.header)) {
return NULL; // Failed to read the header.
}
if (pcx.header.header != 10) {
return NULL; // Not a PCX file.
}
if (pcx.header.encoding != 1) {
return NULL; // Not supporting non-RLE encoding. Would assume a value of 0 indicates raw, unencoded, but that is apparently never used.
}
if (pcx.header.bpp != 1 && pcx.header.bpp != 2 && pcx.header.bpp != 4 && pcx.header.bpp != 8) {
return NULL; // Unsupported pixel format.
}
if (pcx.header.left > pcx.header.right) {
drpcx_uint16 temp = pcx.header.left;
pcx.header.left = pcx.header.right;
pcx.header.right = temp;
}
if (pcx.header.top > pcx.header.bottom) {
drpcx_uint16 temp = pcx.header.top;
pcx.header.top = pcx.header.bottom;
pcx.header.bottom = temp;
}
pcx.width = pcx.header.right - pcx.header.left + 1;
pcx.height = pcx.header.bottom - pcx.header.top + 1;
pcx.components = (pcx.header.bpp == 8 && pcx.header.bitPlanes == 4) ? 4 : 3;
size_t dataSize = pcx.width * pcx.height * pcx.components;
pcx.pImageData = (drpcx_uint8*)calloc(1, dataSize); // <-- Clearing to zero is important! Required for proper decoding.
if (pcx.pImageData == NULL) {
return NULL; // Failed to allocate memory.
}
drpcx_bool32 result = DRPCX_FALSE;
switch (pcx.header.bpp)
{
case 1:
{
result = drpcx__decode_1bit(&pcx);
} break;
case 2:
{
result = drpcx__decode_2bit(&pcx);
} break;
case 4:
{
result = drpcx__decode_4bit(&pcx);
} break;
case 8:
{
result = drpcx__decode_8bit(&pcx);
} break;
}
if (!result) {
free(pcx.pImageData);
return NULL;
}
// There's an annoying amount of branching when loading PCX files so for simplicity I'm doing the component conversion as
// a second pass.
if (desiredComponents == 0) desiredComponents = pcx.components;
if (desiredComponents != (int)pcx.components) {
drpcx_uint8* pNewImageData = (drpcx_uint8*)malloc(pcx.width * pcx.height * desiredComponents);
if (pNewImageData == NULL) {
free(pcx.pImageData);
return NULL;
}
drpcx_uint8* pSrcData = pcx.pImageData;
drpcx_uint8* pDstData = pNewImageData;
if (desiredComponents < (int)pcx.components) {
// We're reducing the number of components. Just drop the excess.
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
for (int c = 0; c < desiredComponents; ++c) {
pDstData[c] = pSrcData[c];
}
pSrcData += pcx.components;
pDstData += desiredComponents;
}
} else {
// We're increasing the number of components. Always ensure the alpha channel is set to 0xFF.
if (pcx.components == 1) {
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
for (int c = 0; c < desiredComponents; ++c) {
pDstData[c] = pSrcData[0];
}
pSrcData += pcx.components;
pDstData += desiredComponents;
}
} else if (pcx.components == 2) {
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
pDstData[0] = pSrcData[0];
pDstData[1] = pSrcData[1];
pDstData[2] = 0x00;
if (desiredComponents == 4) pDstData[3] = 0xFF;
pSrcData += pcx.components;
pDstData += desiredComponents;
}
} else {
assert(pcx.components == 3);
assert(desiredComponents == 4);
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
pDstData[0] = pSrcData[0];
pDstData[1] = pSrcData[1];
pDstData[2] = pSrcData[2];
pDstData[3] = 0xFF;
pSrcData += pcx.components;
pDstData += desiredComponents;
}
}
}
free(pcx.pImageData);
pcx.pImageData = pNewImageData;
}
if (x) *x = pcx.width;
if (y) *y = pcx.height;
if (internalComponents) *internalComponents = pcx.components;
return pcx.pImageData;
}
void drpcx_free(void* pReturnValueFromLoad)
{
free(pReturnValueFromLoad);
}
#endif // DR_PCX_IMPLEMENTATION
// REVISION HISTORY
//
// v0.3.1 - 2018-09-11
// - Styling fixes.
// - Fix a typo.
//
// v0.3 - 2018-02-08
// - API CHANGE: Rename dr_* types to drpcx_*.
//
// v0.2c - 2018-02-07
// - Fix a crash.
//
// v0.2b - 2018-02-02
// - Fix compilation error.
//
// v0.2a - 2017-07-16
// - Change underlying type for booleans to unsigned.
//
// v0.2 - 2016-10-28
// - API CHANGE: Add a parameter to drpcx_load() and family to control the number of output components.
// - Use custom sized types rather than built-in ones to improve support for older MSVC compilers.
//
// v0.1c - 2016-10-23
// - A minor change to drpcx_bool8 and drpcx_bool32 types.
//
// v0.1b - 2016-10-11
// - Use drpcx_bool32 instead of the built-in "bool" type. The reason for this change is that it helps maintain API/ABI consistency
// between C and C++ builds.
//
// v0.1a - 2016-09-18
// - Change date format to ISO 8601 (YYYY-MM-DD)
//
// v0.1 - 2016-05-04
// - Initial versioned release.
// TODO
// - Test 2-bpp/4-plane and 4-bpp/1-plane formats.
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org/>
*/

View file

@ -1,134 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2010 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
Load a BMP image and convert it to a PNG image. This example also shows how
to use other data with the same memory structure as BMP, such as the image
format native to win32, GDI (HBITMAP, BITMAPINFO, ...) often encountered if
you're programming for Windows in Visual Studio.
This example only supports uncompressed 24-bit RGB or 32-bit RGBA bitmaps.
For other types of BMP's, use a full fledged BMP decoder, or convert the
bitmap to 24-bit or 32-bit format.
NOTE: it overwrites the output file without warning if it exists!
*/
//g++ lodepng.cpp example_bmp2png.cpp -ansi -pedantic -Wall -Wextra -O3
#include "lodepng.h"
#include <iostream>
//returns 0 if all went ok, non-0 if error
//output image is always given in RGBA (with alpha channel), even if it's a BMP without alpha channel
unsigned decodeBMP(std::vector<unsigned char>& image, unsigned& w, unsigned& h, const std::vector<unsigned char>& bmp)
{
static const unsigned MINHEADER = 54; //minimum BMP header size
if(bmp.size() < MINHEADER) return -1;
if(bmp[0] != 'B' || bmp[1] != 'M') return 1; //It's not a BMP file if it doesn't start with marker 'BM'
unsigned pixeloffset = bmp[10] + 256 * bmp[11]; //where the pixel data starts
//read width and height from BMP header
w = bmp[18] + bmp[19] * 256;
h = bmp[22] + bmp[23] * 256;
//read number of channels from BMP header
if(bmp[28] != 24 && bmp[28] != 32) return 2; //only 24-bit and 32-bit BMPs are supported.
unsigned numChannels = bmp[28] / 8;
//The amount of scanline bytes is width of image times channels, with extra bytes added if needed
//to make it a multiple of 4 bytes.
unsigned scanlineBytes = w * numChannels;
if(scanlineBytes % 4 != 0) scanlineBytes = (scanlineBytes / 4) * 4 + 4;
unsigned dataSize = scanlineBytes * h;
if(bmp.size() < dataSize + pixeloffset) return 3; //BMP file too small to contain all pixels
image.resize(w * h * 4);
/*
There are 3 differences between BMP and the raw image buffer for LodePNG:
-it's upside down
-it's in BGR instead of RGB format (or BRGA instead of RGBA)
-each scanline has padding bytes to make it a multiple of 4 if needed
The 2D for loop below does all these 3 conversions at once.
*/
for(unsigned y = 0; y < h; y++)
for(unsigned x = 0; x < w; x++)
{
//pixel start byte position in the BMP
unsigned bmpos = pixeloffset + (h - y - 1) * scanlineBytes + numChannels * x;
//pixel start byte position in the new raw image
unsigned newpos = 4 * y * w + 4 * x;
if(numChannels == 3)
{
image[newpos + 0] = bmp[bmpos + 2]; //R
image[newpos + 1] = bmp[bmpos + 1]; //G
image[newpos + 2] = bmp[bmpos + 0]; //B
image[newpos + 3] = 255; //A
}
else
{
image[newpos + 0] = bmp[bmpos + 3]; //R
image[newpos + 1] = bmp[bmpos + 2]; //G
image[newpos + 2] = bmp[bmpos + 1]; //B
image[newpos + 3] = bmp[bmpos + 0]; //A
}
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc < 3)
{
std::cout << "Please provice input PNG and output BMP file names" << std::endl;
return 0;
}
std::vector<unsigned char> bmp;
lodepng::load_file(bmp, argv[1]);
std::vector<unsigned char> image;
unsigned w, h;
unsigned error = decodeBMP(image, w, h, bmp);
if(error)
{
std::cout << "BMP decoding error " << error << std::endl;
return 0;
}
std::vector<unsigned char> png;
error = lodepng::encode(png, image, w, h);
if(error)
{
std::cout << "PNG encoding error " << error << ": " << lodepng_error_text(error) << std::endl;
return 0;
}
lodepng::save_file(png, argv[2]);
}

View file

@ -1,113 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <stdio.h>
#include <stdlib.h>
/*
3 ways to decode a PNG from a file to RGBA pixel data (and 2 in-memory ways).
*/
/*
Example 1
Decode from disk to raw pixels with a single function call
*/
void decodeOneStep(const char* filename)
{
unsigned error;
unsigned char* image;
unsigned width, height;
error = lodepng_decode32_file(&image, &width, &height, filename);
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
/*use image here*/
free(image);
}
/*
Example 2
Load PNG file from disk to memory first, then decode to raw pixels in memory.
*/
void decodeTwoSteps(const char* filename)
{
unsigned error;
unsigned char* image;
unsigned width, height;
unsigned char* png;
size_t pngsize;
lodepng_load_file(&png, &pngsize, filename);
error = lodepng_decode32(&image, &width, &height, png, pngsize);
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
free(png);
/*use image here*/
free(image);
}
/*
Example 3
Load PNG file from disk using a State, normally needed for more advanced usage.
*/
void decodeWithState(const char* filename)
{
unsigned error;
unsigned char* image;
unsigned width, height;
unsigned char* png;
size_t pngsize;
LodePNGState state;
lodepng_state_init(&state);
/*optionally customize the state*/
lodepng_load_file(&png, &pngsize, filename);
error = lodepng_decode(&image, &width, &height, &state, png, pngsize);
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
free(png);
/*use image here*/
/*state contains extra information about the PNG such as text chunks, ...*/
lodepng_state_cleanup(&state);
free(image);
}
int main(int argc, char *argv[])
{
const char* filename = argc > 1 ? argv[1] : "test.png";
decodeOneStep(filename);
return 0;
}

View file

@ -1,95 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <iostream>
/*
3 ways to decode a PNG from a file to RGBA pixel data (and 2 in-memory ways).
*/
//g++ lodepng.cpp example_decode.cpp -ansi -pedantic -Wall -Wextra -O3
//Example 1
//Decode from disk to raw pixels with a single function call
void decodeOneStep(const char* filename)
{
std::vector<unsigned char> image; //the raw pixels
unsigned width, height;
//decode
unsigned error = lodepng::decode(image, width, height, filename);
//if there's an error, display it
if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl;
//the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
}
//Example 2
//Load PNG file from disk to memory first, then decode to raw pixels in memory.
void decodeTwoSteps(const char* filename)
{
std::vector<unsigned char> png;
std::vector<unsigned char> image; //the raw pixels
unsigned width, height;
//load and decode
lodepng::load_file(png, filename);
unsigned error = lodepng::decode(image, width, height, png);
//if there's an error, display it
if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl;
//the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
}
//Example 3
//Load PNG file from disk using a State, normally needed for more advanced usage.
void decodeWithState(const char* filename)
{
std::vector<unsigned char> png;
std::vector<unsigned char> image; //the raw pixels
unsigned width, height;
lodepng::State state; //optionally customize this one
lodepng::load_file(png, filename); //load the image file with given filename
unsigned error = lodepng::decode(image, width, height, state, png);
//if there's an error, display it
if(error) std::cout << "decoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
//the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
//State state contains extra information about the PNG such as text chunks, ...
}
int main(int argc, char *argv[])
{
const char* filename = argc > 1 ? argv[1] : "test.png";
decodeOneStep(filename);
}

View file

@ -1,116 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <stdio.h>
#include <stdlib.h>
/*
3 ways to encode a PNG from RGBA pixel data to a file (and 2 in-memory ways).
NOTE: this samples overwrite the file or test.png without warning!
*/
/*
Example 1
Encode from raw pixels to disk with a single function call
The image argument has width * height RGBA pixels or width * height * 4 bytes
*/
void encodeOneStep(const char* filename, const unsigned char* image, unsigned width, unsigned height)
{
/*Encode the image*/
unsigned error = lodepng_encode32_file(filename, image, width, height);
/*if there's an error, display it*/
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
}
/*
Example 2
Encode from raw pixels to an in-memory PNG file first, then write it to disk
The image argument has width * height RGBA pixels or width * height * 4 bytes
*/
void encodeTwoSteps(const char* filename, const unsigned char* image, unsigned width, unsigned height)
{
unsigned char* png;
size_t pngsize;
unsigned error = lodepng_encode32(&png, &pngsize, image, width, height);
if(!error) lodepng_save_file(png, pngsize, filename);
/*if there's an error, display it*/
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
free(png);
}
/*
Example 3
Save a PNG file to disk using a State, normally needed for more advanced usage.
The image argument has width * height RGBA pixels or width * height * 4 bytes
*/
void encodeWithState(const char* filename, const unsigned char* image, unsigned width, unsigned height)
{
unsigned error;
unsigned char* png;
size_t pngsize;
LodePNGState state;
lodepng_state_init(&state);
/*optionally customize the state*/
error = lodepng_encode(&png, &pngsize, image, width, height, &state);
if(!error) lodepng_save_file(png, pngsize, filename);
/*if there's an error, display it*/
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
lodepng_state_cleanup(&state);
free(png);
}
int main(int argc, char *argv[])
{
const char* filename = argc > 1 ? argv[1] : "test.png";
/*generate some image*/
unsigned width = 512, height = 512;
unsigned char* image = malloc(width * height * 4);
unsigned x, y;
for(y = 0; y < height; y++)
for(x = 0; x < width; x++)
{
image[4 * width * y + 4 * x + 0] = 255 * !(x & y);
image[4 * width * y + 4 * x + 1] = x ^ y;
image[4 * width * y + 4 * x + 2] = x | y;
image[4 * width * y + 4 * x + 3] = 255;
}
/*run an example*/
encodeOneStep(filename, image, width, height);
free(image);
return 0;
}

View file

@ -1,97 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <iostream>
/*
3 ways to encode a PNG from RGBA pixel data to a file (and 2 in-memory ways).
NOTE: this samples overwrite the file or test.png without warning!
*/
//g++ lodepng.cpp example_encode.cpp -ansi -pedantic -Wall -Wextra -O3
//Example 1
//Encode from raw pixels to disk with a single function call
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeOneStep(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height)
{
//Encode the image
unsigned error = lodepng::encode(filename, image, width, height);
//if there's an error, display it
if(error) std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
}
//Example 2
//Encode from raw pixels to an in-memory PNG file first, then write it to disk
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeTwoSteps(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height)
{
std::vector<unsigned char> png;
unsigned error = lodepng::encode(png, image, width, height);
if(!error) lodepng::save_file(png, filename);
//if there's an error, display it
if(error) std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
}
//Example 3
//Save a PNG file to disk using a State, normally needed for more advanced usage.
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeWithState(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height)
{
std::vector<unsigned char> png;
lodepng::State state; //optionally customize this one
unsigned error = lodepng::encode(png, image, width, height, state);
if(!error) lodepng::save_file(png, filename);
//if there's an error, display it
if(error) std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
}
//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char *argv[])
{
//NOTE: this sample will overwrite the file or test.png without warning!
const char* filename = argc > 1 ? argv[1] : "test.png";
//generate some image
unsigned width = 512, height = 512;
std::vector<unsigned char> image;
image.resize(width * height * 4);
for(unsigned y = 0; y < height; y++)
for(unsigned x = 0; x < width; x++)
{
image[4 * width * y + 4 * x + 0] = 255 * !(x & y);
image[4 * width * y + 4 * x + 1] = x ^ y;
image[4 * width * y + 4 * x + 2] = x | y;
image[4 * width * y + 4 * x + 3] = 255;
}
encodeOneStep(filename, image, width, height);
}

View file

@ -1,93 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <iostream>
#include <stdlib.h>
/*
Encodes given file as a gzip file.
See also the gzip specification, RFC 1952: http://www.gzip.org/zlib/rfc-gzip.html
*/
//g++ lodepng.cpp example_gzip.cpp -ansi -pedantic -Wall -Wextra -O3
//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char *argv[])
{
if(argc < 2)
{
std::cout << "Please provide input filename (output is input with .gz)" << std::endl;
return 0;
}
//NOTE: this sample will overwrite the output file without warning!
std::string infilename = argv[1];
std::string outfilename = infilename + ".gz";
std::vector<unsigned char> in;
lodepng::load_file(in, infilename);
size_t outsize = 10;
unsigned char* out = (unsigned char*)malloc(outsize);
out[0] = 31; //ID1
out[1] = 139; //ID2
out[2] = 8; //CM
out[3] = 0; //FLG
//MTIME
out[4] = 0;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 2; //2 = slow, 4 = fast compression
out[9] = 255; //OS unknown
lodepng_deflate(&out, &outsize, &in[0], in.size(), &lodepng_default_compress_settings);
unsigned crc = lodepng_crc32(&in[0], in.size());
size_t footer = outsize;
outsize += 8;
out = (unsigned char*)realloc(out, outsize);
//CRC
out[footer + 0] = crc % 256;
out[footer + 1] = (crc >> 8) % 256;
out[footer + 2] = (crc >> 16) % 256;
out[footer + 3] = (crc >> 24) % 256;
//ISIZE
out[footer + 4] = in.size() % 256;
out[footer + 5] = (in.size() >> 8) % 256;
out[footer + 6] = (in.size() >> 16) % 256;
out[footer + 7] = (in.size() >> 24) % 256;
lodepng_save_file(out, outsize, outfilename.c_str());
free(out);
}

View file

@ -1,132 +0,0 @@
/*
LodePNG Examples
Copyright (c) 2005-2012 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "lodepng.h"
#include <iostream>
/*
This example converts a PNG file to a BMP file.
NOTE: it overwrites the output file without warning if it exists!
Give the PNG and the BMP file names as command line arguments.
*/
/*
g++ lodepng.cpp example_png2bmp.cpp -Wall -Wextra -pedantic -ansi -lSDL -O3
*/
//Input image must be RGB buffer (3 bytes per pixel), but you can easily make it
//support RGBA input and output by changing the inputChannels and/or outputChannels
//in the function to 4.
void encodeBMP(std::vector<unsigned char>& bmp, const unsigned char* image, int w, int h)
{
//3 bytes per pixel used for both input and output.
int inputChannels = 3;
int outputChannels = 3;
//bytes 0-13
bmp.push_back('B'); bmp.push_back('M'); //0: bfType
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //2: bfSize; size not yet known for now, filled in later.
bmp.push_back(0); bmp.push_back(0); //6: bfReserved1
bmp.push_back(0); bmp.push_back(0); //8: bfReserved2
bmp.push_back(54 % 256); bmp.push_back(54 / 256); bmp.push_back(0); bmp.push_back(0); //10: bfOffBits (54 header bytes)
//bytes 14-53
bmp.push_back(40); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //14: biSize
bmp.push_back(w % 256); bmp.push_back(w / 256); bmp.push_back(0); bmp.push_back(0); //18: biWidth
bmp.push_back(h % 256); bmp.push_back(h / 256); bmp.push_back(0); bmp.push_back(0); //22: biHeight
bmp.push_back(1); bmp.push_back(0); //26: biPlanes
bmp.push_back(outputChannels * 8); bmp.push_back(0); //28: biBitCount
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //30: biCompression
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //34: biSizeImage
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //38: biXPelsPerMeter
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //42: biYPelsPerMeter
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //46: biClrUsed
bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); bmp.push_back(0); //50: biClrImportant
/*
Convert the input RGBRGBRGB pixel buffer to the BMP pixel buffer format. There are 3 differences with the input buffer:
-BMP stores the rows inversed, from bottom to top
-BMP stores the color channels in BGR instead of RGB order
-BMP requires each row to have a multiple of 4 bytes, so sometimes padding bytes are added between rows
*/
int imagerowbytes = outputChannels * w;
imagerowbytes = imagerowbytes % 4 == 0 ? imagerowbytes : imagerowbytes + (4 - imagerowbytes % 4); //must be multiple of 4
for(int y = h - 1; y >= 0; y--) //the rows are stored inversed in bmp
{
int c = 0;
for(int x = 0; x < imagerowbytes; x++)
{
if(x < w * outputChannels)
{
int inc = c;
//Convert RGB(A) into BGR(A)
if(c == 0) inc = 2;
else if(c == 2) inc = 0;
bmp.push_back(image[inputChannels * (w * y + x / outputChannels) + inc]);
}
else bmp.push_back(0);
c++;
if(c >= outputChannels) c = 0;
}
}
// Fill in the size
bmp[2] = bmp.size() % 256;
bmp[3] = (bmp.size() / 256) % 256;
bmp[4] = (bmp.size() / 65536) % 256;
bmp[5] = bmp.size() / 16777216;
}
int main(int argc, char *argv[])
{
if(argc < 3)
{
std::cout << "Please provice input PNG and output BMP file names" << std::endl;
return 0;
}
const char* infile = argv[1];
const char* outfile = argv[2];
std::vector<unsigned char> image; //the raw pixels
unsigned width, height;
unsigned error = lodepng::decode(image, width, height, infile, LCT_RGB, 8);
if(error)
{
std::cout << "error " << error << ": " << lodepng_error_text(error) << std::endl;
return 0;
}
std::vector<unsigned char> bmp;
encodeBMP(bmp, &image[0], width, height);
lodepng::save_file(bmp, outfile);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
-http://lodev.org/lodepng/

View file

@ -1,41 +0,0 @@
#ifdef QB64_BACKSLASH_FILESYSTEM
# include "src\\lodepng.cpp"
#else
# include "src/lodepng.cpp"
#endif
uint8 *image_decode_png(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
static unsigned char *png;
static unsigned width, height;
if (lodepng_decode32(&png, &width, &height, (unsigned char *)content, bytes))
return NULL; // RGBA
static uint8 *si;
si = (uint8 *)png;
static int32 w, h;
w = width;
h = height;
static uint8 *di;
di = (uint8 *)malloc(w * h * 4);
// RGBA->BGRA
static int32 c;
c = w * h;
while (c--) {
di[c * 4 + 2] = si[c * 4]; // red
di[c * 4 + 1] = si[c * 4 + 1]; // green
di[c * 4] = si[c * 4 + 2]; // blue
di[c * 4 + 3] = si[c * 4 + 3]; // alpha
}
// Cleanup
free(si);
*result = 1 + 2;
*x = w;
*y = h;
return di;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
#define STB_IMAGE_IMPLEMENTATION
#include "src/stb_image.h"
uint8 *image_decode_stb(uint8 *content, int32 bytes, int32 *result, int32 *x, int32 *y) {
// Result:bit 1=Success,bit 2=32bit[BGRA]
*result = 0;
int32 h = 0, w = 0;
uint8 *out;
int comp = 0;
out = stbi_load_from_memory(content, bytes, &w, &h, &comp, 4);
if (out == NULL)
return NULL;
// RGBA->BGRA
uint8 *cp = out;
int32 x2, y2;
int32 r, g, b, a;
for (y2 = 0; y2 < h; y2++) {
for (x2 = 0; x2 < w; x2++) {
r = cp[0];
b = cp[2];
cp[0] = b;
cp[2] = r;
cp += 4;
}
}
*result = 1 + 2;
*x = w;
*y = h;
return out;
}

View file

@ -4,18 +4,8 @@ extern uint32 matchcol(int32 r, int32 g, int32 b);
// Stub(s):
int32 func__loadimage(qbs *f, int32 bpp, int32 passed);
#else
# ifdef QB64_BACKSLASH_FILESYSTEM
# include "decode\\jpg\\src.c"
# include "decode\\bmp\\src.c"
# include "decode\\other\\src.c" //PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM(PPM/PGM)
# include "decode\\png\\src.c"
# else
# include "decode/bmp/src.c"
# include "decode/jpg/src.c"
# include "decode/other/src.c" //PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM(PPM/PGM)
# include "decode/png/src.c"
# endif
# include "decode/pcx/src.c"
# include "decode/stb/src.c"
int32 func__loadimage(qbs *f, int32 bpp, int32 passed) {
if (new_error)
@ -66,61 +56,24 @@ int32 func__loadimage(qbs *f, int32 bpp, int32 passed) {
return -1;
}
// Identify format:
static int32 format;
format = 0;
//'.png'
if (lof >= 8) {
if ((content[0] == 0x89) && (content[1] == 0x50) && (content[2] == 0x4E) && (content[3] == 0x47) && (content[4] == 0x0D) && (content[5] == 0x0A) &&
(content[6] == 0x1A) && (content[7] == 0x0A)) {
format = 2;
goto got_format;
} // PNG
} // 8
//'.bmp'
if (lof >= 6) {
if ((content[0] == 0x42) && (content[1] == 0x4D)) {
if ((*((int32 *)(&content[2]))) == lof) { // length of file
format = 3;
goto got_format;
}
} // BMP
} // 6
//'.jpg' The first two bytes of every JPEG stream are the Start Of Image (SOI) marker values FFh D8h
if (lof >= 2) {
if ((content[0] == 0xFF) && (content[1] == 0xD8)) {
format = 1;
goto got_format;
} // JP[E]G
} // 2
got_format:
static uint8 *pixels;
static int32 x, y;
if (format == 1)
pixels = image_decode_jpg(content, lof, &result, &x, &y);
if (format == 2)
pixels = image_decode_png(content, lof, &result, &x, &y);
if (format == 3)
pixels = image_decode_bmp(content, lof, &result, &x, &y);
// Try to load the image using dr_pcx
pixels = image_decode_pcx(content, lof, &result, &x, &y);
// If that failed try loading via stb_image
if (!(result & 1)) {
pixels = image_decode_other(content, lof, &result, &x, &y);
pixels = image_decode_stb(content, lof, &result, &x, &y);
}
// Free the memory holding the file
free(content);
// Return failure if nothing was able to load the image
if (!(result & 1))
return -1;
//...
static int32 i;
static int32 prevDest;
static uint16 scanX, scanY;
static uint8 red, green, blue;
i = func__newimage(x, y, 32, 1);
if (i == -1) {

View file

@ -0,0 +1,50 @@
{{QBDLDATE:08-13-2022}}
{{QBDLTIME:00:10:21}}
{{FixedStart}}
''template$'' is a string literal or variable, using the following
formatting characters:
┌───────┬────────────────────────────────────────────────────────────────┐
│ '''&''' │ Prints an entire string value. [[STRING]] length should be limited │
│ │ as template width will vary. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''\ \''' │ Denotes the start and end point of a fixed string area with │
│ │ spaces between([[LEN]] = spaces + 2). │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''!''' │ Prints only the leading character of a string value. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''#''' │ Denotes a numerical digit. An appropriate number of digits │
│ │ should be used for values received. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''^^^^''' │ After # digits prints numerical value in exponential E+xx │
│ │ format. Use ^^^^^ for E+xxx values. '''(1)''' │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''.''' │ Period sets a number's decimal point position. Digits following│
│ │ determine [[CINT|rounded]] value accuracy. │
├───────┼────────────────────────────────────────────────────────────────┤
│ ''',.''' │ [[Comma]] to left of decimal point, prints a comma every 3 used # │
│ │ digit places left of the decimal point. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''+''' │ Plus sign denotes the position of the number's sign. + or - │
│ │ will be displayed. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''-''' │ Minus sign (dash) placed after the number, displays only a │
│ │ negative value's sign. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''$$''' │ Prints a dollar sign immediately before the highest non-zero # │
│ │ digit position of the numerical value. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''**''' │ Prints an asterisk in any leading empty spaces of a numerical │
│ │ value. Adds 2 extra digit positions. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''**$''' │ Combines ** and $$. Negative values will display minus sign to │
│ │ left of $. │
├───────┼────────────────────────────────────────────────────────────────┤
│ '''_''' │ [[Underscore]] preceding a format symbol prints those symbols as │
│ │ literal string characters. │
└───────┴────────────────────────────────────────────────────────────────┘
'''Note:''' Any string character not listed above will be printed as
a literal text character.
'''(1)''' Any # decimal point position may be specified. The exponent is
adjusted with significant digits left-justified.
{{FixedEnd}}