Allow to choose the splashscreen.

The author is taken from the Artist exif metadata of the jpeg
using 'KLab exif' lib for that (exiv2 has an incompatible licence and libexif need autoconf for compiling)
This commit is contained in:
remi durand 2021-04-27 04:25:54 +02:00
parent 8504793a7e
commit b6a98377ae
13 changed files with 4021 additions and 12 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 136 KiB

View File

@ -25,6 +25,8 @@ if (SLIC3R_GUI)
add_subdirectory(imgui) add_subdirectory(imgui)
add_subdirectory(hidapi) add_subdirectory(hidapi)
include_directories(hidapi/include) include_directories(hidapi/include)
add_subdirectory(exif)
include_directories(exif/include)
if(WIN32) if(WIN32)
message(STATUS "WXWIN environment set to: $ENV{WXWIN}") message(STATUS "WXWIN environment set to: $ENV{WXWIN}")

6
src/exif/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 2.5)
include_directories(include)
add_library(exif STATIC exif.c)

201
src/exif/COPYING Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

94
src/exif/README Normal file
View File

@ -0,0 +1,94 @@
"exif.c" is a simple implementation to access the Exif segment in a JPEG file.
It easily enables you to get the value of the IFD tag field with such code:
TagNodeInfo *tag = getTagInfo(ifdArray, IFD_EXIF, TAG_DateTimeOriginal);
printf("DateTimeOriginal = [%s]\n", tag->byteData);
-> DateTimeOriginal = [2013:09:01 09:49:00]
See "sample_main.c" and "exif.h" for details.
exif.c only uses standard C library functions. So, it will be usable in many environments.
It has been tested in the following environments.
- Windows XP 32bit + 32bit Visual C++
- Windows 7 64bit + 64bit Visual C++
- Redhat Linux 32bit + 32bit gcc
- Mac OS X 64bit + 64bit gcc
building with gcc:
gcc -o exif sample_main.c exif.c
building with Microsoft Visual C++:
cl.exe /o exif sample_main.c exif.c
The following output is the result of the sample program.
---------------------------------------------------------------------------
$ exif test.jpg
[test.jpg] createIfdTableArray: result=4
{0TH IFD}
- Make: [Apple]
- Model: [iPod touch]
- Orientation: 1
- XResolution: 72/1
- YResolution: 72/1
- ResolutionUnit: 2
- Software: [6.1.4]
- DateTime: [2013:09:01 09:49:00]
- YCbCrPositioning: 1
- ExifIFDPointer: 206
- GPSInfoIFDPointer: 576
{EXIF IFD}
- ExposureTime: 1/30
- FNumber: 12/5
- ExposureProgram: 2
- PhotographicSensitivity: 400
- ExifVersion: 0 2 2 1
- DateTimeOriginal: [2013:09:01 09:49:00]
- DateTimeDigitized: [2013:09:01 09:49:00]
- ComponentsConfiguration: 0x01 0x02 0x03 0x00
- ShutterSpeedValue: 4035/821
- ApertureValue: 4845/1918
- BrightnessValue: 2234/1113
- MeteringMode: 5
- Flash: 32
- FocalLength: 77/20
- FlashPixVersion: 0 1 0 0
- ColorSpace: 1
- PixelXDimension: 960
- PixelYDimension: 720
- SensingMethod: 2
- ExposureMode: 0
- WhiteBalance: 0
- FocalLengthIn35mmFormat: 32
- SceneCaptureType: 0
{GPS IFD}
- GPSLatitudeRef: [S]
- GPSLatitude: 69/1 17/100 0/1
- GPSLongitudeRef: [E]
- GPSLongitude: 39/1 35/100 0/1
- GPSAltitudeRef: 0
- GPSAltitude: 6151/470
- GPSTimeStamp: 0/1 48/1 3921/100
{1ST IFD}
- Compression: 6
- XResolution: 72/1
- YResolution: 72/1
- ResolutionUnit: 2
- JPEGInterchangeFormat: 840
- JPEGInterchangeFormatLength: 8648
0th IFD : Model = [iPod touch]
Exif IFD : DateTimeOriginal = [2013:09:01 09:49:00]
GPS IFD : GPSLatitude = 69/1 17/100 0/1
removeExifSegmentFromJPEGFile: result=1
---------------------------------------------------------------------------
http://dsas.blog.klab.org/archives/52123322.html (Japanese only)
Copyright (C) 2013 KLab Inc.

2889
src/exif/exif.c Normal file

File diff suppressed because it is too large Load Diff

751
src/exif/include/exif.h Normal file
View File

@ -0,0 +1,751 @@
/*
* Copyright (C) 2013 KLab Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EXIF_H_
#define EXIF_H_
#ifdef _WIN32
#define EXIF_API_EXPORT __declspec(dllexport)
#define EXIF_API_CALL
#else
#define EXIF_API_EXPORT /**< API export macro */
#define EXIF_API_CALL /**< API call macro */
#endif
#define EXIF_API_EXPORT_CALL EXIF_API_EXPORT EXIF_API_CALL /**< API export and call macro*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* setVerbose()
*
* Verbose output on/off
*
* parameters
* [in] v : 1=on 0=off
*/
void EXIF_API_EXPORT_CALL exif_setVerbose(int);
#ifdef _DEBUG
#ifdef _MSC_VER
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
//#define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif
#include <stdint.h>
/**
* Typical Usage:
*
* The following code describes how to get "Model" Tag's data
* from 0th IFD in "test.jpg".
*
* // Parse the JPEG header and create the pointer array of the IFD tables
* int result;
* void **ifdArray = createIfdTableArray("test.jpg", *result);
* switch (result) {
* case 0:
* :
* }
* if (!ifdArray) {
* return;
* }
*
* // Get the TagNodeInfo that matches the IFD_TYPE & TagId
* TagNodeInfo *tag = getTagInfo(ifdArray, IFD_0TH, TAG_Model);
*
* if (tag) {
* if (!tag->error) {
* printf("Model=[%s]\n", tag->byteData); // TYPE_ASCII
* }
* freeTagInfo(tag);
* }
*
* freeIfdTableArray(ifdArray);
* return;
*
*/
// IFD Type
typedef enum {
IFD_UNKNOWN = 0,
IFD_0TH,
IFD_1ST,
IFD_EXIF,
IFD_GPS,
IFD_IO,
IFD_MPF
} EXIF_IFD_TYPE;
// Tag Type
typedef enum {
TYPE_BYTE = 1,
TYPE_ASCII,
TYPE_SHORT,
TYPE_LONG,
TYPE_RATIONAL,
TYPE_SBYTE,
TYPE_UNDEFINED,
TYPE_SSHORT,
TYPE_SLONG,
TYPE_SRATIONAL
} EXIF_IFD_TAG_TYPE;
// Tag info structure
typedef struct _exif_tagNodeInfo ExifTagNodeInfo;
struct _exif_tagNodeInfo {
uint16_t tagId; // tag ID (e.g. TAG_Model = 0x0110)
uint16_t type; // data Type (e.g. TYPE_ASCII = 2)
unsigned int count; // count of the data
unsigned int* numData; // numeric data array
uint8_t* byteData; // byte data array
uint16_t error; // 0: no error 1: parse error
};
typedef struct _exif_image_dir_ent
{
uint32_t ImageFlags;
uint32_t ImageLength;
uint32_t ImageStart;
uint16_t Image1EntryNum;
uint16_t Image2EntryNum;
} EXIF_IMAGE_DIR_ENT;
/**
* Note:
*
* [Type = TYPE_BYTE, TYPE_SHORT, TYPE_LONG,
* TYPE_SBYTE, TYPE_SSHORT, TYPE_SLONG]
* 'numData' holds numeric values.
* numData[0] to numData[count-1] is accessible.
*
* [Type = TYPE_RATIONAL, TYPE_SRATIONAL]
* 'numData' holds numeric values.
* numData[0] to numData[count*2-1] is accessible.
*
* [Type = TYPE_ASCII]
* 'byteData' holds ascii string data.
* 'count' means the whole length of string with '\0' terminator.
*
* [Type = TYPE_UNDEFINED]
* 'byteData' holds byte data.
* byteData[0] to byteData[count-1] is accessible.
*
* If the original tag field holds the wrong value, the 'error' flag
* will be set to 1. In such cases, both 'numData' and 'byteData'
* might have set to NULL. So, the flag should be checked first.
*/
// error status
#define EXIF_ERR_READ_FILE -1
#define EXIF_ERR_WRITE_FILE -2
#define EXIF_ERR_INVALID_JPEG -3
#define EXIF_ERR_INVALID_APP1HEADER -4
#define EXIF_ERR_INVALID_IFD -5
#define EXIF_ERR_INVALID_ID -6
#define EXIF_ERR_INVALID_TYPE -7
#define EXIF_ERR_INVALID_COUNT -8
#define EXIF_ERR_INVALID_POINTER -9
#define EXIF_ERR_NOT_EXIST -10
#define EXIF_ERR_ALREADY_EXIST -11
#define EXIF_ERR_UNKNOWN -12
#define EXIF_ERR_MEMALLOC -13
// public funtions
/**
* removeExifSegmentFromJPEGFile()
*
* Remove the Exif segment from a JPEG file
*
* parameters
* [in] inJPEGFileName : original JPEG file
* [in] outJPGEFileName : output JPEG file
*
* return
* 1: OK
* 0: the Exif segment is not found
* -n: error
* ERR_READ_FILE
* ERR_WRITE_FILE
* ERR_INVALID_JPEG
* ERR_INVALID_APP1HEADER
*/
int EXIF_API_EXPORT_CALL exif_removeExifSegmentFromJPEGFile(const char* inJPEGFileName,
const char* outJPGEFileName);
/**
* fillIfdTableArray()
*
* Parse the JPEG header and fill in the IFD table
*
* parameters
* [in] JPEGFileName : target JPEG file
* [out] ifdArray[32] : array of IfdTable pointers
*
* return
* n: number of IFD tables
* 0: the Exif segment is not found
* -n: error
* ERR_READ_FILE
* ERR_INVALID_JPEG
* ERR_INVALID_APP1HEADER
* ERR_INVALID_IFD
*/
int EXIF_API_EXPORT_CALL exif_fillIfdTableArray(const char* JPEGFileName, void* ifdArray[32]);
/**
* createIfdTableArray()
*
* Parse the JPEG header and create the pointer array of the IFD tables
*
* parameters
* [in] JPEGFileName : target JPEG file
* [out] result : result status value
* n: number of IFD tables
* 0: the Exif segment is not found
* -n: error
* ERR_READ_FILE
* ERR_INVALID_JPEG
* ERR_INVALID_APP1HEADER
* ERR_INVALID_IFD
*
* return
* NULL: error or no Exif segment
* !NULL: pointer array of the IFD tables
*/
void EXIF_API_EXPORT ** EXIF_API_CALL exif_createIfdTableArray(const char* JPEGFileName, int* result);
/**
* freeIfdTables()
*
* Free the pointer array of the IFD tables
*
* parameters
* [in] ifdArray : address of the IFD array
*/
void EXIF_API_EXPORT_CALL exif_freeIfdTables(void* ifdArray[32]);
/**
* freeIfdTableArray()
*
* Free the pointer array of the IFD tables
*
* parameters
* [in] ifdArray : address of the IFD array
*/
void EXIF_API_EXPORT_CALL exif_freeIfdTableArray(void** ifdArray);
/**
* getIfdType()
*
* Returns the type of the IFD
*
* parameters
* [in] ifd: target IFD
*
* return
* IFD TYPE value
*/
EXIF_IFD_TYPE EXIF_API_EXPORT_CALL exif_getIfdType(void* ifd);
/**
* dumpIfdTable()
*
* Dump the IFD table
*
* parameters
* [in] ifd: target IFD
*/
void EXIF_API_EXPORT_CALL exif_dumpIfdTable(void* ifd);
/**
* dumpIfdTableArray()
*
* Dump the array of the IFD tables
*
* parameters
* [in] ifdArray : address of the IFD array
*/
void EXIF_API_EXPORT_CALL exif_dumpIfdTableArray(void** ifdArray);
/**
* getTagInfo()
*
* Get the TagNodeInfo that matches the IFD_TYPE & TagId
*
* parameters
* [in] ifdArray : address of the IFD array
* [in] ifdType : target IFD TYPE
* [in] tagId : target tag ID
*
* return
* NULL: tag is not found
* !NULL: address of the TagNodeInfo structure
*/
ExifTagNodeInfo EXIF_API_EXPORT * EXIF_API_CALL exif_getTagInfo(void** ifdArray,
EXIF_IFD_TYPE ifdType,
uint16_t tagId);
/**
* getTagInfoFromIfd()
*
* Get the TagNodeInfo that matches the TagId
*
* parameters
* [in] ifd : target IFD
* [in] tagId : target tag ID
*
* return
* NULL: tag is not found
* !NULL: address of the TagNodeInfo structure
*/
ExifTagNodeInfo EXIF_API_EXPORT * EXIF_API_CALL exif_getTagInfoFromIfd(void* ifd, uint16_t tagId);
/**
* freeTagInfo()
*
* Free the TagNodeInfo allocated by getTagInfo() or getTagInfoFromIfd()
*
* parameters
* [in] tag : target TagNodeInfo
*/
void EXIF_API_EXPORT_CALL exif_freeTagInfo(void* tag);
/**
* queryTagNodeIsExist()
*
* Query if the specified tag node is exist in the IFD tables
*
* parameters
* [in] ifdTableArray: address of the IFD tables array
* [in] ifdType : target IFD type
* [in] tagId : target tag ID
*
* return
* 0: not exist
* 1: exist
*/
int EXIF_API_EXPORT_CALL exif_queryTagNodeIsExist(void** ifdTableArray,
EXIF_IFD_TYPE ifdType,
uint16_t tagId);
/**
* createTagInfo()
*
* Create new TagNodeInfo block
*
* parameters
* [in] tagId: id of the tag
* [in] type: type of the tag
* [in] count: data count of the tag
* [out] pResult : error status
* 0: OK
* -n: error
* ERR_INVALID_TYPE
* ERR_INVALID_COUNT
* ERR_MEMALLOC
*
* return
* NULL: error
* !NULL: address of the newly created TagNodeInfo
*/
ExifTagNodeInfo EXIF_API_EXPORT * EXIF_API_CALL exif_createTagInfo(uint16_t tagId,
uint16_t type,
unsigned int count,
int* pResult);
/**
* removeIfdTableFromIfdTableArray()
*
* Remove the IFD table from the ifdTableArray
*
* parameters
* [in] ifdTableArray: address of the IFD tables array
* [in] ifdType : target IFD type
*
* return
* n: number of the removed IFD tables
*/
int EXIF_API_EXPORT_CALL exif_removeIfdTableFromIfdTableArray(void** ifdTableArray, EXIF_IFD_TYPE ifdType);
/**
* insertIfdTableToIfdTableArray()
*
* Insert new IFD table to the ifdTableArray
*
* parameters
* [in] ifdTableArray: address of the IFD tables array
* [in] ifdType : target IFD type
* [out] pResult : result status
* 0: OK
* -n: error
* ERR_INVALID_POINTER
* ERR_ALREADY_EXIST
* ERR_MEMALLOC
*
* return
* NULL: error
* !NULL: address of the newly created ifdTableArray
*
* note
* This function frees old ifdTableArray if is not NULL.
*/
void EXIF_API_EXPORT ** EXIF_API_CALL exif_insertIfdTableToIfdTableArray(void** ifdTableArray,
EXIF_IFD_TYPE ifdType,
int* pResult);
/**
* removeTagNodeFromIfdTableArray()
*
* Remove the specified tag node from the IFD table
*
* parameters
* [in] ifdTableArray: address of the IFD tables array
* [in] ifdType : target IFD type
* [in] tagId : target tag ID
*
* return
* n: number of the removed tags
*/
int EXIF_API_EXPORT_CALL exif_removeTagNodeFromIfdTableArray(void** ifdTableArray,
EXIF_IFD_TYPE ifdType,
uint16_t tagId);
/**
* insertTagNodeToIfdTableArray()
*
* Insert the specified tag node to the IFD table
*
* parameters
* [in] ifdTableArray: address of the IFD tables array
* [in] ifdType : target IFD type
* [in] tagNodeInfo: address of the TagNodeInfo
*
* note
* This function uses the copy of the specified tag data.
* The caller must free it after this function returns.
*
* return
* 0: OK
* ERR_INVALID_POINTER:
* ERR_NOT_EXIST:
* ERR_ALREADY_EXIST:
* ERR_UNKNOWN:
*/
int EXIF_API_EXPORT_CALL exif_insertTagNodeToIfdTableArray(void** ifdTableArray,
EXIF_IFD_TYPE ifdType,
ExifTagNodeInfo* tagNodeInfo);
/**
* getThumbnailDataOnIfdTableArray()
*
* Get a copy of the thumbnail data from the 1st IFD table
*
* parameters
* [in] ifdTableArray : address of the IFD tables array
* [out] pLength : returns the length of the thumbnail data
* [out] pResult : result status
* 0: OK
* -n: error
* ERR_INVALID_POINTER
* ERR_MEMALLOC
* ERR_NOT_EXIST
*
* return
* NULL: error
* !NULL: the thumbnail data
*
* note
* This function returns the copy of the thumbnail data.
* The caller must free it.
*/
uint8_t EXIF_API_EXPORT * EXIF_API_CALL exif_getThumbnailDataOnIfdTableArray(void** ifdTableArray,
unsigned int* pLength,
int* pResult);
/**
* setThumbnailDataOnIfdTableArray()
*
* Set or update the thumbnail data to the 1st IFD table
*
* parameters
* [in] ifdTableArray : address of the IFD tables array
* [in] pData : thumbnail data
* [in] length : thumbnail data length
*
* note
* This function creates the copy of the specified data.
* The caller must free it after this function returns.
*
* return
* 0: OK
* -n: error
* ERR_INVALID_POINTER
* ERR_MEMALLOC
* ERR_UNKNOWN
*/
int EXIF_API_EXPORT_CALL exif_setThumbnailDataOnIfdTableArray(void** ifdTableArray,
uint8_t* pData,
unsigned int length);
void EXIF_API_EXPORT_CALL exif_getIfdTableDump(void* pIfd, char** pp);
/**
* updateExifSegmentInJPEGFile()
*
* Update the Exif segment in a JPEG file
*
* parameters
* [in] inJPEGFileName : original JPEG file
* [in] outJPGEFileName : output JPEG file
* [in] ifdTableArray : address of the IFD tables array
*
* return
* 1: OK
* -n: error
* ERR_READ_FILE
* ERR_WRITE_FILE
* ERR_INVALID_JPEG
* ERR_INVALID_APP1HEADER
* ERR_INVALID_POINTER
* ERROR_UNKNOWN:
*/
int EXIF_API_EXPORT_CALL exif_updateExifSegmentInJPEGFile(const char* inJPEGFileName,
const char* outJPGEFileName,
void** ifdTableArray);
void EXIF_API_EXPORT_CALL exif_getIfdTableDump(void* pIfd, char** pp);
/**
* removeAdobeMetadataSegmentFromJPEGFile()
*
* Remove Adobe's XMP metadata segment from a JPEG file
*
* parameters
* [in] inJPEGFileName : original JPEG file
* [in] outJPGEFileName : output JPEG file
*
* return
* 1: OK
* 0: Adobe's metadata segment is not found
* -n: error
* ERR_READ_FILE
* ERR_WRITE_FILE
* ERR_INVALID_JPEG
* ERR_INVALID_APP1HEADER
*/
int EXIF_API_EXPORT_CALL exif_removeAdobeMetadataSegmentFromJPEGFile(const char* inJPEGFileName,
const char* outJPGEFileName);
// Tag IDs
// 0th IFD, 1st IFD, Exif IFD
#define TAG_ImageWidth 0x0100
#define TAG_ImageLength 0x0101
#define TAG_BitsPerSample 0x0102
#define TAG_Compression 0x0103
#define TAG_PhotometricInterpretation 0x0106
#define TAG_Orientation 0x0112
#define TAG_SamplesPerPixel 0x0115
#define TAG_PlanarConfiguration 0x011C
#define TAG_YCbCrSubSampling 0x0212
#define TAG_YCbCrPositioning 0x0213
#define TAG_XResolution 0x011A
#define TAG_YResolution 0x011B
#define TAG_ResolutionUnit 0x0128
#define TAG_StripOffsets 0x0111
#define TAG_RowsPerStrip 0x0116
#define TAG_StripByteCounts 0x0117
#define TAG_JPEGInterchangeFormat 0x0201
#define TAG_JPEGInterchangeFormatLength 0x0202
#define TAG_TransferFunction 0x012D
#define TAG_WhitePoint 0x013E
#define TAG_PrimaryChromaticities 0x013F
#define TAG_YCbCrCoefficients 0x0211
#define TAG_ReferenceBlackWhite 0x0214
#define TAG_DateTime 0x0132
#define TAG_ImageDescription 0x010E
#define TAG_Make 0x010F
#define TAG_Model 0x0110
#define TAG_Software 0x0131
#define TAG_Artist 0x013B
#define TAG_Copyright 0x8298
#define TAG_ExifIFDPointer 0x8769
#define TAG_GPSInfoIFDPointer 0x8825
#define TAG_InteroperabilityIFDPointer 0xA005
#define TAG_Rating 0x4746
#define TAG_ExifVersion 0x9000
#define TAG_FlashPixVersion 0xA000
#define TAG_ColorSpace 0xA001
#define TAG_ComponentsConfiguration 0x9101
#define TAG_CompressedBitsPerPixel 0x9102
#define TAG_PixelXDimension 0xA002
#define TAG_PixelYDimension 0xA003
#define TAG_MakerNote 0x927C
#define TAG_UserComment 0x9286
#define TAG_RelatedSoundFile 0xA004
#define TAG_DateTimeOriginal 0x9003
#define TAG_DateTimeDigitized 0x9004
#define TAG_SubSecTime 0x9290
#define TAG_SubSecTimeOriginal 0x9291
#define TAG_SubSecTimeDigitized 0x9292
#define TAG_ExposureTime 0x829A
#define TAG_FNumber 0x829D
#define TAG_ExposureProgram 0x8822
#define TAG_SpectralSensitivity 0x8824
#define TAG_PhotographicSensitivity 0x8827
#define TAG_OECF 0x8828
#define TAG_SensitivityType 0x8830
#define TAG_StandardOutputSensitivity 0x8831
#define TAG_RecommendedExposureIndex 0x8832
#define TAG_ISOSpeed 0x8833
#define TAG_ISOSpeedLatitudeyyy 0x8834
#define TAG_ISOSpeedLatitudezzz 0x8835
#define TAG_ShutterSpeedValue 0x9201
#define TAG_ApertureValue 0x9202
#define TAG_BrightnessValue 0x9203
#define TAG_ExposureBiasValue 0x9204
#define TAG_MaxApertureValue 0x9205
#define TAG_SubjectDistance 0x9206
#define TAG_MeteringMode 0x9207
#define TAG_LightSource 0x9208
#define TAG_Flash 0x9209
#define TAG_FocalLength 0x920A
#define TAG_SubjectArea 0x9214
#define TAG_FlashEnergy 0xA20B
#define TAG_SpatialFrequencyResponse 0xA20C
#define TAG_FocalPlaneXResolution 0xA20E
#define TAG_FocalPlaneYResolution 0xA20F
#define TAG_FocalPlaneResolutionUnit 0xA210
#define TAG_SubjectLocation 0xA214
#define TAG_ExposureIndex 0xA215
#define TAG_SensingMethod 0xA217
#define TAG_FileSource 0xA300
#define TAG_SceneType 0xA301
#define TAG_CFAPattern 0xA302
#define TAG_CustomRendered 0xA401
#define TAG_ExposureMode 0xA402
#define TAG_WhiteBalance 0xA403
#define TAG_DigitalZoomRatio 0xA404
#define TAG_FocalLengthIn35mmFormat 0xA405
#define TAG_SceneCaptureType 0xA406
#define TAG_GainControl 0xA407
#define TAG_Contrast 0xA408
#define TAG_Saturation 0xA409
#define TAG_Sharpness 0xA40A
#define TAG_DeviceSettingDescription 0xA40B
#define TAG_SubjectDistanceRange 0xA40C
#define TAG_ImageUniqueID 0xA420
#define TAG_CameraOwnerName 0xA430
#define TAG_BodySerialNumber 0xA431
#define TAG_LensSpecification 0xA432
#define TAG_LensMake 0xA433
#define TAG_LensModel 0xA434
#define TAG_LensSerialNumber 0xA435
#define TAG_Gamma 0xA500
#define TAG_PrintIM 0xC4A5
#define TAG_Padding 0xEA1C
// GPS IFD
#define TAG_GPSVersionID 0x0000
#define TAG_GPSLatitudeRef 0x0001
#define TAG_GPSLatitude 0x0002
#define TAG_GPSLongitudeRef 0x0003
#define TAG_GPSLongitude 0x0004
#define TAG_GPSAltitudeRef 0x0005
#define TAG_GPSAltitude 0x0006
#define TAG_GPSTimeStamp 0x0007
#define TAG_GPSSatellites 0x0008
#define TAG_GPSStatus 0x0009
#define TAG_GPSMeasureMode 0x000A
#define TAG_GPSDOP 0x000B
#define TAG_GPSSpeedRef 0x000C
#define TAG_GPSSpeed 0x000D
#define TAG_GPSTrackRef 0x000E
#define TAG_GPSTrack 0x000F
#define TAG_GPSImgDirectionRef 0x0010
#define TAG_GPSImgDirection 0x0011
#define TAG_GPSMapDatum 0x0012
#define TAG_GPSDestLatitudeRef 0x0013
#define TAG_GPSDestLatitude 0x0014
#define TAG_GPSDestLongitudeRef 0x0015
#define TAG_GPSDestLongitude 0x0016
#define TAG_GPSBearingRef 0x0017
#define TAG_GPSBearing 0x0018
#define TAG_GPSDestDistanceRef 0x0019
#define TAG_GPSDestDistance 0x001A
#define TAG_GPSProcessingMethod 0x001B
#define TAG_GPSAreaInformation 0x001C
#define TAG_GPSDateStamp 0x001D
#define TAG_GPSDifferential 0x001E
#define TAG_GPSHPositioningError 0x001F
// Interoperability IFD
#define TAG_InteroperabilityIndex 0x0001
#define TAG_InteroperabilityVersion 0x0002
#define TAG_RelatedImageFileFormat 0x1000
#define TAG_RelatedImageWidth 0x1001
#define TAG_RelatedImageHeight 0x1002
// MPF tags
#define TAG_MPFVersion 0xB000
#define TAG_NumberOfImage 0xB001
#define TAG_MPImageList 0xB002
#define TAG_ImageUIDList 0xB003
#define TAG_TotalFrames 0xB004
#define TAG_MPIndividualNum 0xB101
#define TAG_PanOrientation 0xB201
#define TAG_PanOverlapH 0xB202
#define TAG_PanOverlapV 0xB203
#define TAG_BaseViewpointNum 0xB204
#define TAG_ConvergenceAngle 0xB205
#define TAG_BaselineLength 0xB206
#define TAG_VerticalDivergence 0xB207
#define TAG_AxisDistanceX 0xB208
#define TAG_AxisDistanceY 0xB209
#define TAG_AxisDistanceZ 0xB20A
#define TAG_YawAngle 0xB20B
#define TAG_PitchAngle 0xB20C
#define TAG_RollAngle 0xB20D
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // _EXIF_H_

View File

@ -214,6 +214,12 @@ void AppConfig::set_defaults()
if (get("show_splash_screen").empty()) if (get("show_splash_screen").empty())
set("show_splash_screen", "1"); set("show_splash_screen", "1");
if (get("splash_screen_editor").empty())
set("splash_screen_editor", "benchy-splashscreen.jpg");
if (get("splash_screen_gcodeviewer").empty())
set("splash_screen_gcodeviewer", "prusa-gcodepreview.jpg");
#if ENABLE_CTRL_M_ON_WINDOWS #if ENABLE_CTRL_M_ON_WINDOWS
#ifdef _WIN32 #ifdef _WIN32
if (get("use_legacy_3DConnexion").empty()) if (get("use_legacy_3DConnexion").empty())

View File

@ -257,7 +257,7 @@ target_compile_definitions(libslic3r_gui PRIVATE $<$<BOOL:${SLIC3R_ALPHA}>:SLIC3
encoding_check(libslic3r_gui) encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES}) target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi exif libcurl ${wxWidgets_LIBRARIES})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES}) target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})

View File

@ -990,13 +990,23 @@ void Choice::BUILD() {
temp->Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_is_dropped = true; }); temp->Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_is_dropped = true; });
temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_is_dropped = false; }); temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_is_dropped = false; });
temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_change_field(); }, temp->GetId()); temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) {
//note: on_change_field() is never really called because m_disable_change_event is always true.
// it should be fixed in a better way, but as modifying how m_disable_change_event is set will need exentive testing
// on all platform, I add this stop-gap. If you can remove it and let the splash_screen_editor field working, do it!
if (m_disable_change_event) {
m_disable_change_event = false;
on_change_field();
m_disable_change_event = true;
}else
on_change_field();
}, temp->GetId());
if (m_is_editable) { if (m_is_editable) {
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) {
e.Skip(); e.Skip();
if (m_opt.type == coStrings) { if (m_opt.type == coStrings) {
on_change_field(); on_change_field();
return; return;
} }

View File

@ -37,6 +37,8 @@
#include <wx/splash.h> #include <wx/splash.h>
#include <wx/fontutil.h> #include <wx/fontutil.h>
#include "exif.h"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/I18N.hpp" #include "libslic3r/I18N.hpp"
@ -97,14 +99,14 @@ class MainFrame;
class SplashScreen : public wxSplashScreen class SplashScreen : public wxSplashScreen
{ {
public: public:
SplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxPoint pos = wxDefaultPosition) SplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxPoint pos = wxDefaultPosition, wxString author = "")
: wxSplashScreen(bitmap, splashStyle, milliseconds, static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, wxDefaultPosition, wxDefaultSize, : wxSplashScreen(bitmap, splashStyle, milliseconds, static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, wxDefaultPosition, wxDefaultSize,
#ifdef __APPLE__ #ifdef __APPLE__
wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP
#else #else
wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR
#endif // !__APPLE__ #endif // !__APPLE__
) ), m_author(author)
{ {
wxASSERT(bitmap.IsOk()); wxASSERT(bitmap.IsOk());
@ -221,8 +223,11 @@ public:
int version_height = memDc.GetTextExtent(m_constant_text.version).GetY(); int version_height = memDc.GetTextExtent(m_constant_text.version).GetY();
memDc.SetFont(m_constant_text.credits_font); memDc.SetFont(m_constant_text.credits_font);
memDc.DrawLabel(m_constant_text.credits, banner_rect, wxALIGN_BOTTOM | wxALIGN_LEFT); wxString credit_and_author = m_constant_text.credits;
int credits_height = memDc.GetMultiLineTextExtent(m_constant_text.credits).GetY(); if (!m_author.empty())
credit_and_author += "\n\n" + m_author;
memDc.DrawLabel(credit_and_author, banner_rect, wxALIGN_BOTTOM | wxALIGN_LEFT);
int credits_height = memDc.GetMultiLineTextExtent(credit_and_author).GetY();
int text_height = memDc.GetTextExtent("text").GetY(); int text_height = memDc.GetTextExtent("text").GetY();
// calculate position for the dynamic text // calculate position for the dynamic text
@ -235,6 +240,7 @@ private:
wxFont m_action_font; wxFont m_action_font;
int m_action_line_y_position; int m_action_line_y_position;
float m_scale {1.0}; float m_scale {1.0};
wxString m_author;
struct ConstantText struct ConstantText
{ {
@ -257,8 +263,7 @@ private:
// credits infornation // credits infornation
credits = _L(SLIC3R_INTRO) + "\n\n" + credits = _L(SLIC3R_INTRO) + "\n\n" +
title + " " + _L("is licensed under the") + " " + _L("GNU Affero General Public License, version 3") + "\n\n" + title + " " + _L("is licensed under the") + " " + _L("GNU Affero General Public License, version 3") + "\n\n" +
_L("Contributions by Vojtech Bubnik, Enrico Turri, Durand Remi, Oleksandra Iushchenko, Tamas Meszaros, Lukas Matena, Vojtech Kral, David Kocik and numerous others.") + "\n\n" + _L("Contributions by Vojtech Bubnik, Enrico Turri, Durand Remi, Oleksandra Iushchenko, Tamas Meszaros, Lukas Matena, Vojtech Kral, David Kocik and numerous others.");
_L("Artwork model by Durand Remi");
title_font = version_font = credits_font = init_font; title_font = version_font = credits_font = init_font;
} }
@ -818,8 +823,30 @@ bool GUI_App::on_init_inner()
SplashScreen* scrn = nullptr; SplashScreen* scrn = nullptr;
if (app_config->get("show_splash_screen") == "1") { if (app_config->get("show_splash_screen") == "1") {
wxBitmap bmp;
std::string file_name = is_editor()
? app_config->get("splash_screen_editor")
: app_config->get("splash_screen_gcodeviewer");
wxString artist;
if (!file_name.empty() && file_name != (std::string(SLIC3R_APP_NAME) + L(" icon"))) {
wxString splash_screen_path = (boost::filesystem::path(Slic3r::resources_dir()) / "splashscreen" / file_name).string();
// make a bitmap with dark grey banner on the left side // make a bitmap with dark grey banner on the left side
wxBitmap bmp = SplashScreen::MakeBitmap(wxBitmap(from_u8(var(is_editor() ? "splashscreen.jpg" : "splashscreen-gcodepreview.jpg")), wxBITMAP_TYPE_JPEG)); bmp = SplashScreen::MakeBitmap(wxBitmap(splash_screen_path, wxBITMAP_TYPE_JPEG));
int result;
void** ifdArray = nullptr;
ExifTagNodeInfo* tag;
ifdArray = exif_createIfdTableArray(splash_screen_path.c_str(), &result);
if (result > 0 && ifdArray) {
tag = exif_getTagInfo(ifdArray, IFD_0TH, TAG_Artist);
if (tag) {
if (!tag->error) {
artist = (_L("Artwork model by") + " " + ((char*)tag->byteData));
}
}
}
}
// Detect position (display) to show the splash screen // Detect position (display) to show the splash screen
// Now this position is equal to the mainframe position // Now this position is equal to the mainframe position
@ -832,7 +859,7 @@ bool GUI_App::on_init_inner()
// create splash screen with updated bmp // create splash screen with updated bmp
scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap( SLIC3R_APP_KEY "_logo", nullptr, 400), scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap( SLIC3R_APP_KEY "_logo", nullptr, 400),
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos); wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos, artist);
#ifndef __linux__ #ifndef __linux__
wxYield(); wxYield();
#endif #endif

View File

@ -58,8 +58,10 @@ void PreferencesDialog::build()
m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) { m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset") if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset")
m_values[opt_key] = boost::any_cast<bool>(value) ? "none" : "discard"; m_values[opt_key] = boost::any_cast<bool>(value) ? "none" : "discard";
else if (opt_key == "splash_screen_editor" || opt_key == "splash_screen_gcodeviewer")
m_values[opt_key] = boost::any_cast<std::string>(value);
else else
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0"; m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
}; };
bool is_editor = wxGetApp().is_editor(); bool is_editor = wxGetApp().is_editor();
@ -236,6 +238,27 @@ void PreferencesDialog::build()
def.set_default_value(new ConfigOptionBool{ app_config->get("show_splash_screen") == "1" }); def.set_default_value(new ConfigOptionBool{ app_config->get("show_splash_screen") == "1" });
option = Option(def, "show_splash_screen"); option = Option(def, "show_splash_screen");
m_optgroup_general->append_single_option_line(option); m_optgroup_general->append_single_option_line(option);
// splashscreen image
{
ConfigOptionDef def_combobox;
def_combobox.label = L("Splashscreen image");
def_combobox.type = coStrings;
def_combobox.tooltip = L("Choose the image to use as splashscreen");
def_combobox.gui_type = "f_enum_open";
def_combobox.gui_flags = "show_value";
def_combobox.enum_values.push_back(std::string(SLIC3R_APP_NAME) + L(" icon"));
//get all images in the spashscreen dir
for (const boost::filesystem::directory_entry& dir_entry : boost::filesystem::directory_iterator(boost::filesystem::path(Slic3r::resources_dir()) / "splashscreen"))
if (dir_entry.path().has_extension()&& std::set<std::string>{ ".jpg", ".JPG", ".jpeg" }.count(dir_entry.path().extension().string()) > 0 )
def_combobox.enum_values.push_back(dir_entry.path().filename().string());
std::string current_file_name = app_config->get(is_editor ? "splash_screen_editor" : "splash_screen_gcodeviewer");
if (std::find(def_combobox.enum_values.begin(), def_combobox.enum_values.end(), current_file_name) == def_combobox.enum_values.end())
current_file_name = def_combobox.enum_values[0];
def_combobox.set_default_value(new ConfigOptionStrings{ current_file_name });
option = Option(def_combobox, is_editor ? "splash_screen_editor" : "splash_screen_gcodeviewer");
m_optgroup_general->append_single_option_line(option);
}
#if ENABLE_CTRL_M_ON_WINDOWS #if ENABLE_CTRL_M_ON_WINDOWS
#if defined(_WIN32) || defined(__APPLE__) #if defined(_WIN32) || defined(__APPLE__)