axmol/cocos/platform/CCImage.cpp

2220 lines
68 KiB
C++
Raw Normal View History

/****************************************************************************
Copyright (c) 2010-2012 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
Squashed commit of the following: commit a794d107ad85667e3d754f0b6251fc864dfbf288 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 14:33:49 2014 -0700 Yeah... everything compiles on win32 and wp8 commit 4740be6e4a0d16f742c27996e7ab2c100adc76af Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:58:38 2014 -0700 CCIME moved to base and compiles on Android commit ff3e1bf1eb27a01019f4e1b56d1aebbe2d385f72 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:02:57 2014 -0700 compiles Ok for Windows Phone 8 commit 8160a4eb2ecdc61b5bd1cf56b90d2da6f11e3ebd Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 12:25:31 2014 -0700 fixes for Windows Phone 8 commit 418197649efc93032aee0adc205e502101cdb53d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 11:15:13 2014 -0700 Compiles on Win32 commit 08813ed7cf8ac1079ffadeb1ce78ea9e833e1a33 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 10:08:31 2014 -0700 Compiles on linux! commit 118896521e5b335a5257090b6863f1fb2a2002fe Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 09:30:42 2014 -0700 moves cocos/2d/platform -> cocos/platform commit 4fe9319d7717b0c1bccb2db0156eeb86255a89e0 Merge: bd68ec2 511295e Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 08:24:41 2014 -0700 Merge remote-tracking branch 'cocos2d/v3' into files commit bd68ec2f0e3a826d8b2f4b60564ba65ce766bc56 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Thu May 15 19:36:23 2014 -0700 files in the correct directory
2014-05-17 05:36:00 +08:00
#include "platform/CCImage.h"
#include <string>
#include <ctype.h>
Squashed commit of the following: commit a794d107ad85667e3d754f0b6251fc864dfbf288 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 14:33:49 2014 -0700 Yeah... everything compiles on win32 and wp8 commit 4740be6e4a0d16f742c27996e7ab2c100adc76af Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:58:38 2014 -0700 CCIME moved to base and compiles on Android commit ff3e1bf1eb27a01019f4e1b56d1aebbe2d385f72 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:02:57 2014 -0700 compiles Ok for Windows Phone 8 commit 8160a4eb2ecdc61b5bd1cf56b90d2da6f11e3ebd Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 12:25:31 2014 -0700 fixes for Windows Phone 8 commit 418197649efc93032aee0adc205e502101cdb53d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 11:15:13 2014 -0700 Compiles on Win32 commit 08813ed7cf8ac1079ffadeb1ce78ea9e833e1a33 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 10:08:31 2014 -0700 Compiles on linux! commit 118896521e5b335a5257090b6863f1fb2a2002fe Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 09:30:42 2014 -0700 moves cocos/2d/platform -> cocos/platform commit 4fe9319d7717b0c1bccb2db0156eeb86255a89e0 Merge: bd68ec2 511295e Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 08:24:41 2014 -0700 Merge remote-tracking branch 'cocos2d/v3' into files commit bd68ec2f0e3a826d8b2f4b60564ba65ce766bc56 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Thu May 15 19:36:23 2014 -0700 files in the correct directory
2014-05-17 05:36:00 +08:00
#include "base/CCData.h"
#ifdef EMSCRIPTEN
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#endif // EMSCRIPTEN
extern "C"
{
#ifndef __ENABLE_COMPATIBILITY_WITH_UNIX_2003__
#define __ENABLE_COMPATIBILITY_WITH_UNIX_2003__
#include <stdio.h>
FILE *fopen$UNIX2003( const char *filename, const char *mode )
{
return fopen(filename, mode);
}
size_t fwrite$UNIX2003( const void *a, size_t b, size_t c, FILE *d )
{
return fwrite(a, b, c, d);
}
char *strerror$UNIX2003( int errnum )
{
return strerror(errnum);
}
#endif
#include "png.h"
#include "tiffio.h"
Squashed commit of the following: commit c16dcfaaea0922039aad05bce1f4efed18e04871 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:05:18 2014 -0700 more linux fixes commit 1553795976c9090a1b46deb53d12910fe0676008 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:04:04 2014 -0700 more linux fixes commit 1e43a8cabff33cbf25aa5eb5412f53a878222d83 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:02:07 2014 -0700 fixes linux isuses commit 723a445dd6411f91846da2b801248ad8298174f1 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:58:50 2014 -0700 more linux fixes commit 533c8025e794fc76cef02f396b3a93b3d7f4cfc8 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:57:33 2014 -0700 more linux fixes commit 4ba1e84959670bcbf044f18d1c0d4b3cb3be4090 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:53:43 2014 -0700 more linux fixes commit 1f8e011f306a47ed4134224e5e349929201f0539 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:49:28 2014 -0700 more linux fixes commit 3e2033100822ff6d532a1b4f012337491dc11920 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:47:43 2014 -0700 more linux fixes commit 2e708863c75fd032f1b2396dfdf1d31f7a62b713 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:46:00 2014 -0700 more linux fixes commit 861b5b92a6efd4de7b926c20d636ce9d749b293f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:43:15 2014 -0700 more linux fixes commit 2a43365a0c1755e9b9cada53301be1a20adb31cf Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:36:06 2014 -0700 more fixes for linux commit 7d332bf911892f87c7824d2a5da7bf73ce7ec411 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:35:29 2014 -0700 more fixes for linux commit f1becc17d3316dfe3678c23c9dcedb7a447d9235 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:34:44 2014 -0700 more fixes for linux commit d2e5959bb0dde921dd5e73be1d8acc3b3f50e51d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:33:45 2014 -0700 fixes for linux commit ad9b633c352107cf0e8b060a0e23d6e6a3f5e80f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:16:48 2014 -0700 compiles on Windows commit 4425ee8e5de8f42a2d6050e4470109600dce8b5d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:07:20 2014 -0700 fix builder
2014-05-01 10:09:13 +08:00
#include "base/etc1.h"
#include "jpeglib.h"
}
Squashed commit of the following: commit c16dcfaaea0922039aad05bce1f4efed18e04871 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:05:18 2014 -0700 more linux fixes commit 1553795976c9090a1b46deb53d12910fe0676008 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:04:04 2014 -0700 more linux fixes commit 1e43a8cabff33cbf25aa5eb5412f53a878222d83 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:02:07 2014 -0700 fixes linux isuses commit 723a445dd6411f91846da2b801248ad8298174f1 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:58:50 2014 -0700 more linux fixes commit 533c8025e794fc76cef02f396b3a93b3d7f4cfc8 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:57:33 2014 -0700 more linux fixes commit 4ba1e84959670bcbf044f18d1c0d4b3cb3be4090 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:53:43 2014 -0700 more linux fixes commit 1f8e011f306a47ed4134224e5e349929201f0539 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:49:28 2014 -0700 more linux fixes commit 3e2033100822ff6d532a1b4f012337491dc11920 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:47:43 2014 -0700 more linux fixes commit 2e708863c75fd032f1b2396dfdf1d31f7a62b713 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:46:00 2014 -0700 more linux fixes commit 861b5b92a6efd4de7b926c20d636ce9d749b293f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:43:15 2014 -0700 more linux fixes commit 2a43365a0c1755e9b9cada53301be1a20adb31cf Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:36:06 2014 -0700 more fixes for linux commit 7d332bf911892f87c7824d2a5da7bf73ce7ec411 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:35:29 2014 -0700 more fixes for linux commit f1becc17d3316dfe3678c23c9dcedb7a447d9235 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:34:44 2014 -0700 more fixes for linux commit d2e5959bb0dde921dd5e73be1d8acc3b3f50e51d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:33:45 2014 -0700 fixes for linux commit ad9b633c352107cf0e8b060a0e23d6e6a3f5e80f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:16:48 2014 -0700 compiles on Windows commit 4425ee8e5de8f42a2d6050e4470109600dce8b5d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:07:20 2014 -0700 fix builder
2014-05-01 10:09:13 +08:00
#include "base/s3tc.h"
#include "base/atitc.h"
Squashed commit of the following: commit a794d107ad85667e3d754f0b6251fc864dfbf288 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 14:33:49 2014 -0700 Yeah... everything compiles on win32 and wp8 commit 4740be6e4a0d16f742c27996e7ab2c100adc76af Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:58:38 2014 -0700 CCIME moved to base and compiles on Android commit ff3e1bf1eb27a01019f4e1b56d1aebbe2d385f72 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:02:57 2014 -0700 compiles Ok for Windows Phone 8 commit 8160a4eb2ecdc61b5bd1cf56b90d2da6f11e3ebd Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 12:25:31 2014 -0700 fixes for Windows Phone 8 commit 418197649efc93032aee0adc205e502101cdb53d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 11:15:13 2014 -0700 Compiles on Win32 commit 08813ed7cf8ac1079ffadeb1ce78ea9e833e1a33 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 10:08:31 2014 -0700 Compiles on linux! commit 118896521e5b335a5257090b6863f1fb2a2002fe Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 09:30:42 2014 -0700 moves cocos/2d/platform -> cocos/platform commit 4fe9319d7717b0c1bccb2db0156eeb86255a89e0 Merge: bd68ec2 511295e Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 08:24:41 2014 -0700 Merge remote-tracking branch 'cocos2d/v3' into files commit bd68ec2f0e3a826d8b2f4b60564ba65ce766bc56 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Thu May 15 19:36:23 2014 -0700 files in the correct directory
2014-05-17 05:36:00 +08:00
#include "base/TGAlib.h"
2014-03-22 20:51:39 +08:00
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
#include "decode.h"
2014-03-22 20:51:39 +08:00
#endif
2014-04-30 08:37:36 +08:00
#include "base/ccMacros.h"
#include "CCCommon.h"
#include "CCStdC.h"
#include "CCFileUtils.h"
Squashed commit of the following: commit c16dcfaaea0922039aad05bce1f4efed18e04871 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:05:18 2014 -0700 more linux fixes commit 1553795976c9090a1b46deb53d12910fe0676008 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:04:04 2014 -0700 more linux fixes commit 1e43a8cabff33cbf25aa5eb5412f53a878222d83 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 19:02:07 2014 -0700 fixes linux isuses commit 723a445dd6411f91846da2b801248ad8298174f1 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:58:50 2014 -0700 more linux fixes commit 533c8025e794fc76cef02f396b3a93b3d7f4cfc8 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:57:33 2014 -0700 more linux fixes commit 4ba1e84959670bcbf044f18d1c0d4b3cb3be4090 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:53:43 2014 -0700 more linux fixes commit 1f8e011f306a47ed4134224e5e349929201f0539 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:49:28 2014 -0700 more linux fixes commit 3e2033100822ff6d532a1b4f012337491dc11920 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:47:43 2014 -0700 more linux fixes commit 2e708863c75fd032f1b2396dfdf1d31f7a62b713 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:46:00 2014 -0700 more linux fixes commit 861b5b92a6efd4de7b926c20d636ce9d749b293f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:43:15 2014 -0700 more linux fixes commit 2a43365a0c1755e9b9cada53301be1a20adb31cf Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:36:06 2014 -0700 more fixes for linux commit 7d332bf911892f87c7824d2a5da7bf73ce7ec411 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:35:29 2014 -0700 more fixes for linux commit f1becc17d3316dfe3678c23c9dcedb7a447d9235 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:34:44 2014 -0700 more fixes for linux commit d2e5959bb0dde921dd5e73be1d8acc3b3f50e51d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:33:45 2014 -0700 fixes for linux commit ad9b633c352107cf0e8b060a0e23d6e6a3f5e80f Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:16:48 2014 -0700 compiles on Windows commit 4425ee8e5de8f42a2d6050e4470109600dce8b5d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Wed Apr 30 18:07:20 2014 -0700 fix builder
2014-05-01 10:09:13 +08:00
#include "base/CCConfiguration.h"
Squashed commit of the following: commit a794d107ad85667e3d754f0b6251fc864dfbf288 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 14:33:49 2014 -0700 Yeah... everything compiles on win32 and wp8 commit 4740be6e4a0d16f742c27996e7ab2c100adc76af Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:58:38 2014 -0700 CCIME moved to base and compiles on Android commit ff3e1bf1eb27a01019f4e1b56d1aebbe2d385f72 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 13:02:57 2014 -0700 compiles Ok for Windows Phone 8 commit 8160a4eb2ecdc61b5bd1cf56b90d2da6f11e3ebd Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 12:25:31 2014 -0700 fixes for Windows Phone 8 commit 418197649efc93032aee0adc205e502101cdb53d Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 11:15:13 2014 -0700 Compiles on Win32 commit 08813ed7cf8ac1079ffadeb1ce78ea9e833e1a33 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 10:08:31 2014 -0700 Compiles on linux! commit 118896521e5b335a5257090b6863f1fb2a2002fe Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 09:30:42 2014 -0700 moves cocos/2d/platform -> cocos/platform commit 4fe9319d7717b0c1bccb2db0156eeb86255a89e0 Merge: bd68ec2 511295e Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Fri May 16 08:24:41 2014 -0700 Merge remote-tracking branch 'cocos2d/v3' into files commit bd68ec2f0e3a826d8b2f4b60564ba65ce766bc56 Author: Ricardo Quesada <ricardoquesada@gmail.com> Date: Thu May 15 19:36:23 2014 -0700 files in the correct directory
2014-05-17 05:36:00 +08:00
#include "base/ccUtils.h"
2014-04-30 08:37:36 +08:00
#include "base/ZipUtils.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "android/CCFileUtilsAndroid.h"
#endif
#define CC_GL_ATC_RGB_AMD 0x8C92
#define CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
#define CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
NS_CC_BEGIN
//////////////////////////////////////////////////////////////////////////
//struct and data for pvr structure
2013-08-08 14:11:22 +08:00
namespace
{
static const int PVR_TEXTURE_FLAG_TYPE_MASK = 0xff;
2013-08-06 16:14:36 +08:00
// Values taken from PVRTexture.h from http://www.imgtec.com
2013-08-13 10:11:28 +08:00
enum class PVR2TextureFlag
{
2013-08-06 16:14:36 +08:00
Mipmap = (1<<8), // has mip map levels
Twiddle = (1<<9), // is twiddled
Bumpmap = (1<<10), // has normals encoded for a bump map
Tiling = (1<<11), // is bordered for tiled pvr
Cubemap = (1<<12), // is a cubemap/skybox
FalseMipCol = (1<<13), // are there false colored MIP levels
Volume = (1<<14), // is this a volume texture
Alpha = (1<<15), // v2.1 is there transparency info in the texture
VerticalFlip = (1<<16), // v2.1 is the texture vertically flipped
};
2013-08-06 16:14:36 +08:00
enum class PVR3TextureFlag
{
PremultipliedAlpha = (1<<1) // has premultiplied alpha
};
2013-08-06 16:14:36 +08:00
static const char gPVRTexIdentifier[5] = "PVR!";
// v2
enum class PVR2TexturePixelFormat : unsigned char
{
RGBA4444 = 0x10,
RGBA5551,
RGBA8888,
RGB565,
RGB555, // unsupported
RGB888,
I8,
AI88,
PVRTC2BPP_RGBA,
PVRTC4BPP_RGBA,
BGRA8888,
A8,
2013-08-13 10:11:28 +08:00
};
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v3
enum class PVR3TexturePixelFormat : uint64_t
{
PVRTC2BPP_RGB = 0ULL,
PVRTC2BPP_RGBA = 1ULL,
PVRTC4BPP_RGB = 2ULL,
PVRTC4BPP_RGBA = 3ULL,
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
BGRA8888 = 0x0808080861726762ULL,
RGBA8888 = 0x0808080861626772ULL,
RGBA4444 = 0x0404040461626772ULL,
RGBA5551 = 0x0105050561626772ULL,
RGB565 = 0x0005060500626772ULL,
RGB888 = 0x0008080800626772ULL,
A8 = 0x0000000800000061ULL,
L8 = 0x000000080000006cULL,
LA88 = 0x000008080000616cULL,
};
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v2
typedef const std::map<PVR2TexturePixelFormat, Texture2D::PixelFormat> _pixel2_formathash;
static const _pixel2_formathash::value_type v2_pixel_formathash_value[] =
{
_pixel2_formathash::value_type(PVR2TexturePixelFormat::BGRA8888, Texture2D::PixelFormat::BGRA8888),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::RGBA8888, Texture2D::PixelFormat::RGBA8888),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::RGBA4444, Texture2D::PixelFormat::RGBA4444),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::RGBA5551, Texture2D::PixelFormat::RGB5A1),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::RGB565, Texture2D::PixelFormat::RGB565),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::RGB888, Texture2D::PixelFormat::RGB888),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::A8, Texture2D::PixelFormat::A8),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::I8, Texture2D::PixelFormat::I8),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::AI88, Texture2D::PixelFormat::AI88),
2013-08-06 16:14:36 +08:00
#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
2013-08-13 10:11:28 +08:00
_pixel2_formathash::value_type(PVR2TexturePixelFormat::PVRTC2BPP_RGBA, Texture2D::PixelFormat::PVRTC2A),
_pixel2_formathash::value_type(PVR2TexturePixelFormat::PVRTC4BPP_RGBA, Texture2D::PixelFormat::PVRTC4A),
#endif
2013-08-13 10:11:28 +08:00
};
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const int PVR2_MAX_TABLE_ELEMENTS = sizeof(v2_pixel_formathash_value) / sizeof(v2_pixel_formathash_value[0]);
static const _pixel2_formathash v2_pixel_formathash(v2_pixel_formathash_value, v2_pixel_formathash_value + PVR2_MAX_TABLE_ELEMENTS);
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v3
typedef const std::map<PVR3TexturePixelFormat, Texture2D::PixelFormat> _pixel3_formathash;
static _pixel3_formathash::value_type v3_pixel_formathash_value[] =
{
_pixel3_formathash::value_type(PVR3TexturePixelFormat::BGRA8888, Texture2D::PixelFormat::BGRA8888),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::RGBA8888, Texture2D::PixelFormat::RGBA8888),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::RGBA4444, Texture2D::PixelFormat::RGBA4444),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::RGBA5551, Texture2D::PixelFormat::RGB5A1),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::RGB565, Texture2D::PixelFormat::RGB565),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::RGB888, Texture2D::PixelFormat::RGB888),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::A8, Texture2D::PixelFormat::A8),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::L8, Texture2D::PixelFormat::I8),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::LA88, Texture2D::PixelFormat::AI88),
2013-08-06 16:14:36 +08:00
#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
2013-08-13 10:11:28 +08:00
_pixel3_formathash::value_type(PVR3TexturePixelFormat::PVRTC2BPP_RGB, Texture2D::PixelFormat::PVRTC2),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::PVRTC2BPP_RGBA, Texture2D::PixelFormat::PVRTC2A),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::PVRTC4BPP_RGB, Texture2D::PixelFormat::PVRTC4),
_pixel3_formathash::value_type(PVR3TexturePixelFormat::PVRTC4BPP_RGBA, Texture2D::PixelFormat::PVRTC4A),
#endif
2013-08-13 10:11:28 +08:00
};
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const int PVR3_MAX_TABLE_ELEMENTS = sizeof(v3_pixel_formathash_value) / sizeof(v3_pixel_formathash_value[0]);
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const _pixel3_formathash v3_pixel_formathash(v3_pixel_formathash_value, v3_pixel_formathash_value + PVR3_MAX_TABLE_ELEMENTS);
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
typedef struct _PVRTexHeader
{
unsigned int headerLength;
unsigned int height;
unsigned int width;
unsigned int numMipmaps;
unsigned int flags;
unsigned int dataLength;
unsigned int bpp;
unsigned int bitmaskRed;
unsigned int bitmaskGreen;
unsigned int bitmaskBlue;
unsigned int bitmaskAlpha;
unsigned int pvrTag;
unsigned int numSurfs;
} PVRv2TexHeader;
2013-08-06 16:14:36 +08:00
#ifdef _MSC_VER
#pragma pack(push,1)
#endif
2013-08-13 10:11:28 +08:00
typedef struct
{
uint32_t version;
uint32_t flags;
uint64_t pixelFormat;
uint32_t colorSpace;
uint32_t channelType;
uint32_t height;
uint32_t width;
uint32_t depth;
uint32_t numberOfSurfaces;
uint32_t numberOfFaces;
uint32_t numberOfMipmaps;
uint32_t metadataLength;
#ifdef _MSC_VER
2013-08-13 10:11:28 +08:00
} PVRv3TexHeader;
#pragma pack(pop)
#else
2013-08-06 16:14:36 +08:00
} __attribute__((packed)) PVRv3TexHeader;
#endif
}
//pvr structure end
2013-08-06 11:19:45 +08:00
//////////////////////////////////////////////////////////////////////////
2013-08-06 11:19:45 +08:00
//struct and data for s3tc(dds) struct
2013-08-08 14:59:46 +08:00
namespace
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
struct DDColorKey
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t colorSpaceLowValue;
uint32_t colorSpaceHighValue;
};
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDSCaps
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t caps;
uint32_t caps2;
uint32_t caps3;
uint32_t caps4;
};
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDPixelFormat
{
uint32_t size;
uint32_t flags;
uint32_t fourCC;
uint32_t RGBBitCount;
uint32_t RBitMask;
uint32_t GBitMask;
uint32_t BBitMask;
uint32_t ABitMask;
};
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDSURFACEDESC2
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t size;
uint32_t flags;
uint32_t height;
uint32_t width;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
uint32_t pitch;
uint32_t linearSize;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN1;
union
{
2013-08-09 12:54:05 +08:00
uint32_t backBufferCount;
uint32_t depth;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN5;
union
{
2013-08-09 12:54:05 +08:00
uint32_t mipMapCount;
uint32_t refreshRate;
uint32_t srcVBHandle;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN2;
2013-08-09 12:54:05 +08:00
uint32_t alphaBitDepth;
uint32_t reserved;
uint32_t surface;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
DDColorKey ddckCKDestOverlay;
uint32_t emptyFaceColor;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN3;
2013-08-09 12:54:05 +08:00
DDColorKey ddckCKDestBlt;
DDColorKey ddckCKSrcOverlay;
DDColorKey ddckCKSrcBlt;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
DDPixelFormat ddpfPixelFormat;
uint32_t FVF;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN4;
2013-08-09 12:54:05 +08:00
DDSCaps ddsCaps;
uint32_t textureStage;
} ;
2013-08-06 11:19:45 +08:00
2013-08-08 14:59:46 +08:00
#pragma pack(push,1)
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct S3TCTexHeader
2013-08-06 11:19:45 +08:00
{
2013-08-08 14:59:46 +08:00
char fileCode[4];
DDSURFACEDESC2 ddsd;
2013-08-09 12:54:05 +08:00
};
2013-08-06 11:19:45 +08:00
#pragma pack(pop)
2013-08-08 14:59:46 +08:00
}
2013-08-06 11:19:45 +08:00
//s3tc struct end
//////////////////////////////////////////////////////////////////////////
//struct and data for atitc(ktx) struct
namespace
{
struct ATITCTexHeader
{
//HEADER
char identifier[12];
uint32_t endianness;
uint32_t glType;
uint32_t glTypeSize;
uint32_t glFormat;
uint32_t glInternalFormat;
uint32_t glBaseInternalFormat;
uint32_t pixelWidth;
uint32_t pixelHeight;
uint32_t pixelDepth;
uint32_t numberOfArrayElements;
uint32_t numberOfFaces;
uint32_t numberOfMipmapLevels;
uint32_t bytesOfKeyValueData;
};
}
//atittc struct end
//////////////////////////////////////////////////////////////////////////
2013-08-06 11:19:45 +08:00
2013-08-08 14:59:46 +08:00
namespace
{
2013-08-06 16:14:36 +08:00
typedef struct
{
2013-08-12 17:05:19 +08:00
const unsigned char * data;
2013-12-06 16:32:06 +08:00
ssize_t size;
2013-08-06 16:14:36 +08:00
int offset;
}tImageSource;
static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
{
2013-08-06 16:14:36 +08:00
tImageSource* isource = (tImageSource*)png_get_io_ptr(png_ptr);
if((int)(isource->offset + length) <= isource->size)
{
memcpy(data, isource->data+isource->offset, length);
isource->offset += length;
}
else
{
png_error(png_ptr, "pngReaderCallback failed");
}
}
}
//////////////////////////////////////////////////////////////////////////
// Implement Image
//////////////////////////////////////////////////////////////////////////
Image::Image()
: _data(nullptr)
, _dataLen(0)
, _width(0)
, _height(0)
, _fileType(Format::UNKOWN)
, _renderFormat(Texture2D::PixelFormat::NONE)
, _preMulti(false)
, _numberOfMipmaps(0)
2013-11-13 11:22:34 +08:00
, _hasPremultipliedAlpha(true)
{
}
Image::~Image()
{
CC_SAFE_FREE(_data);
}
bool Image::initWithImageFile(const std::string& path)
{
bool ret = false;
_filePath = FileUtils::getInstance()->fullPathForFilename(path);
#ifdef EMSCRIPTEN
// Emscripten includes a re-implementation of SDL that uses HTML5 canvas
// operations underneath. Consequently, loading images via IMG_Load (an SDL
// API) will be a lot faster than running libpng et al as compiled with
// Emscripten.
2013-07-23 21:49:00 +08:00
SDL_Surface *iSurf = IMG_Load(fullPath.c_str());
int size = 4 * (iSurf->w * iSurf->h);
ret = initWithRawData((const unsigned char*)iSurf->pixels, size, iSurf->w, iSurf->h, 8, true);
unsigned int *tmp = (unsigned int *)_data;
int nrPixels = iSurf->w * iSurf->h;
for(int i = 0; i < nrPixels; i++)
{
unsigned char *p = _data + i * 4;
tmp[i] = CC_RGB_PREMULTIPLY_ALPHA( p[0], p[1], p[2], p[3] );
}
SDL_FreeSurface(iSurf);
#else
Data data = FileUtils::getInstance()->getDataFromFile(_filePath);
if (!data.isNull())
{
ret = initWithImageData(data.getBytes(), data.getSize());
}
#endif // EMSCRIPTEN
return ret;
}
bool Image::initWithImageFileThreadSafe(const std::string& fullpath)
{
bool ret = false;
_filePath = fullpath;
Data data = FileUtils::getInstance()->getDataFromFile(fullpath);
if (!data.isNull())
{
ret = initWithImageData(data.getBytes(), data.getSize());
}
return ret;
}
2013-12-05 17:19:01 +08:00
bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen)
{
2013-08-12 17:05:19 +08:00
bool ret = false;
do
{
CC_BREAK_IF(! data || dataLen <= 0);
unsigned char* unpackedData = nullptr;
2013-12-05 17:19:01 +08:00
ssize_t unpackedLen = 0;
//detecgt and unzip the compress file
if (ZipUtils::isCCZBuffer(data, dataLen))
{
unpackedLen = ZipUtils::inflateCCZBuffer(data, dataLen, &unpackedData);
}
else if (ZipUtils::isGZipBuffer(data, dataLen))
{
unpackedLen = ZipUtils::inflateMemory(const_cast<unsigned char*>(data), dataLen, &unpackedData);
}
else
{
2013-08-12 17:05:19 +08:00
unpackedData = const_cast<unsigned char*>(data);
unpackedLen = dataLen;
}
_fileType = detectFormat(unpackedData, unpackedLen);
2013-07-17 17:12:04 +08:00
switch (_fileType)
{
case Format::PNG:
2013-08-12 17:05:19 +08:00
ret = initWithPngData(unpackedData, unpackedLen);
break;
case Format::JPG:
2013-08-12 17:05:19 +08:00
ret = initWithJpgData(unpackedData, unpackedLen);
break;
case Format::TIFF:
2013-08-12 17:05:19 +08:00
ret = initWithTiffData(unpackedData, unpackedLen);
break;
case Format::WEBP:
2013-08-12 17:05:19 +08:00
ret = initWithWebpData(unpackedData, unpackedLen);
break;
case Format::PVR:
2013-08-12 17:05:19 +08:00
ret = initWithPVRData(unpackedData, unpackedLen);
break;
case Format::ETC:
2013-08-12 17:05:19 +08:00
ret = initWithETCData(unpackedData, unpackedLen);
break;
2013-08-06 11:19:45 +08:00
case Format::S3TC:
2013-08-12 17:05:19 +08:00
ret = initWithS3TCData(unpackedData, unpackedLen);
break;
case Format::ATITC:
2013-08-16 14:27:13 +08:00
ret = initWithATITCData(unpackedData, unpackedLen);
break;
default:
{
// load and detect image format
tImageTGA* tgaData = tgaLoadBuffer(unpackedData, unpackedLen);
if (tgaData != nullptr && tgaData->status == TGA_OK)
{
ret = initWithTGAData(tgaData);
}
else
{
CCAssert(false, "unsupport image format!");
}
free(tgaData);
break;
}
}
if(unpackedData != data)
{
free(unpackedData);
}
} while (0);
2013-08-12 17:05:19 +08:00
return ret;
}
2013-12-05 17:19:01 +08:00
bool Image::isPng(const unsigned char * data, ssize_t dataLen)
2013-07-17 17:12:04 +08:00
{
if (dataLen <= 8)
2013-07-19 15:37:54 +08:00
{
return false;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const unsigned char PNG_SIGNATURE[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
2013-07-17 17:12:04 +08:00
return memcmp(PNG_SIGNATURE, data, sizeof(PNG_SIGNATURE)) == 0;
}
2013-12-05 17:19:01 +08:00
bool Image::isEtc(const unsigned char * data, ssize_t dataLen)
{
2013-08-02 15:01:27 +08:00
return etc1_pkm_is_valid((etc1_byte*)data) ? true : false;
2013-07-17 17:12:04 +08:00
}
2013-08-08 14:11:22 +08:00
2013-12-05 17:19:01 +08:00
bool Image::isS3TC(const unsigned char * data, ssize_t dataLen)
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
S3TCTexHeader *header = (S3TCTexHeader *)data;
2013-08-06 11:19:45 +08:00
if (strncmp(header->fileCode, "DDS", 3) != 0)
2013-08-06 11:19:45 +08:00
{
CCLOG("cocos2d: the file is not a dds file!");
return false;
}
return true;
}
2013-12-05 17:19:01 +08:00
bool Image::isATITC(const unsigned char *data, ssize_t dataLen)
{
ATITCTexHeader *header = (ATITCTexHeader *)data;
if (strncmp(&header->identifier[1], "KTX", 3) != 0)
{
CCLOG("cocos3d: the file is not a ktx file!");
return false;
}
return true;
}
2013-12-05 17:19:01 +08:00
bool Image::isJpg(const unsigned char * data, ssize_t dataLen)
2013-07-17 17:12:04 +08:00
{
if (dataLen <= 4)
2013-07-19 15:37:54 +08:00
{
return false;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const unsigned char JPG_SOI[] = {0xFF, 0xD8};
2013-07-17 17:12:04 +08:00
return memcmp(data, JPG_SOI, 2) == 0;
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image::isTiff(const unsigned char * data, ssize_t dataLen)
2013-07-17 17:12:04 +08:00
{
if (dataLen <= 4)
2013-07-19 15:37:54 +08:00
{
return false;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const char* TIFF_II = "II";
static const char* TIFF_MM = "MM";
2013-07-17 17:12:04 +08:00
2013-08-06 16:14:36 +08:00
return (memcmp(data, TIFF_II, 2) == 0 && *(static_cast<const unsigned char*>(data) + 2) == 42 && *(static_cast<const unsigned char*>(data) + 3) == 0) ||
(memcmp(data, TIFF_MM, 2) == 0 && *(static_cast<const unsigned char*>(data) + 2) == 0 && *(static_cast<const unsigned char*>(data) + 3) == 42);
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image::isWebp(const unsigned char * data, ssize_t dataLen)
2013-07-17 17:12:04 +08:00
{
if (dataLen <= 12)
2013-07-19 15:37:54 +08:00
{
return false;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const char* WEBP_RIFF = "RIFF";
static const char* WEBP_WEBP = "WEBP";
2013-07-17 17:12:04 +08:00
return memcmp(data, WEBP_RIFF, 4) == 0
2013-08-06 16:14:36 +08:00
&& memcmp(static_cast<const unsigned char*>(data) + 8, WEBP_WEBP, 4) == 0;
}
2013-12-05 17:19:01 +08:00
bool Image::isPvr(const unsigned char * data, ssize_t dataLen)
{
2013-11-13 11:22:34 +08:00
if (static_cast<size_t>(dataLen) < sizeof(PVRv2TexHeader) || static_cast<size_t>(dataLen) < sizeof(PVRv3TexHeader))
{
return false;
}
2013-08-12 17:05:19 +08:00
const PVRv2TexHeader* headerv2 = static_cast<const PVRv2TexHeader*>(static_cast<const void*>(data));
const PVRv3TexHeader* headerv3 = static_cast<const PVRv3TexHeader*>(static_cast<const void*>(data));
return memcmp(&headerv2->pvrTag, gPVRTexIdentifier, strlen(gPVRTexIdentifier)) == 0 || CC_SWAP_INT32_BIG_TO_HOST(headerv3->version) == 0x50565203;
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
Image::Format Image::detectFormat(const unsigned char * data, ssize_t dataLen)
2013-07-17 17:12:04 +08:00
{
if (isPng(data, dataLen))
2013-07-19 15:37:54 +08:00
{
return Format::PNG;
}
else if (isJpg(data, dataLen))
2013-07-19 15:37:54 +08:00
{
return Format::JPG;
}
else if (isTiff(data, dataLen))
2013-07-19 15:37:54 +08:00
{
return Format::TIFF;
}
else if (isWebp(data, dataLen))
2013-07-19 15:37:54 +08:00
{
return Format::WEBP;
}
else if (isPvr(data, dataLen))
2013-07-19 15:37:54 +08:00
{
return Format::PVR;
}
else if (isEtc(data, dataLen))
{
return Format::ETC;
}
else if (isS3TC(data, dataLen))
2013-08-06 11:19:45 +08:00
{
return Format::S3TC;
}
else if (isATITC(data, dataLen))
{
return Format::ATITC;
}
else
{
return Format::UNKOWN;
2013-07-19 15:37:54 +08:00
}
2013-07-17 17:12:04 +08:00
}
int Image::getBitPerPixel()
{
return Texture2D::getPixelFormatInfoMap().at(_renderFormat).bpp;
}
bool Image::hasAlpha()
{
return Texture2D::getPixelFormatInfoMap().at(_renderFormat).alpha;
}
bool Image::isCompressed()
{
return Texture2D::getPixelFormatInfoMap().at(_renderFormat).compressed;
}
2013-08-06 16:14:36 +08:00
namespace
{
/*
* ERROR HANDLING:
*
* The JPEG library's standard error handler (jerror.c) is divided into
* several "methods" which you can override individually. This lets you
* adjust the behavior without duplicating a lot of code, which you might
* have to update with each future release.
*
* We override the "error_exit" method so that control is returned to the
* library's caller when a fatal error occurs, rather than calling exit()
* as the standard error_exit method does.
*
* We use C's setjmp/longjmp facility to return control. This means that the
* routine which calls the JPEG library must first execute a setjmp() call to
* establish the return point. We want the replacement error_exit to do a
* longjmp(). But we need to make the setjmp buffer accessible to the
* error_exit routine. To do this, we make a private extension of the
* standard JPEG error handler object. (If we were using C++, we'd say we
* were making a subclass of the regular error handler.)
*
* Here's the extended error handler struct:
*/
2013-08-06 16:14:36 +08:00
struct MyErrorMgr
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct MyErrorMgr * MyErrorPtr;
2013-08-06 16:14:36 +08:00
/*
* Here's the routine that will replace the standard error_exit method:
*/
2013-08-06 16:14:36 +08:00
METHODDEF(void)
myErrorExit(j_common_ptr cinfo)
{
/* cinfo->err really points to a MyErrorMgr struct, so coerce pointer */
MyErrorPtr myerr = (MyErrorPtr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
/* internal message function cann't show error message in some platforms, so we rewrite it here.
* edit it if has version confilict.
*/
//(*cinfo->err->output_message) (cinfo);
char buffer[JMSG_LENGTH_MAX];
(*cinfo->err->format_message) (cinfo, buffer);
CCLOG("jpeg error: %s", buffer);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
}
2013-12-05 17:19:01 +08:00
bool Image::initWithJpgData(const unsigned char * data, ssize_t dataLen)
{
/* these are standard libjpeg structures for reading(decompression) */
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
2013-08-06 16:14:36 +08:00
struct MyErrorMgr jerr;
/* libjpeg data structure for storing one row, that is, scanline of an image */
JSAMPROW row_pointer[1] = {0};
unsigned long location = 0;
unsigned int i = 0;
bool bRet = false;
do
{
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
2013-08-06 16:14:36 +08:00
jerr.pub.error_exit = myErrorExit;
/* Establish the setjmp return context for MyErrorExit to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
break;
}
/* setup decompression process and source, then read JPEG header */
jpeg_create_decompress( &cinfo );
#ifndef CC_TARGET_QT5
2013-08-12 17:05:19 +08:00
jpeg_mem_src( &cinfo, const_cast<unsigned char*>(data), dataLen );
#endif /* CC_TARGET_QT5 */
/* reading the image header which contains image information */
2013-05-07 13:28:13 +08:00
#if (JPEG_LIB_VERSION >= 90)
// libjpeg 0.9 adds stricter types.
jpeg_read_header( &cinfo, TRUE );
#else
jpeg_read_header( &cinfo, true );
2013-05-07 13:28:13 +08:00
#endif
// we only support RGB or grayscale
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
{
_renderFormat = Texture2D::PixelFormat::I8;
2013-07-19 15:37:54 +08:00
}else
{
cinfo.out_color_space = JCS_RGB;
_renderFormat = Texture2D::PixelFormat::RGB888;
}
/* Start decompression jpeg here */
jpeg_start_decompress( &cinfo );
/* init image info */
2013-08-12 17:05:19 +08:00
_width = cinfo.output_width;
_height = cinfo.output_height;
_preMulti = false;
2013-11-29 15:13:16 +08:00
row_pointer[0] = static_cast<unsigned char*>(malloc(cinfo.output_width*cinfo.output_components * sizeof(unsigned char)));
CC_BREAK_IF(! row_pointer[0]);
_dataLen = cinfo.output_width*cinfo.output_height*cinfo.output_components;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2014-04-13 06:13:58 +08:00
CC_BREAK_IF(! _data);
/* now actually read the jpeg into the raw buffer */
/* read one scan line at a time */
while( cinfo.output_scanline < cinfo.output_height )
{
jpeg_read_scanlines( &cinfo, row_pointer, 1 );
for( i=0; i<cinfo.output_width*cinfo.output_components;i++)
{
_data[location++] = row_pointer[0][i];
}
}
/* When read image file with broken data, jpeg_finish_decompress() may cause error.
* Besides, jpeg_destroy_decompress() shall deallocate and release all memory associated
* with the decompression object.
* So it doesn't need to call jpeg_finish_decompress().
*/
//jpeg_finish_decompress( &cinfo );
jpeg_destroy_decompress( &cinfo );
/* wrap up decompression, destroy objects, free pointers and close open files */
bRet = true;
} while (0);
2013-11-29 15:13:16 +08:00
if (row_pointer[0] != nullptr)
{
free(row_pointer[0]);
};
return bRet;
}
2013-12-05 17:19:01 +08:00
bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen)
{
2013-07-19 15:37:54 +08:00
// length of bytes to check if it is a valid png file
#define PNGSIGSIZE 8
bool bRet = false;
png_byte header[PNGSIGSIZE] = {0};
png_structp png_ptr = 0;
png_infop info_ptr = 0;
do
{
// png header len is 8 bytes
CC_BREAK_IF(dataLen < PNGSIGSIZE);
// check the data is png or not
memcpy(header, data, PNGSIGSIZE);
CC_BREAK_IF(png_sig_cmp(header, 0, PNGSIGSIZE));
// init png_struct
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
CC_BREAK_IF(! png_ptr);
// init png_info
info_ptr = png_create_info_struct(png_ptr);
CC_BREAK_IF(!info_ptr);
2013-03-02 01:09:58 +08:00
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA && CC_TARGET_PLATFORM != CC_PLATFORM_NACL)
CC_BREAK_IF(setjmp(png_jmpbuf(png_ptr)));
#endif
// set the read call back function
tImageSource imageSource;
imageSource.data = (unsigned char*)data;
imageSource.size = dataLen;
imageSource.offset = 0;
png_set_read_fn(png_ptr, &imageSource, pngReadCallback);
// read png header info
2013-07-19 15:37:54 +08:00
// read png file info
png_read_info(png_ptr, info_ptr);
2013-07-19 15:37:54 +08:00
_width = png_get_image_width(png_ptr, info_ptr);
_height = png_get_image_height(png_ptr, info_ptr);
png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);
2012-08-29 21:50:09 +08:00
//CCLOG("color type %u", color_type);
2013-07-19 15:37:54 +08:00
2012-07-24 16:43:48 +08:00
// force palette images to be expanded to 24-bit RGB
// it may include alpha channel
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_palette_to_rgb(png_ptr);
}
// low-bit-depth grayscale images are to be expanded to 8 bits
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
2012-07-24 16:43:48 +08:00
{
bit_depth = 8;
2012-07-26 11:42:31 +08:00
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
2012-07-24 16:43:48 +08:00
// expand any tRNS chunk data into a full alpha channel
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
}
// reduce images with 16-bit samples to 8 bits
if (bit_depth == 16)
{
2012-07-24 16:43:48 +08:00
png_set_strip_16(png_ptr);
}
2013-07-17 17:12:04 +08:00
// Expanded earlier for grayscale, now take care of palette and rgb
if (bit_depth < 8) {
2013-07-19 15:37:54 +08:00
png_set_packing(png_ptr);
}
// update info
png_read_update_info(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
2013-07-19 15:37:54 +08:00
color_type = png_get_color_type(png_ptr, info_ptr);
switch (color_type)
{
case PNG_COLOR_TYPE_GRAY:
_renderFormat = Texture2D::PixelFormat::I8;
break;
2013-07-19 15:37:54 +08:00
case PNG_COLOR_TYPE_GRAY_ALPHA:
_renderFormat = Texture2D::PixelFormat::AI88;
2013-07-19 15:37:54 +08:00
break;
case PNG_COLOR_TYPE_RGB:
_renderFormat = Texture2D::PixelFormat::RGB888;
break;
2013-07-19 15:37:54 +08:00
case PNG_COLOR_TYPE_RGB_ALPHA:
_renderFormat = Texture2D::PixelFormat::RGBA8888;
2013-07-19 15:37:54 +08:00
break;
default:
break;
}
// read png data
2013-12-06 16:32:06 +08:00
png_size_t rowbytes;
png_bytep* row_pointers = (png_bytep*)malloc( sizeof(png_bytep) * _height );
2013-07-19 15:37:54 +08:00
2012-07-24 16:43:48 +08:00
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
2013-07-19 15:37:54 +08:00
_dataLen = rowbytes * _height;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2014-04-13 06:13:58 +08:00
if(!_data)
{
if (row_pointers != nullptr)
{
free(row_pointers);
}
break;
}
2013-07-19 15:37:54 +08:00
for (unsigned short i = 0; i < _height; ++i)
{
row_pointers[i] = _data + i*rowbytes;
2012-07-24 16:43:48 +08:00
}
png_read_image(png_ptr, row_pointers);
2013-07-19 15:37:54 +08:00
png_read_end(png_ptr, nullptr);
2013-07-19 15:37:54 +08:00
// premultiplied alpha for RGBA8888
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
premultipliedAlpha();
}
else
{
_preMulti = false;
}
2012-07-24 16:43:48 +08:00
2013-11-29 15:13:16 +08:00
if (row_pointers != nullptr)
{
free(row_pointers);
2014-04-13 06:13:58 +08:00
}
2012-07-26 11:42:31 +08:00
2012-07-24 16:43:48 +08:00
bRet = true;
} while (0);
if (png_ptr)
{
png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0);
}
return bRet;
}
namespace
{
2013-08-06 16:14:36 +08:00
static tmsize_t tiffReadProc(thandle_t fd, void* buf, tmsize_t size)
{
2013-08-06 16:14:36 +08:00
tImageSource* isource = (tImageSource*)fd;
uint8* ma;
uint64 mb;
unsigned long n;
unsigned long o;
tmsize_t p;
ma=(uint8*)buf;
mb=size;
p=0;
while (mb>0)
{
2013-08-06 16:14:36 +08:00
n=0x80000000UL;
if ((uint64)n>mb)
n=(unsigned long)mb;
if((int)(isource->offset + n) <= isource->size)
{
memcpy(ma, isource->data+isource->offset, n);
isource->offset += n;
o = n;
}
else
{
return 0;
}
ma+=o;
mb-=o;
p+=o;
if (o!=n)
{
break;
}
}
2013-08-06 16:14:36 +08:00
return p;
}
2013-08-06 16:14:36 +08:00
static tmsize_t tiffWriteProc(thandle_t fd, void* buf, tmsize_t size)
{
2013-08-06 16:14:36 +08:00
CC_UNUSED_PARAM(fd);
CC_UNUSED_PARAM(buf);
CC_UNUSED_PARAM(size);
return 0;
}
static uint64 tiffSeekProc(thandle_t fd, uint64 off, int whence)
{
tImageSource* isource = (tImageSource*)fd;
uint64 ret = -1;
do
{
2013-08-06 16:14:36 +08:00
if (whence == SEEK_SET)
{
CC_BREAK_IF(off >= (uint64)isource->size);
ret = isource->offset = (uint32)off;
}
else if (whence == SEEK_CUR)
{
CC_BREAK_IF(isource->offset + off >= (uint64)isource->size);
ret = isource->offset += (uint32)off;
}
else if (whence == SEEK_END)
{
CC_BREAK_IF(off >= (uint64)isource->size);
ret = isource->offset = (uint32)(isource->size-1 - off);
}
else
{
CC_BREAK_IF(off >= (uint64)isource->size);
ret = isource->offset = (uint32)off;
}
} while (0);
return ret;
}
2013-08-06 16:14:36 +08:00
static uint64 tiffSizeProc(thandle_t fd)
{
tImageSource* pImageSrc = (tImageSource*)fd;
return pImageSrc->size;
}
static int tiffCloseProc(thandle_t fd)
{
CC_UNUSED_PARAM(fd);
return 0;
}
static int tiffMapProc(thandle_t fd, void** pbase, toff_t* psize)
{
CC_UNUSED_PARAM(fd);
CC_UNUSED_PARAM(pbase);
CC_UNUSED_PARAM(psize);
return 0;
}
static void tiffUnmapProc(thandle_t fd, void* base, toff_t size)
{
CC_UNUSED_PARAM(fd);
CC_UNUSED_PARAM(base);
CC_UNUSED_PARAM(size);
}
}
2013-12-05 17:19:01 +08:00
bool Image::initWithTiffData(const unsigned char * data, ssize_t dataLen)
{
bool bRet = false;
do
{
// set the read call back function
tImageSource imageSource;
2013-08-12 17:05:19 +08:00
imageSource.data = data;
imageSource.size = dataLen;
imageSource.offset = 0;
TIFF* tif = TIFFClientOpen("file.tif", "r", (thandle_t)&imageSource,
2013-08-06 16:14:36 +08:00
tiffReadProc, tiffWriteProc,
tiffSeekProc, tiffCloseProc, tiffSizeProc,
tiffMapProc,
tiffUnmapProc);
CC_BREAK_IF(nullptr == tif);
uint32 w = 0, h = 0;
uint16 bitsPerSample = 0, samplePerPixel = 0, planarConfig = 0;
size_t npixels = 0;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplePerPixel);
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarConfig);
npixels = w * h;
_renderFormat = Texture2D::PixelFormat::RGBA8888;
_width = w;
_height = h;
_dataLen = npixels * sizeof (uint32);
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
uint32* raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != nullptr)
{
if (TIFFReadRGBAImageOriented(tif, w, h, raster, ORIENTATION_TOPLEFT, 0))
{
/* the raster data is pre-multiplied by the alpha component
after invoking TIFFReadRGBAImageOriented*/
_preMulti = true;
memcpy(_data, raster, npixels*sizeof (uint32));
}
_TIFFfree(raster);
}
TIFFClose(tif);
bRet = true;
} while (0);
return bRet;
}
2013-08-06 16:14:36 +08:00
namespace
{
2013-08-06 16:14:36 +08:00
bool testFormatForPvr2TCSupport(PVR2TexturePixelFormat format)
{
2013-08-06 16:14:36 +08:00
if (!Configuration::getInstance()->supportsPVRTC())
{
2013-08-06 16:14:36 +08:00
if (format == PVR2TexturePixelFormat::PVRTC2BPP_RGBA ||
format == PVR2TexturePixelFormat::PVRTC4BPP_RGBA)
{
return false;
}
}
2013-08-06 16:14:36 +08:00
return true;
}
2013-08-06 16:14:36 +08:00
bool testFormatForPvr3TCSupport(PVR3TexturePixelFormat format)
{
if (!Configuration::getInstance()->supportsPVRTC())
{
if (format == PVR3TexturePixelFormat::PVRTC2BPP_RGB ||
format == PVR3TexturePixelFormat::PVRTC2BPP_RGBA ||
format == PVR3TexturePixelFormat::PVRTC4BPP_RGB ||
format == PVR3TexturePixelFormat::PVRTC4BPP_RGBA)
{
return false;
}
}
return true;
}
}
2013-12-05 17:19:01 +08:00
bool Image::initWithPVRv2Data(const unsigned char * data, ssize_t dataLen)
{
int dataLength = 0, dataOffset = 0, dataSize = 0;
int blockSize = 0, widthBlocks = 0, heightBlocks = 0;
int width = 0, height = 0;
//Cast first sizeof(PVRTexHeader) bytes of data stream as PVRTexHeader
2013-08-12 17:05:19 +08:00
const PVRv2TexHeader *header = static_cast<const PVRv2TexHeader *>(static_cast<const void*>(data));
//Make sure that tag is in correct formatting
2013-08-06 16:14:36 +08:00
if (memcmp(&header->pvrTag, gPVRTexIdentifier, strlen(gPVRTexIdentifier)) != 0)
{
return false;
}
Configuration *configuration = Configuration::getInstance();
_hasPremultipliedAlpha = false;
2013-08-06 16:14:36 +08:00
unsigned int flags = CC_SWAP_INT32_LITTLE_TO_HOST(header->flags);
PVR2TexturePixelFormat formatFlags = static_cast<PVR2TexturePixelFormat>(flags & PVR_TEXTURE_FLAG_TYPE_MASK);
bool flipped = (flags & (unsigned int)PVR2TextureFlag::VerticalFlip) ? true : false;
if (flipped)
{
CCLOG("cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool");
}
if (! configuration->supportsNPOT() &&
2013-12-27 15:06:16 +08:00
(static_cast<int>(header->width) != ccNextPOT(header->width)
|| static_cast<int>(header->height) != ccNextPOT(header->height)))
{
CCLOG("cocos2d: ERROR: Loading an NPOT texture (%dx%d) but is not supported on this device", header->width, header->height);
return false;
}
2013-08-06 16:14:36 +08:00
if (!testFormatForPvr2TCSupport(formatFlags))
{
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", (int)formatFlags);
return false;
}
if (v2_pixel_formathash.find(formatFlags) == v2_pixel_formathash.end())
{
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", (int)formatFlags);
return false;
}
auto it = Texture2D::getPixelFormatInfoMap().find(v2_pixel_formathash.at(formatFlags));
if (it == Texture2D::getPixelFormatInfoMap().end())
{
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", (int)formatFlags);
return false;
}
_renderFormat = it->first;
//Reset num of mipmaps
_numberOfMipmaps = 0;
//Get size of mipmap
_width = width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width);
_height = height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height);
//Get ptr to where data starts..
dataLength = CC_SWAP_INT32_LITTLE_TO_HOST(header->dataLength);
//Move by size of header
_dataLen = dataLen - sizeof(PVRv2TexHeader);
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
memcpy(_data, (unsigned char*)data + sizeof(PVRv2TexHeader), _dataLen);
// Calculate the data size for each texture level and respect the minimum number of blocks
while (dataOffset < dataLength)
{
switch (formatFlags) {
case PVR2TexturePixelFormat::PVRTC2BPP_RGBA:
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
widthBlocks = width / 8;
heightBlocks = height / 4;
break;
case PVR2TexturePixelFormat::PVRTC4BPP_RGBA:
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
widthBlocks = width / 4;
heightBlocks = height / 4;
break;
case PVR2TexturePixelFormat::BGRA8888:
if (Configuration::getInstance()->supportsBGRA8888() == false)
{
CCLOG("cocos2d: Image. BGRA8888 not supported on this device");
return false;
}
default:
blockSize = 1;
widthBlocks = width;
heightBlocks = height;
break;
}
// Clamp to minimum number of blocks
if (widthBlocks < 2)
{
widthBlocks = 2;
}
if (heightBlocks < 2)
{
heightBlocks = 2;
}
dataSize = widthBlocks * heightBlocks * ((blockSize * it->second.bpp) / 8);
int packetLength = (dataLength - dataOffset);
packetLength = packetLength > dataSize ? dataSize : packetLength;
//Make record to the mipmaps array and increment counter
_mipmaps[_numberOfMipmaps].address = _data + dataOffset;
_mipmaps[_numberOfMipmaps].len = packetLength;
_numberOfMipmaps++;
dataOffset += packetLength;
//Update width and height to the next lower power of two
width = MAX(width >> 1, 1);
height = MAX(height >> 1, 1);
}
return true;
}
2013-12-05 17:19:01 +08:00
bool Image::initWithPVRv3Data(const unsigned char * data, ssize_t dataLen)
{
2013-11-13 11:22:34 +08:00
if (static_cast<size_t>(dataLen) < sizeof(PVRv3TexHeader))
{
return false;
}
2013-08-12 17:05:19 +08:00
const PVRv3TexHeader *header = static_cast<const PVRv3TexHeader *>(static_cast<const void*>(data));
// validate version
if (CC_SWAP_INT32_BIG_TO_HOST(header->version) != 0x50565203)
{
CCLOG("cocos2d: WARNING: pvr file version mismatch");
return false;
}
// parse pixel format
2013-08-06 16:14:36 +08:00
PVR3TexturePixelFormat pixelFormat = static_cast<PVR3TexturePixelFormat>(header->pixelFormat);
2013-08-06 16:14:36 +08:00
if (!testFormatForPvr3TCSupport(pixelFormat))
{
2013-08-06 16:14:36 +08:00
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant",
static_cast<unsigned long long>(pixelFormat));
return false;
}
if (v3_pixel_formathash.find(pixelFormat) == v3_pixel_formathash.end())
{
2013-08-06 16:14:36 +08:00
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant",
static_cast<unsigned long long>(pixelFormat));
return false;
}
auto it = Texture2D::getPixelFormatInfoMap().find(v3_pixel_formathash.at(pixelFormat));
if (it == Texture2D::getPixelFormatInfoMap().end())
{
2013-08-06 16:14:36 +08:00
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant",
static_cast<unsigned long long>(pixelFormat));
return false;
}
_renderFormat = it->first;
// flags
int flags = CC_SWAP_INT32_LITTLE_TO_HOST(header->flags);
// PVRv3 specifies premultiply alpha in a flag -- should always respect this in PVRv3 files
if (flags & (unsigned int)PVR3TextureFlag::PremultipliedAlpha)
{
_preMulti = true;
}
// sizing
int width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width);
int height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height);
_width = width;
_height = height;
int dataOffset = 0, dataSize = 0;
int blockSize = 0, widthBlocks = 0, heightBlocks = 0;
_dataLen = dataLen - (sizeof(PVRv3TexHeader) + header->metadataLength);
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-06 16:14:36 +08:00
memcpy(_data, static_cast<const unsigned char*>(data) + sizeof(PVRv3TexHeader) + header->metadataLength, _dataLen);
_numberOfMipmaps = header->numberOfMipmaps;
CCAssert(_numberOfMipmaps < MIPMAP_MAX, "Image: Maximum number of mimpaps reached. Increate the CC_MIPMAP_MAX value");
for (int i = 0; i < _numberOfMipmaps; i++)
{
switch ((PVR3TexturePixelFormat)pixelFormat)
{
case PVR3TexturePixelFormat::PVRTC2BPP_RGB :
case PVR3TexturePixelFormat::PVRTC2BPP_RGBA :
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
widthBlocks = width / 8;
heightBlocks = height / 4;
break;
case PVR3TexturePixelFormat::PVRTC4BPP_RGB :
case PVR3TexturePixelFormat::PVRTC4BPP_RGBA :
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
widthBlocks = width / 4;
heightBlocks = height / 4;
break;
case PVR3TexturePixelFormat::BGRA8888:
if( ! Configuration::getInstance()->supportsBGRA8888())
{
CCLOG("cocos2d: Image. BGRA8888 not supported on this device");
return false;
}
default:
blockSize = 1;
widthBlocks = width;
heightBlocks = height;
break;
}
// Clamp to minimum number of blocks
if (widthBlocks < 2)
{
widthBlocks = 2;
}
if (heightBlocks < 2)
{
heightBlocks = 2;
}
dataSize = widthBlocks * heightBlocks * ((blockSize * it->second.bpp) / 8);
2013-12-05 17:19:01 +08:00
auto packetLength = _dataLen - dataOffset;
packetLength = packetLength > dataSize ? dataSize : packetLength;
_mipmaps[i].address = _data + dataOffset;
2013-12-06 16:32:06 +08:00
_mipmaps[i].len = static_cast<int>(packetLength);
dataOffset += packetLength;
CCAssert(dataOffset <= _dataLen, "CCTexurePVR: Invalid lenght");
width = MAX(width >> 1, 1);
height = MAX(height >> 1, 1);
}
return true;
}
2013-12-05 17:19:01 +08:00
bool Image::initWithETCData(const unsigned char * data, ssize_t dataLen)
{
2013-08-06 16:14:36 +08:00
const etc1_byte* header = static_cast<const etc1_byte*>(data);
//check the data
if(!etc1_pkm_is_valid(header))
{
return false;
}
_width = etc1_pkm_get_width(header);
_height = etc1_pkm_get_height(header);
if( 0 == _width || 0 == _height )
{
return false;
}
if(Configuration::getInstance()->supportsETC())
{
//old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy.
#ifdef GL_ETC1_RGB8_OES
_renderFormat = Texture2D::PixelFormat::ETC;
_dataLen = dataLen - ETC_PKM_HEADER_SIZE;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-06 16:14:36 +08:00
memcpy(_data, static_cast<const unsigned char*>(data) + ETC_PKM_HEADER_SIZE, _dataLen);
return true;
#endif
}
else
{
CCLOG("cocos2d: Hardware ETC1 decoder not present. Using software decoder");
//if it is not gles or device do not support ETC, decode texture by software
int bytePerPixel = 3;
unsigned int stride = _width * bytePerPixel;
_renderFormat = Texture2D::PixelFormat::RGB888;
_dataLen = _width * _height * bytePerPixel;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-06 16:14:36 +08:00
if (etc1_decode_image(static_cast<const unsigned char*>(data) + ETC_PKM_HEADER_SIZE, static_cast<etc1_byte*>(_data), _width, _height, bytePerPixel, stride) != 0)
{
_dataLen = 0;
2013-11-29 15:13:16 +08:00
if (_data != nullptr)
{
free(_data);
}
return false;
}
return true;
}
return false;
}
bool Image::initWithTGAData(tImageTGA* tgaData)
{
bool ret = false;
do
{
CC_BREAK_IF(tgaData == nullptr);
// tgaLoadBuffer only support type 2, 3, 10
if (2 == tgaData->type || 10 == tgaData->type)
{
// true color
// unsupport RGB555
if (tgaData->pixelDepth == 16)
{
_renderFormat = Texture2D::PixelFormat::RGB5A1;
}
else if(tgaData->pixelDepth == 24)
{
_renderFormat = Texture2D::PixelFormat::RGB888;
}
else if(tgaData->pixelDepth == 32)
{
_renderFormat = Texture2D::PixelFormat::RGBA8888;
}
else
{
CCLOG("Image WARNING: unsupport true color tga data pixel format. FILE: %s", _filePath.c_str());
break;
}
}
else if(3 == tgaData->type)
{
// gray
if (8 == tgaData->pixelDepth)
{
_renderFormat = Texture2D::PixelFormat::I8;
}
else
{
// actually this won't happen, if it happens, maybe the image file is not a tga
CCLOG("Image WARNING: unsupport gray tga data pixel format. FILE: %s", _filePath.c_str());
break;
}
}
_width = tgaData->width;
_height = tgaData->height;
_data = tgaData->imageData;
_dataLen = _width * _height * tgaData->pixelDepth / 8;
_fileType = Format::TGA;
2014-06-03 16:22:50 +08:00
_preMulti = false;
ret = true;
}while(false);
if (ret)
{
const unsigned char tgaSuffix[] = ".tga";
for(int i = 0; i < 4; ++i)
{
if (tolower(_filePath[_filePath.length() - i - 1]) != tgaSuffix[3 - i])
{
CCLOG("Image WARNING: the image file suffix is not tga, but parsed as a tga image file. FILE: %s", _filePath.c_str());
break;
};
}
}
else
{
2014-04-09 20:41:09 +08:00
if (tgaData && tgaData->imageData != nullptr)
{
free(tgaData->imageData);
_data = nullptr;
}
}
return ret;
}
2013-08-09 12:54:05 +08:00
namespace
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
static const uint32_t makeFourCC(char ch0, char ch1, char ch2, char ch3)
{
const uint32_t fourCC = ((uint32_t)(char)(ch0) | ((uint32_t)(char)(ch1) << 8) | ((uint32_t)(char)(ch2) << 16) | ((uint32_t)(char)(ch3) << 24 ));
return fourCC;
}
2013-08-06 11:19:45 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image::initWithS3TCData(const unsigned char * data, ssize_t dataLen)
2013-08-06 11:19:45 +08:00
{
2013-08-07 16:39:05 +08:00
const uint32_t FOURCC_DXT1 = makeFourCC('D', 'X', 'T', '1');
const uint32_t FOURCC_DXT3 = makeFourCC('D', 'X', 'T', '3');
const uint32_t FOURCC_DXT5 = makeFourCC('D', 'X', 'T', '5');
2013-08-06 11:19:45 +08:00
/* load the .dds file */
2013-08-09 12:54:05 +08:00
S3TCTexHeader *header = (S3TCTexHeader *)data;
2013-11-29 15:13:16 +08:00
unsigned char *pixelData = static_cast<unsigned char*>(malloc((dataLen - sizeof(S3TCTexHeader)) * sizeof(unsigned char)));
2013-08-12 17:05:19 +08:00
memcpy((void *)pixelData, data + sizeof(S3TCTexHeader), dataLen - sizeof(S3TCTexHeader));
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
_width = header->ddsd.width;
_height = header->ddsd.height;
_numberOfMipmaps = MAX(1, header->ddsd.DUMMYUNIONNAMEN2.mipMapCount); //if dds header reports 0 mipmaps, set to 1 to force correct software decoding (if needed).
_dataLen = 0;
2013-08-09 12:54:05 +08:00
int blockSize = (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) ? 8 : 16;
2013-08-07 16:39:05 +08:00
/* calculate the dataLen */
2013-08-06 11:19:45 +08:00
int width = _width;
int height = _height;
2013-08-09 12:54:05 +08:00
if (Configuration::getInstance()->supportsS3TC()) //compressed data length
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
_dataLen = dataLen - sizeof(S3TCTexHeader);
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-09 12:54:05 +08:00
memcpy((void *)_data,(void *)pixelData , _dataLen);
}
else //decompressed data length
2013-08-06 11:19:45 +08:00
{
2013-09-08 11:26:38 +08:00
for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
2013-08-06 11:19:45 +08:00
{
if (width == 0) width = 1;
if (height == 0) height = 1;
_dataLen += (height * width *4);
width >>= 1;
height >>= 1;
}
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-06 11:19:45 +08:00
}
/* if hardware supports s3tc, set pixelformat before loading mipmaps, to support non-mipmapped textures */
if (Configuration::getInstance()->supportsS3TC())
{ //decode texture throught hardware
if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
{
_renderFormat = Texture2D::PixelFormat::S3TC_DXT1;
}
else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
{
_renderFormat = Texture2D::PixelFormat::S3TC_DXT3;
}
else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
{
_renderFormat = Texture2D::PixelFormat::S3TC_DXT5;
}
} else { //will software decode
_renderFormat = Texture2D::PixelFormat::RGBA8888;
}
2013-08-06 11:19:45 +08:00
/* load the mipmaps */
2013-08-07 16:39:05 +08:00
2013-08-09 14:37:47 +08:00
int encodeOffset = 0;
int decodeOffset = 0;
2013-08-09 12:54:05 +08:00
width = _width; height = _height;
2013-08-06 11:19:45 +08:00
2013-09-08 11:26:38 +08:00
for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
2013-08-06 11:19:45 +08:00
{
if (width == 0) width = 1;
if (height == 0) height = 1;
int size = ((width+3)/4)*((height+3)/4)*blockSize;
if (Configuration::getInstance()->supportsS3TC())
2013-08-07 16:39:05 +08:00
{ //decode texture throught hardware
2013-08-09 14:37:47 +08:00
_mipmaps[i].address = (unsigned char *)_data + encodeOffset;
2013-08-06 11:19:45 +08:00
_mipmaps[i].len = size;
}
else
2013-08-07 16:39:05 +08:00
{ //if it is not gles or device do not support S3TC, decode texture by software
CCLOG("cocos2d: Hardware S3TC decoder not present. Using software decoder");
2013-08-06 11:19:45 +08:00
int bytePerPixel = 4;
unsigned int stride = width * bytePerPixel;
std::vector<unsigned char> decodeImageData(stride * height);
2013-08-09 12:54:05 +08:00
if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT1);
2013-08-06 11:19:45 +08:00
}
2013-08-09 12:54:05 +08:00
else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT3);
2013-08-06 11:19:45 +08:00
}
2013-08-09 12:54:05 +08:00
else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT5);
2013-08-06 11:19:45 +08:00
}
2013-08-09 14:37:47 +08:00
_mipmaps[i].address = (unsigned char *)_data + decodeOffset;
2013-08-06 11:19:45 +08:00
_mipmaps[i].len = (stride * height);
memcpy((void *)_mipmaps[i].address, (void *)&decodeImageData[0], _mipmaps[i].len);
2013-08-09 14:37:47 +08:00
decodeOffset += stride * height;
2013-08-06 11:19:45 +08:00
}
2013-08-09 15:00:26 +08:00
encodeOffset += size;
2013-08-06 11:19:45 +08:00
width >>= 1;
height >>= 1;
}
2013-08-07 16:39:05 +08:00
/* end load the mipmaps */
2013-11-29 15:13:16 +08:00
if (pixelData != nullptr)
{
free(pixelData);
};
2013-08-06 11:19:45 +08:00
return true;
}
2013-08-16 14:27:13 +08:00
2013-12-05 17:19:01 +08:00
bool Image::initWithATITCData(const unsigned char *data, ssize_t dataLen)
{
/* load the .ktx file */
ATITCTexHeader *header = (ATITCTexHeader *)data;
_width = header->pixelWidth;
_height = header->pixelHeight;
_numberOfMipmaps = header->numberOfMipmapLevels;
int blockSize = 0;
switch (header->glInternalFormat)
{
case CC_GL_ATC_RGB_AMD:
blockSize = 8;
break;
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
blockSize = 16;
break;
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
blockSize = 16;
break;
default:
break;
}
/* pixelData point to the compressed data address */
unsigned char *pixelData = (unsigned char *)data + sizeof(ATITCTexHeader) + header->bytesOfKeyValueData + 4;
/* caculate the dataLen */
int width = _width;
int height = _height;
if (Configuration::getInstance()->supportsATITC()) //compressed data length
{
_dataLen = dataLen - sizeof(ATITCTexHeader) - header->bytesOfKeyValueData - 4;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
memcpy((void *)_data,(void *)pixelData , _dataLen);
}
else //decompressed data length
{
2013-09-08 11:26:38 +08:00
for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
{
if (width == 0) width = 1;
if (height == 0) height = 1;
_dataLen += (height * width *4);
width >>= 1;
height >>= 1;
}
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
}
/* load the mipmaps */
int encodeOffset = 0;
int decodeOffset = 0;
width = _width; height = _height;
2013-09-08 11:26:38 +08:00
for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
{
if (width == 0) width = 1;
if (height == 0) height = 1;
int size = ((width+3)/4)*((height+3)/4)*blockSize;
if (Configuration::getInstance()->supportsATITC())
{
/* decode texture throught hardware */
CCLOG("this is atitc H decode");
switch (header->glInternalFormat)
{
case CC_GL_ATC_RGB_AMD:
_renderFormat = Texture2D::PixelFormat::ATC_RGB;
break;
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
_renderFormat = Texture2D::PixelFormat::ATC_EXPLICIT_ALPHA;
break;
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
_renderFormat = Texture2D::PixelFormat::ATC_INTERPOLATED_ALPHA;
break;
default:
break;
}
_mipmaps[i].address = (unsigned char *)_data + encodeOffset;
_mipmaps[i].len = size;
}
else
{
/* if it is not gles or device do not support ATITC, decode texture by software */
CCLOG("cocos2d: Hardware ATITC decoder not present. Using software decoder");
int bytePerPixel = 4;
unsigned int stride = width * bytePerPixel;
_renderFormat = Texture2D::PixelFormat::RGBA8888;
std::vector<unsigned char> decodeImageData(stride * height);
switch (header->glInternalFormat)
{
case CC_GL_ATC_RGB_AMD:
atitc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, ATITCDecodeFlag::ATC_RGB);
break;
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
atitc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, ATITCDecodeFlag::ATC_EXPLICIT_ALPHA);
break;
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
atitc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA);
break;
default:
break;
}
_mipmaps[i].address = (unsigned char *)_data + decodeOffset;
_mipmaps[i].len = (stride * height);
memcpy((void *)_mipmaps[i].address, (void *)&decodeImageData[0], _mipmaps[i].len);
decodeOffset += stride * height;
}
encodeOffset += (size + 4);
width >>= 1;
height >>= 1;
}
/* end load the mipmaps */
return true;
}
2013-12-05 17:19:01 +08:00
bool Image::initWithPVRData(const unsigned char * data, ssize_t dataLen)
{
2013-07-29 14:04:51 +08:00
return initWithPVRv2Data(data, dataLen) || initWithPVRv3Data(data, dataLen);
}
2013-12-05 17:19:01 +08:00
bool Image::initWithWebpData(const unsigned char * data, ssize_t dataLen)
{
2014-03-22 20:51:39 +08:00
bool bRet = false;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
CCLOG("WEBP image format not supported on WinRT or WP8");
#else
do
{
WebPDecoderConfig config;
if (WebPInitDecoderConfig(&config) == 0) break;
2013-08-06 16:14:36 +08:00
if (WebPGetFeatures(static_cast<const uint8_t*>(data), dataLen, &config.input) != VP8_STATUS_OK) break;
if (config.input.width == 0 || config.input.height == 0) break;
config.output.colorspace = MODE_RGBA;
_renderFormat = Texture2D::PixelFormat::RGBA8888;
_width = config.input.width;
_height = config.input.height;
_dataLen = _width * _height * 4;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
2013-08-06 16:14:36 +08:00
config.output.u.RGBA.rgba = static_cast<uint8_t*>(_data);
config.output.u.RGBA.stride = _width * 4;
config.output.u.RGBA.size = _dataLen;
config.output.is_external_memory = 1;
2013-08-06 16:14:36 +08:00
if (WebPDecode(static_cast<const uint8_t*>(data), dataLen, &config) != VP8_STATUS_OK)
{
2013-11-29 15:13:16 +08:00
free(_data);
_data = nullptr;
break;
}
bRet = true;
} while (0);
2014-03-22 20:51:39 +08:00
#endif
return bRet;
}
2014-03-22 20:51:39 +08:00
2013-12-05 17:19:01 +08:00
bool Image::initWithRawData(const unsigned char * data, ssize_t dataLen, int width, int height, int bitsPerComponent, bool preMulti)
{
bool bRet = false;
do
{
2013-08-06 16:14:36 +08:00
CC_BREAK_IF(0 == width || 0 == height);
2013-08-06 16:14:36 +08:00
_height = height;
_width = width;
_preMulti = preMulti;
_renderFormat = Texture2D::PixelFormat::RGBA8888;
// only RGBA8888 supported
2013-08-06 16:14:36 +08:00
int bytesPerComponent = 4;
_dataLen = height * width * bytesPerComponent;
2013-11-29 15:13:16 +08:00
_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
CC_BREAK_IF(! _data);
memcpy(_data, data, _dataLen);
bRet = true;
} while (0);
return bRet;
}
2013-08-08 14:11:22 +08:00
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
bool Image::saveToFile(const std::string& filename, bool bIsToRGB)
{
//only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data
if (isCompressed() || (_renderFormat != Texture2D::PixelFormat::RGB888 && _renderFormat != Texture2D::PixelFormat::RGBA8888))
{
CCLOG("cocos2d: Image: saveToFile is only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data for now");
return false;
}
bool bRet = false;
do
{
CC_BREAK_IF(filename.size() <= 4);
std::string strLowerCasePath(filename);
for (unsigned int i = 0; i < strLowerCasePath.length(); ++i)
{
strLowerCasePath[i] = tolower(filename[i]);
}
if (std::string::npos != strLowerCasePath.find(".png"))
{
CC_BREAK_IF(!saveImageToPNG(filename, bIsToRGB));
}
else if (std::string::npos != strLowerCasePath.find(".jpg"))
{
CC_BREAK_IF(!saveImageToJPG(filename));
}
else
{
break;
}
bRet = true;
} while (0);
return bRet;
}
#endif
bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB)
{
bool bRet = false;
do
{
FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
png_colorp palette;
png_bytep *row_pointers;
fp = fopen(filePath.c_str(), "wb");
CC_BREAK_IF(nullptr == fp);
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (nullptr == png_ptr)
{
fclose(fp);
break;
}
info_ptr = png_create_info_struct(png_ptr);
if (nullptr == info_ptr)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, nullptr);
break;
}
2013-03-02 01:09:58 +08:00
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA && CC_TARGET_PLATFORM != CC_PLATFORM_NACL)
if (setjmp(png_jmpbuf(png_ptr)))
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
break;
}
#endif
png_init_io(png_ptr, fp);
2013-08-06 16:14:36 +08:00
if (!isToRGB && hasAlpha())
{
png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else
{
png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
png_write_info(png_ptr, info_ptr);
png_set_packing(png_ptr);
row_pointers = (png_bytep *)malloc(_height * sizeof(png_bytep));
if(row_pointers == nullptr)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
break;
}
if (!hasAlpha())
{
for (int i = 0; i < (int)_height; i++)
{
row_pointers[i] = (png_bytep)_data + i * _width * 3;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = nullptr;
}
else
{
2013-08-06 16:14:36 +08:00
if (isToRGB)
{
unsigned char *pTempData = static_cast<unsigned char*>(malloc(_width * _height * 3 * sizeof(unsigned char)));
if (nullptr == pTempData)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
2014-04-13 06:13:58 +08:00
free(row_pointers);
row_pointers = nullptr;
break;
}
for (int i = 0; i < _height; ++i)
{
for (int j = 0; j < _width; ++j)
{
pTempData[(i * _width + j) * 3] = _data[(i * _width + j) * 4];
pTempData[(i * _width + j) * 3 + 1] = _data[(i * _width + j) * 4 + 1];
pTempData[(i * _width + j) * 3 + 2] = _data[(i * _width + j) * 4 + 2];
}
}
for (int i = 0; i < (int)_height; i++)
{
row_pointers[i] = (png_bytep)pTempData + i * _width * 3;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = nullptr;
2013-11-29 15:13:16 +08:00
if (pTempData != nullptr)
{
free(pTempData);
}
}
else
{
for (int i = 0; i < (int)_height; i++)
{
row_pointers[i] = (png_bytep)_data + i * _width * 4;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = nullptr;
}
}
png_write_end(png_ptr, info_ptr);
png_free(png_ptr, palette);
palette = nullptr;
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
bRet = true;
} while (0);
return bRet;
}
bool Image::saveImageToJPG(const std::string& filePath)
{
bool bRet = false;
do
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
CC_BREAK_IF((outfile = fopen(filePath.c_str(), "wb")) == nullptr);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = _width; /* image width and height, in pixels */
cinfo.image_height = _height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 90, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = _width * 3; /* JSAMPLEs per row in image_buffer */
if (hasAlpha())
{
2013-11-29 15:13:16 +08:00
unsigned char *pTempData = static_cast<unsigned char*>(malloc(_width * _height * 3 * sizeof(unsigned char)));
if (nullptr == pTempData)
{
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(outfile);
break;
}
for (int i = 0; i < _height; ++i)
{
for (int j = 0; j < _width; ++j)
{
pTempData[(i * _width + j) * 3] = _data[(i * _width + j) * 4];
pTempData[(i * _width + j) * 3 + 1] = _data[(i * _width + j) * 4 + 1];
pTempData[(i * _width + j) * 3 + 2] = _data[(i * _width + j) * 4 + 2];
}
}
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & pTempData[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
2013-11-29 15:13:16 +08:00
if (pTempData != nullptr)
{
free(pTempData);
}
}
else
{
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & _data[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
bRet = true;
} while (0);
return bRet;
}
void Image::premultipliedAlpha()
{
2014-06-03 16:22:50 +08:00
CCASSERT(_renderFormat == Texture2D::PixelFormat::RGBA8888, "The pixel format should be RGBA8888!");
2014-06-03 15:19:01 +08:00
unsigned int* fourBytes = (unsigned int*)_data;
for(int i = 0; i < _width * _height; i++)
{
unsigned char* p = _data + i * 4;
fourBytes[i] = CC_RGB_PREMULTIPLY_ALPHA(p[0], p[1], p[2], p[3]);
}
_preMulti = true;
}
NS_CC_END