mirror of
https://github.com/dgis/emu48android
synced 2024-12-26 09:58:49 +01:00
Version 2.6 (2022-08-19)
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
This commit is contained in:
parent
d27d777153
commit
bc8bd5b821
24 changed files with 633 additions and 295 deletions
|
@ -58,6 +58,11 @@ LINKS
|
|||
|
||||
CHANGES
|
||||
|
||||
Version 2.6 (2022-08-19)
|
||||
|
||||
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
|
||||
|
||||
|
||||
Version 2.5 (2022-03-03)
|
||||
|
||||
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
||||
|
@ -262,7 +267,7 @@ TODO
|
|||
|
||||
BUILD
|
||||
|
||||
Emu48 for Android is built with Android Studio 2020.3.1 (2021).
|
||||
Emu48 for Android is built with Android Studio 2021.1.1 (2022).
|
||||
And to generate an installable APK file with a real Android device, it MUST be signed.
|
||||
|
||||
Either use Android Studio:
|
||||
|
|
|
@ -28,13 +28,13 @@ if (keystorePropertiesFile.exists()) {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
compileSdkVersion 32
|
||||
defaultConfig {
|
||||
applicationId "org.emulator.forty.eight"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
versionCode 24
|
||||
versionName "2.5"
|
||||
targetSdkVersion 32
|
||||
versionCode 25
|
||||
versionName "2.6"
|
||||
setProperty("archivesBaseName", "Emu48-v$versionName")
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
|
@ -84,10 +84,10 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||
|
|
|
@ -34,7 +34,8 @@ h3 { color:red; font-size:1.1em; }
|
|||
<div id="navi">
|
||||
<p><a class="nav1" href="#s1">1. General</a></p>
|
||||
<p><a class="nav1" href="#s2">2. Acknowledgements</a></p>
|
||||
<p><a class="nav1" href="#s3">3. ROM Images</a></p>
|
||||
<p><a class="nav1" href="#s3">3. ROM Images</a><br>
|
||||
<a class="nav2" href="#ss3.1">3.1 Creation examples</a></p>
|
||||
<p><a class="nav1" href="#s4">4. Installation</a></p>
|
||||
<p><a class="nav1" href="#s5">5. How to Start</a></p>
|
||||
<p><a class="nav1" href="#s6">6. Command Line</a></p>
|
||||
|
@ -83,12 +84,11 @@ h3 { color:red; font-size:1.1em; }
|
|||
<a href="#ss12.2">12.2 About Emu48...</a>
|
||||
</span></p>
|
||||
<p><a class="nav1" href="#s13">13. DDE Server</a></p>
|
||||
<p><a class="nav1" href="#s14">14. Emu48+ Changes</a></p>
|
||||
<p><a class="nav1" href="#s15">15. License</a></p>
|
||||
<p><a class="nav1" href="#s14">14. License</a></p>
|
||||
</div>
|
||||
<div id="main">
|
||||
<h1><a name=s1>1. General</a></h1>
|
||||
<p><a href="http://hp.giesselink.com/emu42.htm">Emu48</a> is an
|
||||
<p><a href="https://hp.giesselink.com/emu48.htm">Emu48</a> is an
|
||||
emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX
|
||||
and HP49G calculator hardware. These calculators are based on the
|
||||
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
|
||||
|
@ -127,73 +127,97 @@ h3 { color:red; font-size:1.1em; }
|
|||
in the destination file with zeros. Final notice, the convert
|
||||
utility shows the CRC result after the file convert and a passed
|
||||
ROM CRC test does <u><b>not</b></u> imply, that the source file
|
||||
is in an Emu48 suitable format!
|
||||
is in an Emu48 suitable format! To create a ROM image in a suitable
|
||||
format, call the convert utility with the 2nd file argument.
|
||||
</p>
|
||||
<ul>
|
||||
<li>HP38
|
||||
<p>To upload the ROM of your HP38G, you will need a special aplet
|
||||
called <a href="http://www.hpcalc.org/details.php?id=633">"ROM UPLOAD"</a>.
|
||||
Once you've uploaded the ROM, you have to convert it using the
|
||||
Convert utility.</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Convert <rom-file> ROM.38G</blockquote>
|
||||
<p>Where <rom-file> is the path to your ROM image. This will
|
||||
create a file named ROM.38G. This tool will also check its validity.
|
||||
</p></li>
|
||||
<li>HP39/40
|
||||
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
|
||||
called <a href="http://hp.giesselink.com/emu48.htm">"ROM UPLOAD"</a>.
|
||||
Once you've uploaded the ROM, you have to convert it using the Rom2emu utility.
|
||||
</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Rom2emu <rom-file> ROM.39G</blockquote>
|
||||
<p>There's also a HP39G/HP40G beta ROM for emulators inside an old
|
||||
<a href="http://www.hpcalc.org/details.php?id=4272">Emu48 package</a>.
|
||||
</p></li>
|
||||
<li>HP48
|
||||
<p>If you have already used another HP48 emulator, you can convert
|
||||
the ROM using the Convert utility.
|
||||
</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Convert <rom-file> ROM.48G</blockquote>
|
||||
<p>or</p>
|
||||
<blockquote>Convert <rom-file> ROM.48S</blockquote>
|
||||
<p>Where <rom-file> is the path to your old ROM image. This
|
||||
will create a file named ROM.48G or ROM.48S, depending on the version
|
||||
you own. This tool should be able to read any style of ROM image, and
|
||||
will also check its validity. Note that if you run it with only one
|
||||
parameter, no file will be written, but it will still check the
|
||||
validity of the ROM.</p>
|
||||
<p>If you have never used an HP48 emulator, and don't have a ROM
|
||||
dump, you can either use Jean-Yves Avenard's ROMUPL.BIN or the
|
||||
ROMDump Wizard V1.x, which will almost automatically get the ROM from
|
||||
your HP48. After the download you may have to convert your dump with
|
||||
the CONVERT utility into the Emu48 format.</p>
|
||||
<p>You can find the latest version of the ROM dump programs on:</p>
|
||||
<blockquote>
|
||||
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
|
||||
http://www.hpcalc.org/details.php?id=3686</a><br>
|
||||
ROMDump Wizard
|
||||
<a href="http://hp.giesselink.com/emu48.htm">
|
||||
http://hp.giesselink.com/emu48.htm</a>
|
||||
</blockquote></li>
|
||||
<li>HP49G
|
||||
<p>There's no ROM download program available so far. But you can
|
||||
create a ROM image with the
|
||||
<a href="http://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
|
||||
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
|
||||
ROM update file</a> for the HP49G calculator. I suggested to use
|
||||
<a href="http://www.hpcalc.org/details.php?id=3240">version 1.19-6</a>
|
||||
</p>
|
||||
<p>To create a HP49G ROM image file, start a Command Prompt while
|
||||
running Windows, and type:</p>
|
||||
<blockquote>UPD49ROM -f hp49119-6.flash ROM.49G</blockquote>
|
||||
<p>This will create a HP49G ROM image file with an empty User
|
||||
Port 2.</p></li>
|
||||
</ul>
|
||||
<p>The general syntax of the convert utility is:</p>
|
||||
<blockquote>Convert [-p] <old-rom-dump> [<new-rom-dump>]</blockquote>
|
||||
<p>where:</p>
|
||||
<blockquote>Convert <old-rom-dump></blockquote>
|
||||
<p>check if <old-rom-dump> is in a known source format and
|
||||
report the ROM Model, the ROM Version and the result of the CRC
|
||||
check.
|
||||
</p>
|
||||
<p>where:</p>
|
||||
<blockquote>Convert <old-rom-dump> <new-rom-dump></blockquote>
|
||||
<p>convert the file <old-rom-dump> into the <u>unpacked</u>
|
||||
ROM image file <new-rom-dump> valid for use in Emu48.
|
||||
</p>
|
||||
<p>where:</p>
|
||||
<blockquote>Convert -p <old-rom-dump> <new-rom-dump></blockquote>
|
||||
<p>convert the file <old-rom-dump> into the <u>packed</u>
|
||||
ROM image file <new-rom-dump> valid for use in Emu48.
|
||||
</p>
|
||||
<h2><a name=ss3.1>3.1 Creation examples</a></h2>
|
||||
<ul>
|
||||
<li>HP38
|
||||
<p>To upload the ROM of your HP38G, you will need a special aplet
|
||||
called <a href="http://www.hpcalc.org/details.php?id=633">"ROM UPLOAD"</a>.
|
||||
Once you've uploaded the ROM, you have to convert it using the
|
||||
Convert utility.</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Convert -p <rom-file> ROM.38G</blockquote>
|
||||
<p>Where <rom-file> is the path to your ROM image. This will
|
||||
create a packed file named ROM.38G. This tool will also check its validity.
|
||||
</p></li>
|
||||
<li>HP39/40
|
||||
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
|
||||
called <a href="https://hp.giesselink.com/emu48.htm">"ROM UPLOAD"</a>.
|
||||
Once you've uploaded the ROM, you may convert it to the unpacked format
|
||||
using the Rom2emu utility or rename it when you want to keep the packed
|
||||
format.
|
||||
</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Rom2emu <rom-file> ROM.39G</blockquote>
|
||||
<p>or</p>
|
||||
<blockquote>rename <rom-file> ROM.39G</blockquote>
|
||||
<p>There's also a HP39G/HP40G beta ROM for emulators inside an old
|
||||
<a href="http://www.hpcalc.org/details.php?id=4272">Emu48 package</a>.
|
||||
</p></li>
|
||||
<li>HP48
|
||||
<p>If you have already used another HP48 emulator, you can convert
|
||||
the ROM using the Convert utility.
|
||||
</p>
|
||||
<p>To do that, start a Command Prompt while running Windows, and
|
||||
type:</p>
|
||||
<blockquote>Convert <rom-file> ROM.48G</blockquote>
|
||||
<p>or</p>
|
||||
<blockquote>Convert <rom-file> ROM.48S</blockquote>
|
||||
<p>Where <rom-file> is the path to your old ROM image. This
|
||||
will create a file named ROM.48G or ROM.48S, depending on the
|
||||
version you own. This tool should be able to read any style of
|
||||
ROM image, and will also check its validity. Note that if you run
|
||||
it with only one parameter, no file will be written, but it will
|
||||
still check the validity of the ROM.</p>
|
||||
<p>If you have never used an HP48 emulator, and don't have a ROM
|
||||
dump, you can either use Jean-Yves Avenard's ROMUPL.BIN or the
|
||||
ROMDump Wizard V1.x, which will almost automatically get the ROM
|
||||
from your HP48. After the download you may have to convert your
|
||||
dump with the CONVERT utility into the Emu48 format.</p>
|
||||
<p>You can find the latest version of the ROM dump programs on:</p>
|
||||
<blockquote>
|
||||
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
|
||||
http://www.hpcalc.org/details.php?id=3686</a><br>
|
||||
ROMDump Wizard
|
||||
<a href="https://hp.giesselink.com/emu48.htm">
|
||||
https://hp.giesselink.com/emu48.htm</a>
|
||||
</blockquote></li>
|
||||
<li>HP49G
|
||||
<p>There's no ROM download program available so far. But you can
|
||||
create a ROM image with the
|
||||
<a href="https://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
|
||||
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
|
||||
ROM update file</a> for the HP49G calculator. I suggested to use
|
||||
<a href="http://www.hpcalc.org/details.php?id=3240">version 1.19-6</a>
|
||||
</p>
|
||||
<p>To create a HP49G ROM image file, start a Command Prompt while
|
||||
running Windows, and type:</p>
|
||||
<blockquote>UPD49ROM -f hp49119-6.flash ROM.49G</blockquote>
|
||||
<p>This will create a HP49G ROM image file with an empty User
|
||||
Port 2.</p></li>
|
||||
</ul>
|
||||
<h1><a name=s4>4. Installation</a></h1>
|
||||
<p>To install Emu48 you may use the installer package which contain,
|
||||
among the binaries, some HP48 KML scripts or just unzip the emulator
|
||||
|
@ -239,7 +263,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
<p>If you want other great scripts, visit Rechlin's great HP archive
|
||||
<a href="http://www.hpcalc.org/"></a></p>
|
||||
<p>If you are interested in writing new scripts, get the KML 2.0
|
||||
documentation from <a href="http://hp.giesselink.com/emu48.htm">the
|
||||
documentation from <a href="https://hp.giesselink.com/emu48.htm">the
|
||||
authors Emu48 page</a>.</p>
|
||||
<p>Having selected a script, press OK to start the emulator. In most
|
||||
cases, when Emu48 crash after pressing the OK button, you are using
|
||||
|
@ -462,7 +486,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
simulation. The data transfer to the printer simulator is done over UDP.
|
||||
In this section you can the define the IPv4 address and the port the
|
||||
printer simulator is listening. A suitable HP82240B printer simulation can
|
||||
be found <a href="http://hp.giesselink.com/hp82240b.htm">here</a>.</p>
|
||||
be found <a href="https://hp.giesselink.com/hp82240b.htm">here</a>.</p>
|
||||
<h4>8.6.3.3 Section Serial Ports</h4>
|
||||
<ul>
|
||||
<li><i>Wire</i>
|
||||
|
@ -651,7 +675,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
Cyrille de Brebisson of Hewlett-Packard.</p>
|
||||
<h1><a name=s15>15. License</a></h1>
|
||||
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
||||
Copyright (C) 2021 Christoph Gießelink</p>
|
||||
Copyright (C) 2022 Christoph Gießelink</p>
|
||||
<p>This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
|
|
|
@ -58,6 +58,11 @@ LINKS
|
|||
|
||||
CHANGES
|
||||
|
||||
Version 2.6 (2022-08-19)
|
||||
|
||||
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
|
||||
|
||||
|
||||
Version 2.5 (2022-03-03)
|
||||
|
||||
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "kml.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERSION "1.63+"
|
||||
#define VERSION "1.64+"
|
||||
|
||||
#ifdef _DEBUG
|
||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
||||
|
@ -681,7 +681,7 @@ static INT_PTR CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, WPARAM wPar
|
|||
|
||||
// set combobox parameter
|
||||
SetCommList(hDlg,szSerialWire,szSerialIr);
|
||||
if (bCommInit) // disable when port open
|
||||
if (CommIsOpen()) // disable when port open
|
||||
{
|
||||
EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE);
|
||||
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
|
||||
|
@ -768,7 +768,10 @@ static UINT SaveChanges(BOOL bAuto)
|
|||
if (GetSaveAsFilename())
|
||||
{
|
||||
if (SaveDocumentAs(szBufferFilename))
|
||||
{
|
||||
MruAdd(szBufferFilename);
|
||||
return IDYES;
|
||||
}
|
||||
else
|
||||
return IDCANCEL;
|
||||
}
|
||||
|
@ -776,6 +779,7 @@ static UINT SaveChanges(BOOL bAuto)
|
|||
}
|
||||
|
||||
SaveDocument();
|
||||
MruAdd(szCurrentFilename);
|
||||
return IDYES;
|
||||
}
|
||||
|
||||
|
@ -1056,25 +1060,32 @@ cancel:
|
|||
//
|
||||
static LRESULT OnFileMruOpen(UINT wID)
|
||||
{
|
||||
LPCTSTR lpszFilename;
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
|
||||
wID -= ID_FILE_MRU_FILE1; // zero based MRU index
|
||||
lpszFilename = MruFilename(wID); // full filename from MRU list
|
||||
if (lpszFilename == NULL) return 0; // MRU slot not filled
|
||||
|
||||
// full filename from MRU list
|
||||
MruFilename(wID,szFilename,ARRAYSIZEOF(szFilename));
|
||||
if (*szFilename == 0) return 0; // MRU slot not filled
|
||||
|
||||
if (bDocumentAvail)
|
||||
{
|
||||
SwitchToState(SM_INVALID);
|
||||
// saving may change MRU index and destroy lpszFilename pointer content
|
||||
if (IDCANCEL == SaveChanges(bAutoSave))
|
||||
goto cancel;
|
||||
}
|
||||
if (!OpenDocument(lpszFilename)) // document loading failed
|
||||
if (!OpenDocument(szFilename)) // document loading failed
|
||||
{
|
||||
MruRemove(wID); // entry not valid any more
|
||||
wID = MruID(szFilename); // get actual MRU ID after saving
|
||||
if (wID != (UINT) -1) // entry still in MRU list
|
||||
{
|
||||
MruRemove(wID); // entry not valid any more
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MruMoveTop(wID); // move entry to top of MRU list
|
||||
MruAdd(szFilename); // add entry to top of MRU list
|
||||
}
|
||||
cancel:
|
||||
if (pbyRom) SwitchToState(SM_RUN);
|
||||
|
|
|
@ -133,7 +133,8 @@ extern VOID MruAdd(LPCTSTR lpszEntry);
|
|||
extern VOID MruRemove(UINT nIndex);
|
||||
extern VOID MruMoveTop(UINT nIndex);
|
||||
extern UINT MruEntries(VOID);
|
||||
extern LPCTSTR MruFilename(UINT nIndex);
|
||||
extern UINT MruID(LPCTSTR lpszEntry);
|
||||
extern VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize);
|
||||
extern VOID MruUpdateMenu(HMENU hMenu);
|
||||
extern VOID MruWriteList(VOID);
|
||||
extern VOID MruReadList(VOID);
|
||||
|
@ -193,7 +194,6 @@ extern BOOL bRealSpeed;
|
|||
extern BOOL bKeySlow;
|
||||
extern BOOL bSoundSlow;
|
||||
extern UINT nOpcSlow;
|
||||
extern BOOL bCommInit;
|
||||
extern CHIPSET Chipset;
|
||||
extern TCHAR szSerialWire[16];
|
||||
extern TCHAR szSerialIr[16];
|
||||
|
@ -412,6 +412,7 @@ extern LPCTSTR RplGetName(DWORD dwAddr);
|
|||
extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr);
|
||||
|
||||
// Serial.c
|
||||
extern BOOL CommIsOpen(VOID);
|
||||
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
|
||||
extern VOID CommClose(VOID);
|
||||
extern VOID CommSetBaud(VOID);
|
||||
|
|
|
@ -22,7 +22,6 @@ BOOL bRealSpeed = FALSE;
|
|||
BOOL bKeySlow = FALSE; // slow down for key emulation
|
||||
BOOL bSoundSlow = FALSE; // slow down for sound emulation
|
||||
UINT nOpcSlow = 0; // no. of opcodes to slow down
|
||||
BOOL bCommInit = FALSE; // COM port not open
|
||||
|
||||
CHIPSET Chipset;
|
||||
|
||||
|
@ -353,16 +352,15 @@ static __inline VOID SetT2Cycles(VOID) // set device specific cpu cycles in int
|
|||
VOID CheckSerial(VOID)
|
||||
{
|
||||
// COM port closed and serial on
|
||||
if (bCommInit == FALSE && (Chipset.IORam[IOC] & SON) != 0)
|
||||
if (CommIsOpen() == FALSE && (Chipset.IORam[IOC] & SON) != 0)
|
||||
{
|
||||
bCommInit = CommOpen(szSerialWire,szSerialIr); // open COM ports
|
||||
CommOpen(szSerialWire,szSerialIr); // open COM ports
|
||||
}
|
||||
|
||||
// COM port opened and serial off
|
||||
if (bCommInit == TRUE && (Chipset.IORam[IOC] & SON) == 0)
|
||||
if (CommIsOpen() == TRUE && (Chipset.IORam[IOC] & SON) == 0)
|
||||
{
|
||||
CommClose(); // close COM port
|
||||
bCommInit = FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -551,7 +549,6 @@ loop:
|
|||
{
|
||||
OnToolMacroStop(); // close open keyboard macro handler
|
||||
CommClose(); // close COM port
|
||||
bCommInit = FALSE; // COM port not open
|
||||
nState = SM_INVALID; // in invalid state
|
||||
WaitForSingleObject(hEventShutdn,INFINITE);
|
||||
if (nNextState == SM_RETURN) // go into return state
|
||||
|
|
|
@ -1730,7 +1730,7 @@ typedef struct _BmpFile
|
|||
LPBYTE pbyFile; // buffer
|
||||
} BMPFILE, FAR *LPBMPFILE, *PBMPFILE;
|
||||
|
||||
static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
|
||||
static __inline WORD DibNumColors(__unaligned BITMAPINFOHEADER CONST *lpbi)
|
||||
{
|
||||
if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed;
|
||||
|
||||
|
@ -1738,7 +1738,7 @@ static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
|
|||
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
|
||||
}
|
||||
|
||||
static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
||||
static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi)
|
||||
{
|
||||
LOGPALETTE* pPal;
|
||||
HPALETTE hpal = NULL;
|
||||
|
@ -1747,12 +1747,9 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
BYTE green;
|
||||
BYTE blue;
|
||||
UINT i;
|
||||
RGBQUAD* pRgb;
|
||||
__unaligned RGBQUAD* pRgb;
|
||||
|
||||
if (!lpbi)
|
||||
return NULL;
|
||||
|
||||
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
||||
if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
||||
return NULL;
|
||||
|
||||
// Get a pointer to the color table and the number of colors in it
|
||||
|
@ -1816,22 +1813,19 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
|
||||
static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
|
||||
{
|
||||
LPBITMAPFILEHEADER pBmfh;
|
||||
LPBITMAPINFO pBmi;
|
||||
HBITMAP hBitmap;
|
||||
DWORD dwFileSize;
|
||||
DWORD dwFileSize;
|
||||
|
||||
hBitmap = NULL;
|
||||
HBITMAP hBitmap = NULL;
|
||||
|
||||
// size of bitmap header information
|
||||
// map memory to BITMAPFILEHEADER and BITMAPINFO
|
||||
const LPBITMAPFILEHEADER pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
|
||||
const __unaligned LPBITMAPINFO pBmi = (__unaligned LPBITMAPINFO) & pBmfh[1];
|
||||
|
||||
// size of bitmap header information & check for bitmap
|
||||
dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||
if (pBmp->dwFileSize < dwFileSize) return NULL;
|
||||
|
||||
// check for bitmap
|
||||
pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
|
||||
if (pBmfh->bfType != 0x4D42) return NULL; // "BM"
|
||||
|
||||
pBmi = (LPBITMAPINFO) (pBmp->pbyFile + sizeof(BITMAPFILEHEADER));
|
||||
if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER
|
||||
|| pBmfh->bfType != 0x4D42) // "BM"
|
||||
return NULL;
|
||||
|
||||
// size with color table
|
||||
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
|
@ -1852,7 +1846,7 @@ static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
|
|||
else
|
||||
{
|
||||
dwFileSize += WIDTHBYTES(pBmi->bmiHeader.biWidth * pBmi->bmiHeader.biBitCount)
|
||||
* labs(pBmi->bmiHeader.biHeight);
|
||||
* labs(pBmi->bmiHeader.biHeight);
|
||||
}
|
||||
if (pBmp->dwFileSize < dwFileSize) return NULL;
|
||||
|
||||
|
@ -2452,11 +2446,15 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
|
|||
if (hBitmap == NULL) goto quit;
|
||||
|
||||
pbySrc = pbyImage; // init source loop pointer
|
||||
pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap
|
||||
|
||||
// fill bottom up DIB pixel buffer with color information
|
||||
for (nHeight = bmi.bmiHeader.biHeight - 1; nHeight >= 0; --nHeight)
|
||||
for (nHeight = 0; nHeight < bmi.bmiHeader.biHeight; ++nHeight)
|
||||
{
|
||||
LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine;
|
||||
LPBYTE pbyLine;
|
||||
|
||||
pbyPixels -= lBytesPerLine; // begin of previous row
|
||||
pbyLine = pbyPixels; // row working copy
|
||||
|
||||
for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth)
|
||||
{
|
||||
|
@ -2465,8 +2463,6 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
|
|||
*pbyLine++ = pbySrc[0]; // red
|
||||
pbySrc += 3;
|
||||
}
|
||||
|
||||
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
|
||||
}
|
||||
|
||||
if (bPalette && hPalette == NULL)
|
||||
|
@ -2482,12 +2478,6 @@ quit:
|
|||
{
|
||||
free(pbyImage); // free PNG image data
|
||||
}
|
||||
|
||||
if (hBitmap != NULL && uError != 0) // creation failed
|
||||
{
|
||||
DeleteObject(hBitmap); // delete bitmap
|
||||
hBitmap = NULL;
|
||||
}
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
LodePNG version 20210627
|
||||
LodePNG version 20220717
|
||||
|
||||
Copyright (c) 2005-2021 Lode Vandevenne
|
||||
Copyright (c) 2005-2022 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
|
||||
|
@ -44,10 +44,10 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
|
|||
#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
|
||||
#endif /*_MSC_VER */
|
||||
|
||||
const char* LODEPNG_VERSION_STRING = "20210627";
|
||||
const char* LODEPNG_VERSION_STRING = "20220717";
|
||||
|
||||
/*
|
||||
This source file is built up in the following large parts. The code sections
|
||||
This source file is divided into the following large parts. The code sections
|
||||
with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
|
||||
-Tools for C and common code for PNG and Zlib
|
||||
-C Code for Zlib (huffman, deflate, ...)
|
||||
|
@ -267,7 +267,7 @@ typedef struct ucvector {
|
|||
} ucvector;
|
||||
|
||||
/*returns 1 if success, 0 if failure ==> nothing done*/
|
||||
static unsigned ucvector_resize(ucvector* p, size_t size) {
|
||||
static unsigned ucvector_reserve(ucvector* p, size_t size) {
|
||||
if(size > p->allocsize) {
|
||||
size_t newsize = size + (p->allocsize >> 1u);
|
||||
void* data = lodepng_realloc(p->data, newsize);
|
||||
|
@ -277,10 +277,15 @@ static unsigned ucvector_resize(ucvector* p, size_t size) {
|
|||
}
|
||||
else return 0; /*error: not enough memory*/
|
||||
}
|
||||
p->size = size;
|
||||
return 1; /*success*/
|
||||
}
|
||||
|
||||
/*returns 1 if success, 0 if failure ==> nothing done*/
|
||||
static unsigned ucvector_resize(ucvector* p, size_t size) {
|
||||
p->size = size;
|
||||
return ucvector_reserve(p, size);
|
||||
}
|
||||
|
||||
static ucvector ucvector_init(unsigned char* buffer, size_t size) {
|
||||
ucvector v;
|
||||
v.data = buffer;
|
||||
|
@ -480,71 +485,62 @@ static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned c
|
|||
ensureBits functions:
|
||||
Ensures the reader can at least read nbits bits in one or more readBits calls,
|
||||
safely even if not enough bits are available.
|
||||
Returns 1 if there are enough bits available, 0 if not.
|
||||
The nbits parameter is unused but is given for documentation purposes, error
|
||||
checking for amount of bits must be done beforehand.
|
||||
*/
|
||||
|
||||
/*See ensureBits documentation above. This one ensures exactly 1 bit */
|
||||
/*static unsigned ensureBits1(LodePNGBitReader* reader) {
|
||||
if(reader->bp >= reader->bitsize) return 0;
|
||||
reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u);
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
/*See ensureBits documentation above. This one ensures up to 9 bits */
|
||||
static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE void ensureBits9(LodePNGBitReader* reader, size_t nbits) {
|
||||
size_t start = reader->bp >> 3u;
|
||||
size_t size = reader->size;
|
||||
if(start + 1u < size) {
|
||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return 1;
|
||||
} else {
|
||||
reader->buffer = 0;
|
||||
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
|
||||
if(start + 0u < size) reader->buffer = reader->data[start + 0];
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return reader->bp + nbits <= reader->bitsize;
|
||||
}
|
||||
(void)nbits;
|
||||
}
|
||||
|
||||
/*See ensureBits documentation above. This one ensures up to 17 bits */
|
||||
static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE void ensureBits17(LodePNGBitReader* reader, size_t nbits) {
|
||||
size_t start = reader->bp >> 3u;
|
||||
size_t size = reader->size;
|
||||
if(start + 2u < size) {
|
||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
|
||||
((unsigned)reader->data[start + 2] << 16u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return 1;
|
||||
} else {
|
||||
reader->buffer = 0;
|
||||
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
|
||||
if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return reader->bp + nbits <= reader->bitsize;
|
||||
}
|
||||
(void)nbits;
|
||||
}
|
||||
|
||||
/*See ensureBits documentation above. This one ensures up to 25 bits */
|
||||
static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE void ensureBits25(LodePNGBitReader* reader, size_t nbits) {
|
||||
size_t start = reader->bp >> 3u;
|
||||
size_t size = reader->size;
|
||||
if(start + 3u < size) {
|
||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
|
||||
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return 1;
|
||||
} else {
|
||||
reader->buffer = 0;
|
||||
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
|
||||
if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
|
||||
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return reader->bp + nbits <= reader->bitsize;
|
||||
}
|
||||
(void)nbits;
|
||||
}
|
||||
|
||||
/*See ensureBits documentation above. This one ensures up to 32 bits */
|
||||
static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE void ensureBits32(LodePNGBitReader* reader, size_t nbits) {
|
||||
size_t start = reader->bp >> 3u;
|
||||
size_t size = reader->size;
|
||||
if(start + 4u < size) {
|
||||
|
@ -552,7 +548,6 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
|
|||
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));
|
||||
return 1;
|
||||
} else {
|
||||
reader->buffer = 0;
|
||||
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
|
||||
|
@ -560,48 +555,28 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
|
|||
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
|
||||
if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);
|
||||
reader->buffer >>= (reader->bp & 7u);
|
||||
return reader->bp + nbits <= reader->bitsize;
|
||||
}
|
||||
(void)nbits;
|
||||
}
|
||||
|
||||
/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */
|
||||
static unsigned peekBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE unsigned peekBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
/* The shift allows nbits to be only up to 31. */
|
||||
return reader->buffer & ((1u << nbits) - 1u);
|
||||
}
|
||||
|
||||
/* Must have enough bits available with ensureBits */
|
||||
static void advanceBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE void advanceBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
reader->buffer >>= nbits;
|
||||
reader->bp += nbits;
|
||||
}
|
||||
|
||||
/* Must have enough bits available with ensureBits */
|
||||
static unsigned readBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
static LODEPNG_INLINE unsigned readBits(LodePNGBitReader* reader, size_t nbits) {
|
||||
unsigned result = peekBits(reader, nbits);
|
||||
advanceBits(reader, nbits);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Public for testing only. steps and result must have numsteps values. */
|
||||
unsigned lode_png_test_bitreader(const unsigned char* data, size_t size,
|
||||
size_t numsteps, const size_t* steps, unsigned* result) {
|
||||
size_t i;
|
||||
LodePNGBitReader reader;
|
||||
unsigned error = LodePNGBitReader_init(&reader, data, size);
|
||||
if(error) return 0;
|
||||
for(i = 0; i < numsteps; i++) {
|
||||
size_t step = steps[i];
|
||||
unsigned ok;
|
||||
if(step > 25) ok = ensureBits32(&reader, step);
|
||||
else if(step > 17) ok = ensureBits25(&reader, step);
|
||||
else if(step > 9) ok = ensureBits17(&reader, step);
|
||||
else ok = ensureBits9(&reader, step);
|
||||
if(!ok) return 0;
|
||||
result[i] = readBits(&reader, step);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
||||
static unsigned reverseBits(unsigned bits, unsigned num) {
|
||||
|
@ -736,10 +711,11 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
|||
numpresent = 0;
|
||||
for(i = 0; i < tree->numcodes; ++i) {
|
||||
unsigned l = tree->lengths[i];
|
||||
unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
|
||||
/*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
|
||||
unsigned reverse = reverseBits(symbol, l);
|
||||
unsigned symbol, reverse;
|
||||
if(l == 0) continue;
|
||||
symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
|
||||
/*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
|
||||
reverse = reverseBits(symbol, l);
|
||||
numpresent++;
|
||||
|
||||
if(l <= FIRSTBITS) {
|
||||
|
@ -1103,11 +1079,10 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree*
|
|||
advanceBits(reader, l);
|
||||
return value;
|
||||
} else {
|
||||
unsigned index2;
|
||||
advanceBits(reader, FIRSTBITS);
|
||||
index2 = value + peekBits(reader, l - FIRSTBITS);
|
||||
advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);
|
||||
return codetree->table_value[index2];
|
||||
value += peekBits(reader, l - FIRSTBITS);
|
||||
advanceBits(reader, codetree->table_len[value] - FIRSTBITS);
|
||||
return codetree->table_value[value];
|
||||
}
|
||||
}
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
@ -1140,7 +1115,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
|
|||
unsigned* bitlen_cl = 0;
|
||||
HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
|
||||
|
||||
if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/
|
||||
if(reader->bitsize - reader->bp < 14) return 49; /*error: the bit pointer is or will go past the memory*/
|
||||
ensureBits17(reader, 14);
|
||||
|
||||
/*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
|
||||
HLIT = readBits(reader, 5) + 257;
|
||||
|
@ -1265,6 +1241,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
unsigned error = 0;
|
||||
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
|
||||
HuffmanTree tree_d; /*the huffman tree for distance codes*/
|
||||
const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */
|
||||
int done = 0;
|
||||
|
||||
if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/
|
||||
|
||||
HuffmanTree_init(&tree_ll);
|
||||
HuffmanTree_init(&tree_d);
|
||||
|
@ -1272,14 +1252,21 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
|
||||
else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);
|
||||
|
||||
while(!error) /*decode all symbols until end reached, breaks at end code*/ {
|
||||
|
||||
while(!error && !done) /*decode all symbols until end reached, breaks at end code*/ {
|
||||
/*code_ll is literal, length or end code*/
|
||||
unsigned code_ll;
|
||||
ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */
|
||||
/* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This
|
||||
appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/
|
||||
ensureBits32(reader, 30);
|
||||
code_ll = huffmanDecodeSymbol(reader, &tree_ll);
|
||||
if(code_ll <= 255) {
|
||||
/*slightly faster code path if multiple literals in a row*/
|
||||
out->data[out->size++] = (unsigned char)code_ll;
|
||||
code_ll = huffmanDecodeSymbol(reader, &tree_ll);
|
||||
}
|
||||
if(code_ll <= 255) /*literal symbol*/ {
|
||||
if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/);
|
||||
out->data[out->size - 1] = (unsigned char)code_ll;
|
||||
out->data[out->size++] = (unsigned char)code_ll;
|
||||
} else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
|
||||
unsigned code_d, distance;
|
||||
unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
|
||||
|
@ -1292,6 +1279,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
|
||||
if(numextrabits_l != 0) {
|
||||
/* bits already ensured above */
|
||||
ensureBits25(reader, 5);
|
||||
length += readBits(reader, numextrabits_l);
|
||||
}
|
||||
|
||||
|
@ -1319,7 +1307,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
|
||||
backward = start - distance;
|
||||
|
||||
if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/);
|
||||
out->size += length;
|
||||
if(distance < length) {
|
||||
size_t forward;
|
||||
lodepng_memcpy(out->data + start, out->data + backward, distance);
|
||||
|
@ -1331,10 +1319,13 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
lodepng_memcpy(out->data + start, out->data + backward, length);
|
||||
}
|
||||
} else if(code_ll == 256) {
|
||||
break; /*end code, break the loop*/
|
||||
done = 1; /*end code, finish the loop*/
|
||||
} else /*if(code_ll == INVALIDSYMBOL)*/ {
|
||||
ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
|
||||
}
|
||||
if(out->allocsize - out->size < reserved_size) {
|
||||
if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/
|
||||
}
|
||||
/*check if any of the ensureBits above went out of bounds*/
|
||||
if(reader->bp > reader->bitsize) {
|
||||
/*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
|
||||
|
@ -1377,8 +1368,11 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader,
|
|||
/*read the literal data: LEN bytes are now stored in the out buffer*/
|
||||
if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/
|
||||
|
||||
lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
|
||||
bytepos += LEN;
|
||||
/*out->data can be NULL (when LEN is zero), and arithmetics on NULL ptr is undefined*/
|
||||
if (LEN) {
|
||||
lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
|
||||
bytepos += LEN;
|
||||
}
|
||||
|
||||
reader->bp = bytepos << 3u;
|
||||
|
||||
|
@ -1396,7 +1390,8 @@ static unsigned lodepng_inflatev(ucvector* out,
|
|||
|
||||
while(!BFINAL) {
|
||||
unsigned BTYPE;
|
||||
if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/
|
||||
if(reader.bitsize - reader.bp < 3) return 52; /*error, bit pointer will jump past memory*/
|
||||
ensureBits9(&reader, 3);
|
||||
BFINAL = readBits(&reader, 1);
|
||||
BTYPE = readBits(&reader, 2);
|
||||
|
||||
|
@ -2378,7 +2373,7 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0,
|
|||
/* ////////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
|
||||
#ifndef LODEPNG_NO_COMPILE_CRC
|
||||
#ifdef LODEPNG_COMPILE_CRC
|
||||
/* CRC polynomial: 0xedb88320 */
|
||||
static unsigned lodepng_crc32_table[256] = {
|
||||
0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u,
|
||||
|
@ -2424,9 +2419,11 @@ unsigned lodepng_crc32(const unsigned char* data, size_t length) {
|
|||
}
|
||||
return r ^ 0xffffffffu;
|
||||
}
|
||||
#else /* !LODEPNG_NO_COMPILE_CRC */
|
||||
#else /* LODEPNG_COMPILE_CRC */
|
||||
/*in this case, the function is only declared here, and must be defined externally
|
||||
so that it will be linked in*/
|
||||
unsigned lodepng_crc32(const unsigned char* data, size_t length);
|
||||
#endif /* !LODEPNG_NO_COMPILE_CRC */
|
||||
#endif /* LODEPNG_COMPILE_CRC */
|
||||
|
||||
/* ////////////////////////////////////////////////////////////////////////// */
|
||||
/* / Reading and writing PNG color channel bits / */
|
||||
|
@ -2464,7 +2461,7 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream,
|
|||
/* ////////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
unsigned lodepng_chunk_length(const unsigned char* chunk) {
|
||||
return lodepng_read32bitInt(&chunk[0]);
|
||||
return lodepng_read32bitInt(chunk);
|
||||
}
|
||||
|
||||
void lodepng_chunk_type(char type[5], const unsigned char* chunk) {
|
||||
|
@ -2514,34 +2511,32 @@ void lodepng_chunk_generate_crc(unsigned char* chunk) {
|
|||
}
|
||||
|
||||
unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) {
|
||||
if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/
|
||||
size_t available_size = (size_t)(end - chunk);
|
||||
if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/
|
||||
if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47
|
||||
&& chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {
|
||||
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
|
||||
return chunk + 8;
|
||||
} else {
|
||||
size_t total_chunk_length;
|
||||
unsigned char* result;
|
||||
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
||||
result = chunk + total_chunk_length;
|
||||
if(result < chunk) return end; /*pointer overflow*/
|
||||
return result;
|
||||
if(total_chunk_length > available_size) return end; /*outside of range*/
|
||||
return chunk + total_chunk_length;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) {
|
||||
if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/
|
||||
size_t available_size = (size_t)(end - chunk);
|
||||
if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/
|
||||
if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47
|
||||
&& chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {
|
||||
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
|
||||
return chunk + 8;
|
||||
} else {
|
||||
size_t total_chunk_length;
|
||||
const unsigned char* result;
|
||||
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
||||
result = chunk + total_chunk_length;
|
||||
if(result < chunk) return end; /*pointer overflow*/
|
||||
return result;
|
||||
if(total_chunk_length > available_size) return end; /*outside of range*/
|
||||
return chunk + total_chunk_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2586,7 +2581,7 @@ the data is at chunk + 8. To finalize chunk, add the data, then use
|
|||
lodepng_chunk_generate_crc */
|
||||
static unsigned lodepng_chunk_init(unsigned char** chunk,
|
||||
ucvector* out,
|
||||
unsigned length, const char* type) {
|
||||
size_t length, const char* type) {
|
||||
size_t new_length = out->size;
|
||||
if(lodepng_addofl(new_length, length, &new_length)) return 77;
|
||||
if(lodepng_addofl(new_length, 12, &new_length)) return 77;
|
||||
|
@ -2594,7 +2589,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk,
|
|||
*chunk = out->data + new_length - length - 12u;
|
||||
|
||||
/*1: length*/
|
||||
lodepng_set32bitInt(*chunk, length);
|
||||
lodepng_set32bitInt(*chunk, (unsigned)length);
|
||||
|
||||
/*2: chunk name (4 letters)*/
|
||||
lodepng_memcpy(*chunk + 4, type, 4);
|
||||
|
@ -2604,7 +2599,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk,
|
|||
|
||||
/* like lodepng_chunk_create but with custom allocsize */
|
||||
static unsigned lodepng_chunk_createv(ucvector* out,
|
||||
unsigned length, const char* type, const unsigned char* data) {
|
||||
size_t length, const char* type, const unsigned char* data) {
|
||||
unsigned char* chunk;
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type));
|
||||
|
||||
|
@ -3051,6 +3046,9 @@ void lodepng_info_init(LodePNGInfo* info) {
|
|||
info->iccp_name = NULL;
|
||||
info->iccp_profile = NULL;
|
||||
|
||||
info->sbit_defined = 0;
|
||||
info->sbit_r = info->sbit_g = info->sbit_b = info->sbit_a = 0;
|
||||
|
||||
LodePNGUnknownChunks_init(info);
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
}
|
||||
|
@ -3945,7 +3943,7 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out,
|
|||
if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize
|
||||
&& mode_in->bitdepth == mode_out->bitdepth) {
|
||||
/*If input should have same palette colors, keep original to preserve its order and prevent conversion*/
|
||||
lodepng_color_mode_cleanup(mode_out);
|
||||
lodepng_color_mode_cleanup(mode_out); /*clears palette, keeps the above set colortype and bitdepth fields as-is*/
|
||||
lodepng_color_mode_copy(mode_out, mode_in);
|
||||
}
|
||||
} else /*8-bit or 16-bit per channel*/ {
|
||||
|
@ -4135,10 +4133,9 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
too much code. Whether this speeds up anything depends on compiler and settings. */
|
||||
if(bytewidth >= 4) {
|
||||
for(; i + 3 < length; i += 4, j += 4) {
|
||||
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
|
||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
|
||||
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
|
||||
unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3];
|
||||
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3];
|
||||
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3];
|
||||
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3];
|
||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
|
||||
|
@ -4146,17 +4143,18 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
}
|
||||
} else if(bytewidth >= 3) {
|
||||
for(; i + 2 < length; i += 3, j += 3) {
|
||||
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
|
||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
|
||||
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
|
||||
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2];
|
||||
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2];
|
||||
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2];
|
||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
|
||||
}
|
||||
} else if(bytewidth >= 2) {
|
||||
for(; i + 1 < length; i += 2, j += 2) {
|
||||
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
|
||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
|
||||
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1];
|
||||
unsigned char r0 = recon[j + 0], r1 = recon[j + 1];
|
||||
unsigned char p0 = precon[i + 0], p1 = precon[i + 1];
|
||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||
}
|
||||
|
@ -4732,6 +4730,47 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings*
|
|||
if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/
|
||||
return error;
|
||||
}
|
||||
|
||||
/*significant bits chunk (sBIT)*/
|
||||
static unsigned readChunk_sBIT(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {
|
||||
unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
|
||||
if(info->color.colortype == LCT_GREY) {
|
||||
/*error: this chunk must be 1 bytes for grayscale image*/
|
||||
if(chunkLength != 1) return 114;
|
||||
if(data[0] == 0 || data[0] > bitdepth) return 115;
|
||||
info->sbit_defined = 1;
|
||||
info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
|
||||
} else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
|
||||
/*error: this chunk must be 3 bytes for RGB and palette image*/
|
||||
if(chunkLength != 3) return 114;
|
||||
if(data[0] == 0 || data[1] == 0 || data[2] == 0) return 115;
|
||||
if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth) return 115;
|
||||
info->sbit_defined = 1;
|
||||
info->sbit_r = data[0];
|
||||
info->sbit_g = data[1];
|
||||
info->sbit_b = data[2];
|
||||
} else if(info->color.colortype == LCT_GREY_ALPHA) {
|
||||
/*error: this chunk must be 2 byte for grayscale with alpha image*/
|
||||
if(chunkLength != 2) return 114;
|
||||
if(data[0] == 0 || data[1] == 0) return 115;
|
||||
if(data[0] > bitdepth || data[1] > bitdepth) return 115;
|
||||
info->sbit_defined = 1;
|
||||
info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
|
||||
info->sbit_a = data[1];
|
||||
} else if(info->color.colortype == LCT_RGBA) {
|
||||
/*error: this chunk must be 4 bytes for grayscale image*/
|
||||
if(chunkLength != 4) return 114;
|
||||
if(data[0] == 0 || data[1] == 0 || data[2] == 0 || data[3] == 0) return 115;
|
||||
if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth || data[3] > bitdepth) return 115;
|
||||
info->sbit_defined = 1;
|
||||
info->sbit_r = data[0];
|
||||
info->sbit_g = data[1];
|
||||
info->sbit_b = data[2];
|
||||
info->sbit_a = data[3];
|
||||
}
|
||||
|
||||
return 0; /* OK */
|
||||
}
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
|
||||
unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
||||
|
@ -4746,7 +4785,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
|||
chunkLength = lodepng_chunk_length(chunk);
|
||||
if(chunkLength > 2147483647) return 63;
|
||||
data = lodepng_chunk_data_const(chunk);
|
||||
if(data + chunkLength + 4 > in + insize) return 30;
|
||||
if(chunkLength + 12 > insize - pos) return 30;
|
||||
|
||||
if(lodepng_chunk_type_equals(chunk, "PLTE")) {
|
||||
error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
|
||||
|
@ -4773,6 +4812,8 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
|||
error = readChunk_sRGB(&state->info_png, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||
error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "sBIT")) {
|
||||
error = readChunk_sBIT(&state->info_png, data, chunkLength);
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
} else {
|
||||
/* unhandled chunk is ok (is not an error) */
|
||||
|
@ -4791,7 +4832,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
LodePNGState* state,
|
||||
const unsigned char* in, size_t insize) {
|
||||
unsigned char IEND = 0;
|
||||
const unsigned char* chunk;
|
||||
const unsigned char* chunk; /*points to beginning of next chunk*/
|
||||
unsigned char* idat; /*the data from idat chunks, zlib compressed*/
|
||||
size_t idatsize = 0;
|
||||
unsigned char* scanlines = 0;
|
||||
|
@ -4827,14 +4868,15 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
while(!IEND && !state->error) {
|
||||
unsigned chunkLength;
|
||||
const unsigned char* data; /*the data in the chunk*/
|
||||
size_t pos = (size_t)(chunk - in);
|
||||
|
||||
/*error: size of the in buffer too small to contain next chunk*/
|
||||
if((size_t)((chunk - in) + 12) > insize || chunk < in) {
|
||||
/*error: next chunk out of bounds of the in buffer*/
|
||||
if(chunk < in || pos + 12 > insize) {
|
||||
if(state->decoder.ignore_end) break; /*other errors may still happen though*/
|
||||
CERROR_BREAK(state->error, 30);
|
||||
}
|
||||
|
||||
/*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
|
||||
/*length of the data of the chunk, excluding the 12 bytes for length, chunk type and CRC*/
|
||||
chunkLength = lodepng_chunk_length(chunk);
|
||||
/*error: chunk length larger than the max PNG chunk size*/
|
||||
if(chunkLength > 2147483647) {
|
||||
|
@ -4842,8 +4884,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
CERROR_BREAK(state->error, 63);
|
||||
}
|
||||
|
||||
if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) {
|
||||
CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
|
||||
if(pos + (size_t)chunkLength + 12 > insize || pos + (size_t)chunkLength + 12 < pos) {
|
||||
CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk (or int overflow)*/
|
||||
}
|
||||
|
||||
data = lodepng_chunk_data_const(chunk);
|
||||
|
@ -4917,6 +4959,9 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||
state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
||||
if(state->error) break;
|
||||
} else if(lodepng_chunk_type_equals(chunk, "sBIT")) {
|
||||
state->error = readChunk_sBIT(&state->info_png, data, chunkLength);
|
||||
if(state->error) break;
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
} else /*it's not an implemented chunk type, so ignore it: skip over the data*/ {
|
||||
/*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
|
||||
|
@ -5152,7 +5197,11 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) {
|
|||
unsigned char* chunk;
|
||||
size_t i, j = 8;
|
||||
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)info->palettesize * 3, "PLTE"));
|
||||
if(info->palettesize == 0 || info->palettesize > 256) {
|
||||
return 68; /*invalid palette size, it is only allowed to be 1-256*/
|
||||
}
|
||||
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE"));
|
||||
|
||||
for(i = 0; i != info->palettesize; ++i) {
|
||||
/*add all channels except alpha channel*/
|
||||
|
@ -5176,7 +5225,7 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {
|
|||
--amount;
|
||||
}
|
||||
if(amount) {
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)amount, "tRNS"));
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS"));
|
||||
/*add the alpha channel values from the palette*/
|
||||
for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3];
|
||||
}
|
||||
|
@ -5210,7 +5259,7 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d
|
|||
|
||||
error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings);
|
||||
if(!error) {
|
||||
error = lodepng_chunk_createv(out, (unsigned)zlibsize, "IDAT", zlib);
|
||||
error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib);
|
||||
}
|
||||
lodepng_free(zlib);
|
||||
return error;
|
||||
|
@ -5227,7 +5276,7 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te
|
|||
size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring);
|
||||
size_t size = keysize + 1 + textsize;
|
||||
if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)size, "tEXt"));
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt"));
|
||||
lodepng_memcpy(chunk + 8, keyword, keysize);
|
||||
chunk[8 + keysize] = 0; /*null termination char*/
|
||||
lodepng_memcpy(chunk + 9 + keysize, textstring, textsize);
|
||||
|
@ -5249,7 +5298,7 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te
|
|||
(const unsigned char*)textstring, textsize, zlibsettings);
|
||||
if(!error) {
|
||||
size_t size = keysize + 2 + compressedsize;
|
||||
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "zTXt");
|
||||
error = lodepng_chunk_init(&chunk, out, size, "zTXt");
|
||||
}
|
||||
if(!error) {
|
||||
lodepng_memcpy(chunk + 8, keyword, keysize);
|
||||
|
@ -5280,7 +5329,7 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw
|
|||
}
|
||||
if(!error) {
|
||||
size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize);
|
||||
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iTXt");
|
||||
error = lodepng_chunk_init(&chunk, out, size, "iTXt");
|
||||
}
|
||||
if(!error) {
|
||||
size_t pos = 8;
|
||||
|
@ -5393,7 +5442,7 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
|
|||
info->iccp_profile, info->iccp_profile_size, zlibsettings);
|
||||
if(!error) {
|
||||
size_t size = keysize + 2 + compressedsize;
|
||||
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iCCP");
|
||||
error = lodepng_chunk_init(&chunk, out, size, "iCCP");
|
||||
}
|
||||
if(!error) {
|
||||
lodepng_memcpy(chunk + 8, info->iccp_name, keysize);
|
||||
|
@ -5407,6 +5456,42 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
|
|||
return error;
|
||||
}
|
||||
|
||||
static unsigned addChunk_sBIT(ucvector* out, const LodePNGInfo* info) {
|
||||
unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
|
||||
unsigned char* chunk = 0;
|
||||
if(info->color.colortype == LCT_GREY) {
|
||||
if(info->sbit_r == 0 || info->sbit_r > bitdepth) return 115;
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "sBIT"));
|
||||
chunk[8] = info->sbit_r;
|
||||
} else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
|
||||
if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0) return 115;
|
||||
if(info->sbit_r > bitdepth || info->sbit_g > bitdepth || info->sbit_b > bitdepth) return 115;
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 3, "sBIT"));
|
||||
chunk[8] = info->sbit_r;
|
||||
chunk[9] = info->sbit_g;
|
||||
chunk[10] = info->sbit_b;
|
||||
} else if(info->color.colortype == LCT_GREY_ALPHA) {
|
||||
if(info->sbit_r == 0 || info->sbit_a == 0) return 115;
|
||||
if(info->sbit_r > bitdepth || info->sbit_a > bitdepth) return 115;
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "sBIT"));
|
||||
chunk[8] = info->sbit_r;
|
||||
chunk[9] = info->sbit_a;
|
||||
} else if(info->color.colortype == LCT_RGBA) {
|
||||
if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0 || info->sbit_a == 0 ||
|
||||
info->sbit_r > bitdepth || info->sbit_g > bitdepth ||
|
||||
info->sbit_b > bitdepth || info->sbit_a > bitdepth) {
|
||||
return 115;
|
||||
}
|
||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "sBIT"));
|
||||
chunk[8] = info->sbit_r;
|
||||
chunk[9] = info->sbit_g;
|
||||
chunk[10] = info->sbit_b;
|
||||
chunk[11] = info->sbit_a;
|
||||
}
|
||||
if(chunk) lodepng_chunk_generate_crc(chunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
|
||||
static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
|
||||
|
@ -5852,8 +5937,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
ucvector outv = ucvector_init(NULL, 0);
|
||||
LodePNGInfo info;
|
||||
const LodePNGInfo* info_png = &state->info_png;
|
||||
LodePNGColorMode auto_color;
|
||||
|
||||
lodepng_info_init(&info);
|
||||
lodepng_color_mode_init(&auto_color);
|
||||
|
||||
/*provide some proper output values if error will happen*/
|
||||
*out = 0;
|
||||
|
@ -5863,6 +5950,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
/*check input values validity*/
|
||||
if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette)
|
||||
&& (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) {
|
||||
/*this error is returned even if auto_convert is enabled and thus encoder could
|
||||
generate the palette by itself: while allowing this could be possible in theory,
|
||||
it may complicate the code or edge cases, and always requiring to give a palette
|
||||
when setting this color type is a simpler contract*/
|
||||
state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -5883,6 +5974,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
lodepng_info_copy(&info, &state->info_png);
|
||||
if(state->encoder.auto_convert) {
|
||||
LodePNGColorStats stats;
|
||||
unsigned allow_convert = 1;
|
||||
lodepng_color_stats_init(&stats);
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
if(info_png->iccp_defined &&
|
||||
|
@ -5904,23 +5996,85 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
/*the background chunk's color must be taken into account as well*/
|
||||
unsigned r = 0, g = 0, b = 0;
|
||||
LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16);
|
||||
lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color);
|
||||
lodepng_convert_rgb(&r, &g, &b,
|
||||
info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color);
|
||||
state->error = lodepng_color_stats_add(&stats, r, g, b, 65535);
|
||||
if(state->error) goto cleanup;
|
||||
}
|
||||
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
|
||||
state->error = auto_choose_color(&info.color, &state->info_raw, &stats);
|
||||
state->error = auto_choose_color(&auto_color, &state->info_raw, &stats);
|
||||
if(state->error) goto cleanup;
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
/*also convert the background chunk*/
|
||||
if(info_png->background_defined) {
|
||||
if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b,
|
||||
info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) {
|
||||
state->error = 104;
|
||||
goto cleanup;
|
||||
if(info_png->sbit_defined) {
|
||||
/*if sbit is defined, due to strict requirements of which sbit values can be present for which color modes,
|
||||
auto_convert can't be done in many cases. However, do support a few cases here.
|
||||
TODO: more conversions may be possible, and it may also be possible to get a more appropriate color type out of
|
||||
auto_choose_color if knowledge about sbit is used beforehand
|
||||
*/
|
||||
unsigned sbit_max = LODEPNG_MAX(LODEPNG_MAX(LODEPNG_MAX(info_png->sbit_r, info_png->sbit_g),
|
||||
info_png->sbit_b), info_png->sbit_a);
|
||||
unsigned equal = (!info_png->sbit_g || info_png->sbit_g == info_png->sbit_r)
|
||||
&& (!info_png->sbit_b || info_png->sbit_b == info_png->sbit_r)
|
||||
&& (!info_png->sbit_a || info_png->sbit_a == info_png->sbit_r);
|
||||
allow_convert = 0;
|
||||
if(info.color.colortype == LCT_PALETTE &&
|
||||
auto_color.colortype == LCT_PALETTE) {
|
||||
/* input and output are palette, and in this case it may happen that palette data is
|
||||
expected to be copied from info_raw into the info_png */
|
||||
allow_convert = 1;
|
||||
}
|
||||
/*going from 8-bit RGB to palette (or 16-bit as long as sbit_max <= 8) is possible
|
||||
since both are 8-bit RGB for sBIT's purposes*/
|
||||
if(info.color.colortype == LCT_RGB &&
|
||||
auto_color.colortype == LCT_PALETTE && sbit_max <= 8) {
|
||||
allow_convert = 1;
|
||||
}
|
||||
/*going from 8-bit RGBA to palette is also ok but only if sbit_a is exactly 8*/
|
||||
if(info.color.colortype == LCT_RGBA && auto_color.colortype == LCT_PALETTE &&
|
||||
info_png->sbit_a == 8 && sbit_max <= 8) {
|
||||
allow_convert = 1;
|
||||
}
|
||||
/*going from 16-bit RGB(A) to 8-bit RGB(A) is ok if all sbit values are <= 8*/
|
||||
if((info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA) && info.color.bitdepth == 16 &&
|
||||
auto_color.colortype == info.color.colortype && auto_color.bitdepth == 8 &&
|
||||
sbit_max <= 8) {
|
||||
allow_convert = 1;
|
||||
}
|
||||
/*going to less channels is ok if all bit values are equal (all possible values in sbit,
|
||||
as well as the chosen bitdepth of the result). Due to how auto_convert works,
|
||||
we already know that auto_color.colortype has less than or equal amount of channels than
|
||||
info.colortype. Palette is not used here. This conversion is not allowed if
|
||||
info_png->sbit_r < auto_color.bitdepth, because specifically for alpha, non-presence of
|
||||
an sbit value heavily implies that alpha's bit depth is equal to the PNG bit depth (rather
|
||||
than the bit depths set in the r, g and b sbit values, by how the PNG specification describes
|
||||
handling tRNS chunk case with sBIT), so be conservative here about ignoring user input.*/
|
||||
if(info.color.colortype != LCT_PALETTE && auto_color.colortype != LCT_PALETTE &&
|
||||
equal && info_png->sbit_r == auto_color.bitdepth) {
|
||||
allow_convert = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(state->encoder.force_palette) {
|
||||
if(info.color.colortype != LCT_GREY && info.color.colortype != LCT_GREY_ALPHA &&
|
||||
(auto_color.colortype == LCT_GREY || auto_color.colortype == LCT_GREY_ALPHA)) {
|
||||
/*user speficially forced a PLTE palette, so cannot convert to grayscale types because
|
||||
the PNG specification only allows writing a suggested palette in PLTE for truecolor types*/
|
||||
allow_convert = 0;
|
||||
}
|
||||
}
|
||||
if(allow_convert) {
|
||||
lodepng_color_mode_copy(&info.color, &auto_color);
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
/*also convert the background chunk*/
|
||||
if(info_png->background_defined) {
|
||||
if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b,
|
||||
info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) {
|
||||
state->error = 104;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
|
||||
}
|
||||
}
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
if(info_png->iccp_defined) {
|
||||
|
@ -5991,6 +6145,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
state->error = addChunk_cHRM(&outv, &info);
|
||||
if(state->error) goto cleanup;
|
||||
}
|
||||
if(info_png->sbit_defined) {
|
||||
state->error = addChunk_sBIT(&outv, &info);
|
||||
if(state->error) goto cleanup;
|
||||
}
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
/*PLTE*/
|
||||
if(info.color.colortype == LCT_PALETTE) {
|
||||
|
@ -6097,6 +6255,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
|||
cleanup:
|
||||
lodepng_info_cleanup(&info);
|
||||
lodepng_free(data);
|
||||
lodepng_color_mode_cleanup(&auto_color);
|
||||
|
||||
/*instead of cleaning the vector up, give it to the output*/
|
||||
*out = outv.data;
|
||||
|
@ -6291,6 +6450,8 @@ const char* lodepng_error_text(unsigned code) {
|
|||
/*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents
|
||||
unreasonable memory consumption when decoding due to impossibly large ICC profile*/
|
||||
case 113: return "ICC profile unreasonably large";
|
||||
case 114: return "sBIT chunk has wrong size for the color type of the image";
|
||||
case 115: return "sBIT value out of range";
|
||||
}
|
||||
return "unknown error code";
|
||||
}
|
||||
|
@ -6327,7 +6488,7 @@ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, si
|
|||
size_t buffersize = 0;
|
||||
unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
|
||||
if(buffer) {
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
lodepng_free(buffer);
|
||||
}
|
||||
return error;
|
||||
|
@ -6346,7 +6507,7 @@ unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size
|
|||
size_t buffersize = 0;
|
||||
unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
|
||||
if(buffer) {
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
lodepng_free(buffer);
|
||||
}
|
||||
return error;
|
||||
|
@ -6391,7 +6552,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const
|
|||
state.info_raw.colortype = colortype;
|
||||
state.info_raw.bitdepth = bitdepth;
|
||||
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
}
|
||||
lodepng_free(buffer);
|
||||
return error;
|
||||
|
@ -6409,7 +6570,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
|||
unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
|
||||
if(buffer && !error) {
|
||||
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
}
|
||||
lodepng_free(buffer);
|
||||
return error;
|
||||
|
@ -6441,7 +6602,7 @@ unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsign
|
|||
size_t buffersize;
|
||||
unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
|
||||
if(buffer) {
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
lodepng_free(buffer);
|
||||
}
|
||||
return error;
|
||||
|
@ -6461,7 +6622,7 @@ unsigned encode(std::vector<unsigned char>& out,
|
|||
size_t buffersize;
|
||||
unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
|
||||
if(buffer) {
|
||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
||||
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||
lodepng_free(buffer);
|
||||
}
|
||||
return error;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
LodePNG version 20210627
|
||||
LodePNG version 20220717
|
||||
|
||||
Copyright (c) 2005-2021 Lode Vandevenne
|
||||
Copyright (c) 2005-2022 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
|
||||
|
@ -35,43 +35,50 @@ The following #defines are used to create code sections. They can be disabled
|
|||
to disable code sections, which can give faster compile time and smaller binary.
|
||||
The "NO_COMPILE" defines are designed to be used to pass as defines to the
|
||||
compiler command to disable them without modifying this header, e.g.
|
||||
-DLODEPNG_NO_COMPILE_ZLIB for gcc.
|
||||
In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
|
||||
allow implementing a custom lodepng_crc32.
|
||||
-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang.
|
||||
*/
|
||||
/*deflate & zlib. If disabled, you must specify alternative zlib functions in
|
||||
the custom_zlib field of the compress and decompress settings*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ZLIB
|
||||
/*pass -DLODEPNG_NO_COMPILE_ZLIB to the compiler to disable this, or comment out LODEPNG_COMPILE_ZLIB below*/
|
||||
#define LODEPNG_COMPILE_ZLIB
|
||||
#endif
|
||||
|
||||
/*png encoder and png decoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_PNG
|
||||
/*pass -DLODEPNG_NO_COMPILE_PNG to the compiler to disable this, or comment out LODEPNG_COMPILE_PNG below*/
|
||||
#define LODEPNG_COMPILE_PNG
|
||||
#endif
|
||||
|
||||
/*deflate&zlib decoder and png decoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_DECODER
|
||||
/*pass -DLODEPNG_NO_COMPILE_DECODER to the compiler to disable this, or comment out LODEPNG_COMPILE_DECODER below*/
|
||||
#define LODEPNG_COMPILE_DECODER
|
||||
#endif
|
||||
|
||||
/*deflate&zlib encoder and png encoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ENCODER
|
||||
/*pass -DLODEPNG_NO_COMPILE_ENCODER to the compiler to disable this, or comment out LODEPNG_COMPILE_ENCODER below*/
|
||||
#define LODEPNG_COMPILE_ENCODER
|
||||
#endif
|
||||
|
||||
/*the optional built in harddisk file loading and saving functions*/
|
||||
#ifndef LODEPNG_NO_COMPILE_DISK
|
||||
/*pass -DLODEPNG_NO_COMPILE_DISK to the compiler to disable this, or comment out LODEPNG_COMPILE_DISK below*/
|
||||
#define LODEPNG_COMPILE_DISK
|
||||
#endif
|
||||
|
||||
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
|
||||
/*pass -DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS to the compiler to disable this,
|
||||
or comment out LODEPNG_COMPILE_ANCILLARY_CHUNKS below*/
|
||||
#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
#endif
|
||||
|
||||
/*ability to convert error numerical codes to English text string*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
|
||||
/*pass -DLODEPNG_NO_COMPILE_ERROR_TEXT to the compiler to disable this,
|
||||
or comment out LODEPNG_COMPILE_ERROR_TEXT below*/
|
||||
#define LODEPNG_COMPILE_ERROR_TEXT
|
||||
#endif
|
||||
|
||||
|
@ -79,12 +86,24 @@ the custom_zlib field of the compress and decompress settings*/
|
|||
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
|
||||
source files with custom allocators.*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ALLOCATORS
|
||||
/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones,
|
||||
or comment out LODEPNG_COMPILE_ALLOCATORS below*/
|
||||
#define LODEPNG_COMPILE_ALLOCATORS
|
||||
#endif
|
||||
|
||||
/*Disable built-in CRC function, in that case a custom implementation of
|
||||
lodepng_crc32 must be defined externally so that it can be linked in.*/
|
||||
#ifndef LODEPNG_NO_COMPILE_CRC
|
||||
/*pass -DLODEPNG_NO_COMPILE_CRC to the compiler to disable the built-in one,
|
||||
or comment out LODEPNG_COMPILE_CRC below*/
|
||||
#define LODEPNG_COMPILE_CRC
|
||||
#endif
|
||||
|
||||
/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
|
||||
#ifdef __cplusplus
|
||||
#ifndef LODEPNG_NO_COMPILE_CPP
|
||||
/*pass -DLODEPNG_NO_COMPILE_CPP to the compiler to disable C++ (not needed if a C-only compiler),
|
||||
or comment out LODEPNG_COMPILE_CPP below*/
|
||||
#define LODEPNG_COMPILE_CPP
|
||||
#endif
|
||||
#endif
|
||||
|
@ -374,8 +393,10 @@ typedef struct LodePNGColorMode {
|
|||
|
||||
The alpha channels must be set as well, set them to 255 for opaque images.
|
||||
|
||||
When decoding, by default you can ignore this palette, since LodePNG already
|
||||
fills the palette colors in the pixels of the raw RGBA output.
|
||||
When decoding, with the default settings you can ignore this palette, since
|
||||
LodePNG already fills the palette colors in the pixels of the raw RGBA output,
|
||||
but when decoding to the original PNG color mode it is needed to reconstruct
|
||||
the colors.
|
||||
|
||||
The palette is only supported for color type 3.
|
||||
*/
|
||||
|
@ -465,10 +486,12 @@ typedef struct LodePNGInfo {
|
|||
with values truncated to the bit depth in the unsigned integer.
|
||||
|
||||
For grayscale and palette PNGs, the value is stored in background_r. The values
|
||||
in background_g and background_b are then unused.
|
||||
in background_g and background_b are then unused. The decoder will set them
|
||||
equal to background_r, the encoder ignores them in this case.
|
||||
|
||||
So when decoding, you may get these in a different color mode than the one you requested
|
||||
for the raw pixels.
|
||||
When decoding, you may get these in a different color mode than the one you requested
|
||||
for the raw pixels: the colortype and bitdepth defined by info_png.color, that is the
|
||||
ones defined in the header of the PNG image, are used.
|
||||
|
||||
When encoding with auto_convert, you must use the color model defined in info_png.color for
|
||||
these values. The encoder normally ignores info_png.color when auto_convert is on, but will
|
||||
|
@ -535,7 +558,7 @@ typedef struct LodePNGInfo {
|
|||
unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
|
||||
|
||||
/*
|
||||
Color profile related chunks: gAMA, cHRM, sRGB, iCPP
|
||||
Color profile related chunks: gAMA, cHRM, sRGB, iCPP, sBIT
|
||||
|
||||
LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color
|
||||
profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please
|
||||
|
@ -598,6 +621,45 @@ typedef struct LodePNGInfo {
|
|||
unsigned char* iccp_profile;
|
||||
unsigned iccp_profile_size; /* The size of iccp_profile in bytes */
|
||||
|
||||
/*
|
||||
sBIT chunk: significant bits. Optional metadata, only set this if needed.
|
||||
|
||||
If defined, these values give the bit depth of the original data. Since PNG only stores 1, 2, 4, 8 or 16-bit
|
||||
per channel data, the significant bits value can be used to indicate the original encoded data has another
|
||||
sample depth, such as 10 or 12.
|
||||
|
||||
Encoders using this value, when storing the pixel data, should use the most significant bits
|
||||
of the data to store the original bits, and use a good sample depth scaling method such as
|
||||
"left bit replication" to fill in the least significant bits, rather than fill zeroes.
|
||||
|
||||
Decoders using this value, if able to work with data that's e.g. 10-bit or 12-bit, should right
|
||||
shift the data to go back to the original bit depth, but decoders are also allowed to ignore
|
||||
sbit and work e.g. with the 8-bit or 16-bit data from the PNG directly, since thanks
|
||||
to the encoder contract, the values encoded in PNG are in valid range for the PNG bit depth.
|
||||
|
||||
For grayscale images, sbit_g and sbit_b are not used, and for images that don't use color
|
||||
type RGBA or grayscale+alpha, sbit_a is not used (it's not used even for palette images with
|
||||
translucent palette values, or images with color key). The values that are used must be
|
||||
greater than zero and smaller than or equal to the PNG bit depth.
|
||||
|
||||
The color type from the header in the PNG image defines these used and unused fields: if
|
||||
decoding with a color mode conversion, such as always decoding to RGBA, this metadata still
|
||||
only uses the color type of the original PNG, and may e.g. lack the alpha channel info
|
||||
if the PNG was RGB. When encoding with auto_convert (as well as without), also always the
|
||||
color model defined in info_png.color determines this.
|
||||
|
||||
NOTE: enabling sbit can hurt compression, because the encoder can then not always use
|
||||
auto_convert to choose a more optimal color mode for the data, because the PNG format has
|
||||
strict requirements for the allowed sbit values in combination with color modes.
|
||||
For example, setting these fields to 10-bit will force the encoder to keep using a 16-bit per channel
|
||||
color mode, even if the pixel data would in fact fit in a more efficient 8-bit mode.
|
||||
*/
|
||||
unsigned sbit_defined; /*is significant bits given? if not, the values below are unused*/
|
||||
unsigned sbit_r; /*red or gray component of significant bits*/
|
||||
unsigned sbit_g; /*green component of significant bits*/
|
||||
unsigned sbit_b; /*blue component of significant bits*/
|
||||
unsigned sbit_a; /*alpha component of significant bits*/
|
||||
|
||||
/* End of color profile related chunks */
|
||||
|
||||
|
||||
|
@ -770,7 +832,11 @@ typedef struct LodePNGEncoderSettings {
|
|||
const unsigned char* predefined_filters;
|
||||
|
||||
/*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
|
||||
If colortype is 3, PLTE is _always_ created.*/
|
||||
If colortype is 3, PLTE is always created. If color type is explicitely set
|
||||
to a grayscale type (1 or 4), this is not done and is ignored. If enabling this,
|
||||
a palette must be present in the info_png.
|
||||
NOTE: enabling this may worsen compression if auto_convert is used to choose
|
||||
optimal color mode, because it cannot use grayscale color modes in this case*/
|
||||
unsigned force_palette;
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
/*add LodePNG identifier and version as a text chunk, for debugging*/
|
||||
|
@ -824,8 +890,8 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h,
|
|||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
||||
/*
|
||||
Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it
|
||||
read in the state. Returns error code on failure.
|
||||
Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect)
|
||||
of the PNG file and outputs what it read in the state. Returns error code on failure.
|
||||
Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const
|
||||
to find the desired chunk type, and if non null use lodepng_inspect_chunk (with
|
||||
chunk_pointer - start_of_file as pos).
|
||||
|
@ -1103,7 +1169,7 @@ TODO:
|
|||
[.] check compatibility with various compilers - done but needs to be redone for every newer version
|
||||
[X] converting color to 16-bit per channel types
|
||||
[X] support color profile chunk types (but never let them touch RGB values by default)
|
||||
[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST)
|
||||
[ ] support all public PNG chunk types (almost done except sPLT and hIST)
|
||||
[ ] make sure encoder generates no chunks with size > (2^31)-1
|
||||
[ ] partial decoding (stream processing)
|
||||
[X] let the "isFullyOpaque" function check color keys and transparent palettes too
|
||||
|
@ -1230,18 +1296,16 @@ The following features are supported by the decoder:
|
|||
gAMA: RGB gamma correction
|
||||
iCCP: ICC color profile
|
||||
sRGB: rendering intent
|
||||
sBIT: significant bits
|
||||
|
||||
1.2. features not supported
|
||||
---------------------------
|
||||
|
||||
The following features are _not_ supported:
|
||||
The following features are not (yet) supported:
|
||||
|
||||
*) some features needed to make a conformant PNG-Editor might be still missing.
|
||||
*) partial loading/stream processing. All data must be available and is processed in one call.
|
||||
*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG:
|
||||
sBIT
|
||||
hIST
|
||||
sPLT
|
||||
*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks
|
||||
|
||||
|
||||
2. C and C++ version
|
||||
|
@ -1845,6 +1909,8 @@ symbol.
|
|||
Not all changes are listed here, the commit history in github lists more:
|
||||
https://github.com/lvandeve/lodepng
|
||||
|
||||
*) 13 jun 2022: added support for the sBIT chunk.
|
||||
*) 09 jan 2022: minor decoder speed improvements.
|
||||
*) 27 jun 2021: added warnings that file reading/writing functions don't support
|
||||
wide-character filenames (support for this is not planned, opening files is
|
||||
not the core part of PNG decoding/decoding and is platform dependent).
|
||||
|
@ -2015,5 +2081,5 @@ Domain: gmail dot com.
|
|||
Account: lode dot vandevenne.
|
||||
|
||||
|
||||
Copyright (c) 2005-2021 Lode Vandevenne
|
||||
Copyright (c) 2005-2022 Lode Vandevenne
|
||||
*/
|
||||
|
|
|
@ -1161,8 +1161,11 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate)
|
|||
case 0x15: // RBR MSB
|
||||
if (bUpdate)
|
||||
{
|
||||
Chipset.IORam[RCS] &= ~RBF;
|
||||
*a = Chipset.IORam[d]; // return RBR value
|
||||
if (d==0x15) // reading RBR MSB
|
||||
{
|
||||
Chipset.IORam[RCS] &= ~RBF; // clear Receive Buffer Full flag
|
||||
}
|
||||
UpdateUSRQ(); // update USRQ
|
||||
rbr_acc = TRUE; // search for new RBR value
|
||||
#if defined DEBUG_SERIAL
|
||||
|
@ -1614,13 +1617,13 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
|
|||
// 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only)
|
||||
// 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event
|
||||
case 0x1A:
|
||||
// COM port open and EIRU bit changed
|
||||
if (bCommInit && ((c^Chipset.IORam[d]) & EIRU) != 0)
|
||||
// EIRU bit changed
|
||||
if (((c^Chipset.IORam[d]) & EIRU) != 0)
|
||||
{
|
||||
// save new value for COM open
|
||||
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
||||
// reopen COM port with new setting
|
||||
bCommInit = CommOpen(szSerialWire,szSerialIr);
|
||||
CommOpen(szSerialWire,szSerialIr);
|
||||
}
|
||||
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
||||
#if defined DEBUG_SERIAL
|
||||
|
|
|
@ -84,7 +84,7 @@ VOID MruCleanup(VOID)
|
|||
{
|
||||
for (i = 0; i < nEntry; ++i) // cleanup each entry
|
||||
{
|
||||
if (ppszFiles[i] != NULL)
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
free(ppszFiles[i]); // cleanup entry
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
|
|||
for (i = 0; i < nEntry; ++i)
|
||||
{
|
||||
// already in table -> quit
|
||||
if ( ppszFiles[i] != NULL
|
||||
if ( ppszFiles[i] != NULL // valid entry
|
||||
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
|
||||
{
|
||||
MruMoveTop(i); // move to top and update menu
|
||||
|
@ -120,7 +120,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
|
|||
}
|
||||
|
||||
i = nEntry - 1; // last index
|
||||
if (ppszFiles[i] != NULL)
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
free(ppszFiles[i]); // free oldest entry
|
||||
|
||||
for (; i > 0; --i) // move old entries 1 line down
|
||||
|
@ -173,16 +173,43 @@ UINT MruEntries(VOID)
|
|||
return nEntry;
|
||||
}
|
||||
|
||||
LPCTSTR MruFilename(UINT nIndex)
|
||||
UINT MruID(LPCTSTR lpszEntry)
|
||||
{
|
||||
LPCTSTR lpszName = _T("");
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
LPTSTR lpFilePart;
|
||||
UINT i;
|
||||
|
||||
if (ppszFiles != NULL) // MRU initialized
|
||||
{
|
||||
_ASSERT(nEntry > 0); // must have entries
|
||||
|
||||
// get full path name
|
||||
GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);
|
||||
|
||||
// look if entry is already in table
|
||||
for (i = 0; i < nEntry; ++i)
|
||||
{
|
||||
if ( ppszFiles[i] != NULL // valid entry
|
||||
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
|
||||
{
|
||||
return i; // return ID
|
||||
}
|
||||
}
|
||||
}
|
||||
return (UINT) -1; // not found
|
||||
}
|
||||
|
||||
VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize)
|
||||
{
|
||||
*szFilename = 0; // not found
|
||||
|
||||
// MRU initialized and index inside valid range
|
||||
if (ppszFiles != NULL && nIndex < nEntry)
|
||||
{
|
||||
lpszName = ppszFiles[nIndex];
|
||||
_ASSERT(ppszFiles[nIndex] != NULL); // valid entry
|
||||
lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize);
|
||||
}
|
||||
return lpszName;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID MruUpdateMenu(HMENU hMenu)
|
||||
|
@ -312,7 +339,7 @@ VOID MruWriteList(VOID)
|
|||
{
|
||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||
wsprintf(szItemname,_T("File%d"),i+1);
|
||||
if (ppszFiles[i] != NULL)
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
{
|
||||
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
|
||||
}
|
||||
|
@ -338,7 +365,7 @@ VOID MruReadList(VOID)
|
|||
wsprintf(szItemname,_T("File%d"),i+1);
|
||||
ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));
|
||||
|
||||
if (ppszFiles[i] != NULL) // already filled
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
{
|
||||
free(ppszFiles[i]); // free entry
|
||||
ppszFiles[i] = NULL; // clear last line
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#endif
|
||||
|
||||
#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier
|
||||
#define __unaligned
|
||||
#define SetWindowLongPtr SetWindowLong
|
||||
#define GetWindowLongPtr GetWindowLong
|
||||
#define SetClassLongPtr SetClassLong
|
||||
|
|
|
@ -93,6 +93,11 @@ static DWORD WINAPI EventThread(LPVOID pParam)
|
|||
UNREFERENCED_PARAMETER(pParam);
|
||||
}
|
||||
|
||||
BOOL CommIsOpen(VOID)
|
||||
{
|
||||
return hComm != NULL; // have COM port handle
|
||||
}
|
||||
|
||||
BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
|
||||
{
|
||||
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
|
||||
|
@ -353,7 +358,7 @@ VOID CommReceive(VOID)
|
|||
// reject reading if com port is closed and not whole operation
|
||||
if (hComm && dwBytesRead == 0L) // com port open and buffer empty
|
||||
{
|
||||
if (ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
|
||||
if (ReadFile(hComm,cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
|
||||
dwBytesRead = 0L;
|
||||
else // bytes received
|
||||
nRp = 0; // reset read pointer
|
||||
|
|
|
@ -42,6 +42,7 @@ BOOL settingsPort2en;
|
|||
BOOL settingsPort2wr;
|
||||
BOOL soundAvailable = FALSE;
|
||||
BOOL soundEnabled = FALSE;
|
||||
BOOL serialPortSlowDown = FALSE;
|
||||
|
||||
|
||||
|
||||
|
@ -1005,6 +1006,9 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onViewCopy(JNIEnv
|
|||
AndroidBitmap_unlockPixels(env, bitmapScreen);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onStackCopyVisible(JNIEnv *env, jobject thisz) {
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onStackCopy(JNIEnv *env, jobject thisz) {
|
||||
OnStackCopy();
|
||||
}
|
||||
|
@ -1297,18 +1301,20 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setConfiguration(J
|
|||
const char * newSerialWire = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||
BOOL serialWireChanged = _tcscmp(szSerialWire, newSerialWire) != 0;
|
||||
_tcsncpy(szSerialWire, newSerialWire, sizeof(szSerialWire));
|
||||
if(bCommInit && serialWireChanged) {
|
||||
if(CommIsOpen() && serialWireChanged) {
|
||||
// Not the right thread, but it seems to work.
|
||||
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
||||
CommOpen(szSerialWire, szSerialIr);
|
||||
}
|
||||
} else if(_tcscmp(_T("settings_serial_ports_ir"), configKey) == 0) {
|
||||
const char * newSerialIr = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||
BOOL serialIrChanged = _tcscmp(szSerialIr, newSerialIr) != 0;
|
||||
_tcsncpy(szSerialIr, newSerialIr, sizeof(szSerialIr));
|
||||
if(bCommInit && serialIrChanged) {
|
||||
if(CommIsOpen() && serialIrChanged) {
|
||||
// Not the right thread, but it seems to work.
|
||||
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
||||
CommOpen(szSerialWire, szSerialIr);
|
||||
}
|
||||
} else if(_tcscmp(_T("settings_serial_slowdown"), configKey) == 0) {
|
||||
serialPortSlowDown = (BOOL)intValue1;
|
||||
}
|
||||
|
||||
if(configKey)
|
||||
|
|
|
@ -341,7 +341,8 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,LPDWO
|
|||
SERIAL_LOGD("WriteFile(hFile: %p, lpBuffer: 0x%08x, nNumberOfBytesToWrite: %d) -> %d bytes\n%s", hFile, lpBuffer, nNumberOfBytesToWrite, writenByteCount, hexAsciiDump);
|
||||
free(hexAsciiDump);
|
||||
#endif
|
||||
Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
||||
if(serialPortSlowDown)
|
||||
Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
||||
if(lpNumberOfBytesWritten)
|
||||
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
||||
return writenByteCount >= 0;
|
||||
|
@ -3484,3 +3485,9 @@ int win32_select(int __fd_count, fd_set* __read_fds, fd_set* __write_fds, fd_set
|
|||
}
|
||||
return select(__fd_count, __read_fds, __write_fds, __exception_fds, __timeout);
|
||||
}
|
||||
|
||||
int win32_ioctlsocket(SOCKET s, long cmd, u_long FAR * argp) {
|
||||
//TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
#include <sys/select.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/log.h>
|
||||
|
@ -66,6 +67,7 @@
|
|||
#endif
|
||||
|
||||
#define _MSC_VER 1914
|
||||
#define __unaligned
|
||||
#define GetWindowLongPtr GetWindowLong
|
||||
|
||||
|
||||
|
@ -1370,6 +1372,7 @@ extern BOOL SetCommState(HANDLE hFile, LPDCB lpDCB);
|
|||
extern BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);
|
||||
extern BOOL SetCommBreak(HANDLE hFile);
|
||||
extern BOOL ClearCommBreak(HANDLE hFile);
|
||||
extern BOOL serialPortSlowDown;
|
||||
|
||||
// TCP
|
||||
|
||||
|
@ -1378,6 +1381,7 @@ typedef int SOCKET;
|
|||
#define SOCKET_ERROR (-1)
|
||||
|
||||
#define WSAEINTR 10004L
|
||||
#define WSAEWOULDBLOCK 10035L
|
||||
extern int WSAGetLastError();
|
||||
|
||||
typedef struct WSAData {
|
||||
|
|
|
@ -66,6 +66,7 @@ public class NativeLib {
|
|||
public static native String[] getObjectsToSave();
|
||||
public static native int onObjectSave(String filename, boolean[] objectsToSaveItemChecked);
|
||||
public static native void onViewCopy(Bitmap bitmapScreen);
|
||||
public static native void onStackCopyVisible();
|
||||
public static native void onStackCopy();
|
||||
public static native void onStackPaste();
|
||||
public static native void onViewReset();
|
||||
|
|
|
@ -370,6 +370,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
OnViewCopyFullscreen();
|
||||
} else if (id == R.id.nav_copy_screen) {
|
||||
OnViewCopy();
|
||||
// } else if (id == R.id.nav_copy_stack_visible) {
|
||||
// OnStackCopyVisible();
|
||||
} else if (id == R.id.nav_copy_stack) {
|
||||
OnStackCopy();
|
||||
} else if (id == R.id.nav_paste_stack) {
|
||||
|
@ -446,6 +448,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
menu.findItem(R.id.nav_load_object).setEnabled(uRun && bObjectEnable);
|
||||
menu.findItem(R.id.nav_save_object).setEnabled(uRun && bObjectEnable);
|
||||
menu.findItem(R.id.nav_copy_screen).setEnabled(uRun);
|
||||
// menu.findItem(R.id.nav_copy_stack_visible).setEnabled(uRun && bBertOrSaca); // HDW_SACA || HDW_BERT)
|
||||
menu.findItem(R.id.nav_copy_stack).setEnabled(uRun && bStackCEnable);
|
||||
menu.findItem(R.id.nav_paste_stack).setEnabled(uRun && bStackPEnable);
|
||||
menu.findItem(R.id.nav_reset_calculator).setEnabled(uRun);
|
||||
|
@ -929,6 +932,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
showAlert(e.getMessage());
|
||||
}
|
||||
}
|
||||
private void OnStackCopyVisible() {
|
||||
NativeLib.onStackCopyVisible();
|
||||
}
|
||||
private void OnStackCopy() {
|
||||
NativeLib.onStackCopy();
|
||||
}
|
||||
|
@ -987,7 +993,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
} else
|
||||
kmlScriptsForCurrentModel = kmlScripts;
|
||||
|
||||
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && (getPackageName().contains("org.emulator.forty.eight") || getPackageName().contains("org.emulator.forty.two"));
|
||||
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && (
|
||||
getPackageName().contains("org.emulator.forty.eight")
|
||||
|| getPackageName().contains("org.emulator.forty.two")
|
||||
|| getPackageName().contains("org.emulator.twenty.eight"));
|
||||
int lastIndex = kmlScriptsForCurrentModel.size();
|
||||
String[] kmlScriptTitles = new String[lastIndex + (showDefaultKMLScriptFolderItem ? 2 : 1)];
|
||||
for (int i = 0; i < kmlScriptsForCurrentModel.size(); i++)
|
||||
|
@ -2201,7 +2210,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
"settings_printer_model", "settings_macro",
|
||||
"settings_kml", "settings_port1", "settings_port2",
|
||||
"settings_flash_port2",
|
||||
"settings_serial_ports_wire", "settings_serial_ports_ir" };
|
||||
"settings_serial_ports_wire", "settings_serial_ports_ir", "settings_serial_slowdown" };
|
||||
for (String settingKey : settingKeys)
|
||||
updateFromPreferences(settingKey, false);
|
||||
} else {
|
||||
|
@ -2331,6 +2340,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
||||
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
||||
break;
|
||||
case "settings_serial_slowdown":
|
||||
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
android:id="@+id/nav_copy_screen"
|
||||
android:icon="@drawable/ic_menu_share"
|
||||
android:title="@string/nav_copy_screen" />
|
||||
<!--<item
|
||||
android:id="@+id/nav_copy_stack_visible"
|
||||
android:icon="@drawable/ic_filter_none_black_24dp"
|
||||
android:title="@string/nav_copy_stack_visible" /> -->
|
||||
<item
|
||||
android:id="@+id/nav_copy_stack"
|
||||
android:icon="@drawable/ic_filter_none_black_24dp"
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<string name="nav_save_object">Save Object...</string>
|
||||
<string name="nav_copy_screen">Copy Screen</string>
|
||||
<string name="nav_copy_fullscreen">Copy Fullscreen</string>
|
||||
<string name="nav_copy_stack_visible">Copy Visible Stack</string>
|
||||
<string name="nav_copy_stack">Copy Stack</string>
|
||||
<string name="nav_recents">Recent</string>
|
||||
<string name="nav_edit">Edit</string>
|
||||
|
@ -223,5 +224,6 @@
|
|||
<string name="settings_category_serial_ports_title">Serial Ports (Please allow USB OTG)</string>
|
||||
<string name="settings_serial_ports_wire_title">Wire</string>
|
||||
<string name="settings_serial_ports_ir_title">Infrared (2400 baud only)</string>
|
||||
<string name="settings_serial_slowdown">Slowdown transmission (prevent errors with 9600 baud)</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<PreferenceScreen xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="@string/settings_category_general_title">
|
||||
|
@ -187,6 +188,11 @@
|
|||
android:title="@string/settings_serial_ports_ir_title"
|
||||
android:summary=""
|
||||
/>
|
||||
<!-- <SwitchPreference-->
|
||||
<!-- android:defaultValue="false"-->
|
||||
<!-- android:key="settings_serial_slowdown"-->
|
||||
<!-- android:title="@string/settings_serial_slowdown"-->
|
||||
<!-- />-->
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.2'
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
|
|
Loading…
Reference in a new issue