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:
parent
09f2546e35
commit
d3da6da2fa
|
@ -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.
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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
|
|
@ -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.
|
||||
|
||||
*--------------------------------------------------------------------*
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
-http://keyj.emphy.de/nanojpeg/
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
https://github.com/nothings/stb
|
|
@ -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;
|
||||
}
|
35
internal/c/parts/video/image/decode/pcx/src.c
Normal file
35
internal/c/parts/video/image/decode/pcx/src.c
Normal 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;
|
||||
}
|
793
internal/c/parts/video/image/decode/pcx/src/dr_pcx.h
Normal file
793
internal/c/parts/video/image/decode/pcx/src/dr_pcx.h
Normal 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/>
|
||||
*/
|
||||
|
|
@ -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]);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -1 +0,0 @@
|
|||
-http://lodev.org/lodepng/
|
|
@ -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
35
internal/c/parts/video/image/decode/stb/src.c
Normal file
35
internal/c/parts/video/image/decode/stb/src.c
Normal 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;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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) {
|
||||
|
|
|
@ -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}}
|
Loading…
Reference in a new issue