Scale Image
A.First Edition
This is a small tool to scale image. For performance reasons, I cannot use floating point calculation, not even
multiplication or division.
1. There is some system limit for windows GDI to createcompatiblebitmap. So, even "halftone" is perfect in scaling image, you
cannot handle large picture.
2. I am required to write program so that it can also run on MAC, so, no system dependent library can be used. Also this is
a rather slow operation, therefore I need to do it faster.
It is like DDD for anti-alias algorithm.
The bit function for mono still not working...
C.Further improvement
delete identical files
// stdafx.h : include file for standard system include files,
#include <windows.h> #include <string.h> #include <stdio.h> #include <TCHAR.h> #include "ijl.h" #include "fileMap.h" #include "jpegScalor.h" #include "md5.h" #pragma comment(lib, "ijl15.lib")
// stdafx.cpp : source file that includes just the standard includes // win32Test.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file
//filename md5.h
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
#define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
void md5_init(md5_state_t *pms);
/* Append a string to the message. */
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
void calculateMD5(const unsigned char *data, int nbytes, unsigned char digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */
//filename md5.cpp
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#include "stdafx.h"
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned */
X = (const md5_word_t *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
{
const md5_byte_t *p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
void calculateMD5(const unsigned char *data, int nbytes, unsigned char digest[16])
{
md5_state_t state;
md5_init(&state);
md5_append(&state, data, nbytes);
md5_finish(&state, digest);
}
//filename filemap.h
#include <windows.h> #include <string.h> #include <stdio.h> #include <TCHAR.h> #include "ijl.h" #include "fileMap.h" #include "jpegScalor.h" #include "md5.h" #pragma comment(lib, "ijl15.lib")
//file name fileMap.cpp
#include "stdafx.h"
HANDLE fileHandle, fileMapHandle;
bool mapFile(const _TCHAR* fileName, LPBYTE& ptr, DWORD& size)
{
if (!(fileHandle = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
{
_tprintf(_T("open file %s failed error %d\n"), fileName, GetLastError());
return false;
}
if (!(fileMapHandle = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL)))
{
_tprintf(_T("create file %s mapping failed error %d\n"), fileName, GetLastError());
CloseHandle(fileHandle);
return false;
}
if (!(ptr = (LPBYTE)MapViewOfFile(fileMapHandle, FILE_MAP_WRITE, 0, 0, 0)))
{
printf("map file %s failed error %d\n", fileName, GetLastError());
CloseHandle(fileHandle);
CloseHandle(fileMapHandle);
return false;
}
size = GetFileSize(fileHandle, NULL);
return true;
}
void unmapFile(LPBYTE ptr)
{
UnmapViewOfFile(ptr);
CloseHandle(fileHandle);
CloseHandle(fileMapHandle);
}
void genericFind(const TCHAR* dir, HandleFileCallBack handleFileCallBack)
{
HANDLE handle;
TCHAR curFileName[MAX_PATH];
TCHAR wildFileName[MAX_PATH];
WIN32_FIND_DATA ffd;
_sntprintf(wildFileName, MAX_PATH, _T("%s\\*.*"), dir);
handle=FindFirstFile(wildFileName, &ffd);
if (handle==INVALID_HANDLE_VALUE)
{
_tprintf(_T("findfirst failed of error code =%d\n"), GetLastError());
exit(19);
}
do
{
if (_tcsicmp(ffd.cFileName, _T("."))!=0 && _tcsicmp(ffd.cFileName, _T(".."))!=0)
{
_stprintf(curFileName, _T("%s\\%s"), dir, ffd.cFileName);
if (GetFileAttributes(curFileName)&FILE_ATTRIBUTE_DIRECTORY)
{
genericFind(curFileName, handleFileCallBack);
}
else
{
handleFileCallBack(curFileName, ffd.cFileName);
}
}
}
while (FindNextFile(handle, &ffd));
FindClose(handle);
}
bool saveFile(const TCHAR* fileName, const char* dest, DWORD size)
{
HANDLE fileHandle = NULL;
DWORD tempSize = 0;
bool result = true;
if (dest == NULL)
{
return false;
}
if ((fileHandle = CreateFile(fileName, GENERIC_WRITE|STANDARD_RIGHTS_ALL, FILE_SHARE_READ,
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
return false;
}
if (!WriteFile(fileHandle, dest, size, &tempSize, NULL))
{
result = false;
}
CloseHandle(fileHandle);
return result;
}
// file name jpegScalor.h
#define JPEG_SUCCESS 0
#define JPEG_FAILURE -1
#define JPEG_ERROR_IJL_INIT 100
#define JPEG_ERROR_IJL_READ_PARAM 101
#define JPEG_ERROR_IJL_WRITE 102
#define JPEG_ERROR_IJL_READ_DATA 104
#define JPEG_ERROR_IJL_FREE 105
#define JPEG_ERROR_INVALID_FORMAT 106
#define JPEG_ERROR_FILE_CREATE 107
#define JPEG_ERROR_FILE_WRITE 108
#define JPEG_ERROR_INVALID_PARAM 109
#define JPEG_ERROR_READ_BITS 110
#define JPEG_ERROR_CREATE_FILE 111
#define JPEG_ERROR_SET_STRETCH 112
#define JPEG_ERROR_UNSUPPORT_FORMAT 113
#define JPEG_ERROR_MEMORY_ALLOC 120
#define LinkStatusInserted 0
#define LinkStatusReading 1
#define LinkStatusFinished 2
#define LinkStatusDead 3
#define LinkStatusImage 4
enum ImageFileFormat
{
Image_File_Format_BMP, Image_File_Format_JPG, Image_File_Format_PNG,
Image_File_Format_TIF, Image_File_Format_GIF, Image_File_Format_UNKNOWN
};
const int DefaultThumbnailSize = 64;
const int DefaultMaxHeight = 500;
int readJpgFile(const char* src, PBITMAPINFO& pbi);
//int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi, LPBYTE lpBits);
int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi);
//int scaleBmp(PBITMAPINFO pbi, LPBYTE& lpNewBits, int width, int height);
int readJpgBuffer(const LPBYTE src, DWORD size, PBITMAPINFO& pbi);
int readBmpBuffer(PBITMAPINFO pbi, LPBYTE& dest, DWORD& size, LPBYTE pbits=NULL);
//int createBmpInfoStruct(const BITMAP& bmp, PBITMAPINFO& pbmi);
int scaleBmp(PBITMAPINFO pbi, int width, int height);
bool mapFile(const _TCHAR* fileName, char*& ptr, DWORD& size);
void unmapFile(char* ptr);
int saveJpgFile(const TCHAR* fileName, const LPBYTE dest, DWORD size);
int scaleTo(const LPBYTE jpgPtr, DWORD jpgSize, int thumbWidth, int thumbHeight,
int& imageWidth, int& imageHeight, LPBYTE& pbits, DWORD& stretchedSize);
int scaleLessThan(const LPBYTE jpgPtr, DWORD jpgSize, int maxHeight, LPBYTE& pbits,
int& stretchedWidth, int& stretchedHeight, DWORD& stretchedSize);
int imageProcess(LPBYTE imagePtr, DWORD imageSize, int maxHeight, int thumbSize,
int& imageWidth, int& imageHeight, int& stretchedWidth, int& stretchedHeight,
LPBYTE& thumbPtr,
LPBYTE& stretchedPtr, DWORD& thumbDataSize, DWORD& stretchedSize);
ImageFileFormat imageFileFormat(const LPBYTE image);
int scaleBmp(PBITMAPINFO pbi, LPBYTE pbits, LPBYTE& lpNewBits, int width, int height);
void saveToFile(TCHAR* fileName);
bool savePictureFile(LPBYTE buffer, DWORD size, FILE* log = NULL);
bool readImageFile(LPCTSTR fileName, PBITMAPINFO& pbi);
// file name jpegScalor.cpp
#include "stdafx.h"
#pragma comment(lib, "Rpcrt4.lib")
const unsigned int MinPictureSize = 50*1024;
int saveCounter = 0;
const BYTE BMP[2] = {0x42, 0x4D};
const BYTE JPG[3]= {0xFF, 0xD8, 0xFF}; //, 0xE0 4A 46 49 46 00 app.
const BYTE PNG[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
const BYTE TIF[4] = {0x4D, 0x4D, 0x00, 0x2A};
const BYTE GIF[6] = {0x47, 0x49, 0x46, 0x38}; //, 0x37, 0x61}; app.
ImageFileFormat imageFileFormat(const LPBYTE image)
{
const BYTE JPG1[4]={0XFF, 0XD8, 0XFF, 0XE1};
const BYTE JPG2[5]={0X45, 0X78, 0X69, 0X66, 0X00};
const BYTE JFIF1[4]={0XFF, 0XD8, 0XFF, 0XE0};
const BYTE JFIF2[5]= {0X4A, 0X46, 0X49, 0X46, 0X00};
if (memcmp(image, BMP, 2) == 0)
{
return Image_File_Format_BMP;
}
if (memcmp(image, JPG1, 4) == 0 && memcmp(image+6, JPG2, 5)== 0)
{
return Image_File_Format_JPG;
}
if (memcmp(image, JFIF1, 4) == 0 && memcmp(image+6, JFIF2, 5)== 0)
{
return Image_File_Format_JPG;
}
if (memcmp(image, PNG, 8) == 0)
{
return Image_File_Format_PNG;
}
if (memcmp(image, TIF, 4) == 0)
{
return Image_File_Format_TIF;
}
if (memcmp(image, GIF, 6) == 0)
{
return Image_File_Format_GIF;
}
return Image_File_Format_UNKNOWN;
}
int imageProcess(LPBYTE imagePtr, DWORD imageSize, int maxHeight, int thumbSize,
int& imageWidth, int& imageHeight, int& stretchedWidth, int& stretchedHeight,
LPBYTE& thumbPtr,
LPBYTE& stretchedPtr, DWORD& thumbDataSize, DWORD& stretchedSize)
{
ImageFileFormat imageFormat = Image_File_Format_JPG;
int result = JPEG_FAILURE;
PBITMAPINFO pbi = NULL;
BITMAPINFO bi;
PBITMAPFILEHEADER pbhi = NULL;
LPBYTE pbits = NULL, bmpInputPtr = NULL, thumbInputPtr = NULL;
memset(&bi, 0, sizeof(BITMAPINFO));
imageFormat = imageFileFormat(imagePtr);
switch (imageFormat)
{
case Image_File_Format_BMP:
pbhi = (PBITMAPFILEHEADER) imagePtr;
pbi = (PBITMAPINFO)(imagePtr + sizeof(BITMAPFILEHEADER));
if (pbi->bmiHeader.biBitCount != 24)
{
result = JPEG_ERROR_UNSUPPORT_FORMAT;
}
else
{
pbits = imagePtr + pbhi->bfOffBits;
imageWidth = pbi->bmiHeader.biWidth;
imageHeight = pbi->bmiHeader.biHeight;
memcpy(&bi, pbi, sizeof(BITMAPINFO));
if (pbi->bmiHeader.biHeight>maxHeight)
{
stretchedHeight = maxHeight;
stretchedWidth = pbi->bmiHeader.biWidth*maxHeight/pbi->bmiHeader.biHeight;
}
else
{
stretchedWidth = pbi->bmiHeader.biWidth;
stretchedHeight = pbi->bmiHeader.biHeight;
}
if ((result = scaleBmp(&bi, pbits, bmpInputPtr, stretchedWidth, stretchedHeight))
== JPEG_SUCCESS)
{
if ((result = readBmpBuffer(&bi, stretchedPtr, stretchedSize, bmpInputPtr))
== JPEG_SUCCESS)
{
if ((result = scaleBmp(&bi, bmpInputPtr, thumbInputPtr, thumbSize, thumbSize))
== JPEG_SUCCESS)
{
result = readBmpBuffer(&bi, thumbPtr, thumbDataSize, thumbInputPtr);
free(thumbInputPtr);
}
if (result != JPEG_SUCCESS)
{
free(stretchedPtr);
}
}
free(bmpInputPtr);
}
}
break;
case Image_File_Format_JPG:
if ((result = scaleTo(imagePtr, imageSize, thumbSize, thumbSize,
imageWidth, imageHeight, thumbPtr, thumbDataSize)) == JPEG_SUCCESS)
{
if ((result = scaleLessThan(imagePtr, imageSize, maxHeight, stretchedPtr,
stretchedWidth, stretchedHeight, stretchedSize)) != JPEG_SUCCESS)
{
free(thumbPtr);
}
}
break;
default:
result = JPEG_ERROR_UNSUPPORT_FORMAT;
break;
}
return result;
}
int scaleLessThan(const LPBYTE jpgPtr, DWORD jpgSize, int maxHeight, LPBYTE& pbits,
int& stretchedWidth, int& stretchedHeight, DWORD& stretchedSize)
{
int result = JPEG_FAILURE;
PBITMAPINFO pbi = NULL;
LPBYTE imagePtr = NULL;
if ((result = readJpgBuffer(jpgPtr, jpgSize, pbi)) == JPEG_SUCCESS)
{
if (pbi->bmiHeader.biHeight > maxHeight)
{
stretchedHeight = maxHeight;
stretchedWidth = pbi->bmiHeader.biWidth * maxHeight / pbi->bmiHeader.biHeight;
}
else
{
stretchedWidth = pbi->bmiHeader.biWidth;
stretchedHeight = pbi->bmiHeader.biHeight;
}
if ((result = scaleBmp(pbi, stretchedWidth, stretchedHeight)) == JPEG_SUCCESS)
{
if ((result = readBmpBuffer(pbi, pbits, stretchedSize)) == JPEG_SUCCESS)
{
result = JPEG_SUCCESS;
}
}
free(pbi);
}
return result;
}
int scaleTo(const LPBYTE jpgPtr, DWORD jpgSize, int thumbWidth, int thumbHeight,
int& imageWidth, int& imageHeight, LPBYTE& pbits, DWORD& stretchedSize)
{
int result = JPEG_FAILURE;
PBITMAPINFO pbi = NULL;
if ((result = readJpgBuffer(jpgPtr, jpgSize, pbi)) == JPEG_SUCCESS)
{
imageWidth = pbi->bmiHeader.biWidth;
imageHeight = pbi->bmiHeader.biHeight;
if ((result = scaleBmp(pbi, thumbWidth, thumbHeight)) == JPEG_SUCCESS)
{
if ((result = readBmpBuffer(pbi, pbits, stretchedSize)) == JPEG_SUCCESS)
{
result = JPEG_SUCCESS;
}
}
free(pbi);
}
return result;
}
int readBmpBuffer(PBITMAPINFO pbi, LPBYTE& dest, DWORD& size, LPBYTE imagePtr)
{
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
PBITMAPINFOHEADER pbhi = NULL;
int colorNumber = 0;
int widthBytes = 0;
int bufferSize = 0;
LPBYTE buffer = NULL;
LPBYTE startPtr = NULL, endPtr = NULL;
LPBYTE pbits = NULL;
if (pbi == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
if ((jerr = ijlInit( &jcprops)) != IJL_OK)
{
return JPEG_ERROR_IJL_INIT;
}
pbhi = &pbi->bmiHeader;
jcprops.DIBWidth = pbhi->biWidth;
jcprops.DIBHeight = pbhi->biHeight;
jcprops.DIBChannels = 3;
jcprops.DIBColor = IJL_BGR;
jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(pbhi->biWidth, 3);
jcprops.JPGWidth = jcprops.DIBWidth;
jcprops.JPGHeight = jcprops.DIBHeight;
jcprops.jquality = 80;
jcprops.JPGChannels = 3;
if (imagePtr == NULL)
{
pbits = (LPBYTE)pbi + pbhi->biSize + colorNumber * sizeof(RGBQUAD);
}
else
{
pbits = imagePtr;
}
widthBytes = ((pbhi->biWidth*pbhi->biBitCount+31) & (~31)) / 8;
switch (pbhi->biBitCount)
{
case 24:
colorNumber = 0;
break;
//ijl doesn't support other than 24 color
default:
ijlFree(&jcprops);
return JPEG_ERROR_UNSUPPORT_FORMAT;
}
/*
case 1:
case 4:
case 8:
jcprops.UseJPEGPROPERTIES = 1;
if (pbhi->biClrUsed == 0)
{
colorNumber = (1 << pbhi->biBitCount);
}
else
{
colorNumber = pbhi->biClrUsed;
}
break;
case 16:
case 32:
jcprops.UseJPEGPROPERTIES = 1;
jcprops.jprops.DIBLineBytes = widthBytes;
colorNumber = 0;
break;
}
*/
bufferSize =pbhi->biHeight * widthBytes;
if ((buffer = (LPBYTE)malloc(bufferSize)) == NULL)
{
ijlFree(&jcprops);
return JPEG_ERROR_MEMORY_ALLOC;
}
for (int i = 0; i < pbhi->biHeight; i ++)
{
startPtr = buffer + i * widthBytes;
endPtr = pbits + (pbhi->biHeight - i - 1) * widthBytes;
memcpy(startPtr, endPtr, widthBytes);
}
jcprops.DIBBytes = buffer;
if ((dest = (LPBYTE)malloc(bufferSize)) == NULL)
{
ijlFree(&jcprops);
free(buffer);
return JPEG_ERROR_MEMORY_ALLOC;
}
jcprops.JPGBytes = dest;
jcprops.JPGSizeBytes = bufferSize;
if ((jerr = ijlWrite(&jcprops, IJL_JBUFF_WRITEWHOLEIMAGE)) != IJL_OK)
{
ijlFree(&jcprops);
free(dest);
free(buffer);
return JPEG_ERROR_IJL_READ_PARAM;
}
free(buffer);
size = jcprops.JPGSizeBytes;
ijlFree(&jcprops);
return JPEG_SUCCESS;
}
int saveJpgFile(const TCHAR* fileName, const LPBYTE dest, DWORD size)
{
HANDLE fileHandle = NULL;
DWORD tempSize = 0;
int result = JPEG_FAILURE;
if (dest == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
if ((fileHandle = CreateFile(fileName, GENERIC_WRITE|STANDARD_RIGHTS_ALL, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
return JPEG_ERROR_CREATE_FILE;
}
if (WriteFile(fileHandle, dest, size, &tempSize, NULL))
{
result = JPEG_SUCCESS;
}
CloseHandle(fileHandle);
return result;
}
int readJpgFile(const char* src, PBITMAPINFO& pbi)
{
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
PBITMAPINFOHEADER pbhi;
int imageSize = 0;;
int bufferSize = 0;
int widthBytes = 0;
LPBYTE pbits = NULL;
int result = JPEG_FAILURE;
if (src == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
if ((jerr = ijlInit( &jcprops)) != IJL_OK)
{
return JPEG_ERROR_IJL_INIT;
}
jcprops.JPGFile = src;
//Read JPEG parameters from the file
if ((jerr = ijlRead(&jcprops, IJL_JFILE_READPARAMS)) == IJL_OK)
{
widthBytes = (jcprops.JPGWidth*3 + 31) & (~31);
imageSize = widthBytes * jcprops.JPGHeight;
bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
if ((pbi = (PBITMAPINFO)malloc(bufferSize)) == NULL)
{
pbhi = (PBITMAPINFOHEADER) pbi;
pbhi->biSize = sizeof(BITMAPINFOHEADER);
pbhi->biPlanes = 1;
pbhi->biClrUsed = 0;
pbhi->biWidth = jcprops.JPGWidth;
pbhi->biHeight = jcprops.JPGHeight;
pbhi->biCompression = BI_RGB;
pbhi->biClrImportant = 0;
pbhi->biBitCount = 24;
pbhi->biXPelsPerMeter= 0;
pbhi->biYPelsPerMeter= 0;
pbhi->biSizeImage = imageSize;
pbits = (LPBYTE)pbi + pbhi->biSize;
//Set up the DIB specification for the JPEG decoder
jcprops.DIBWidth = jcprops.JPGWidth;
jcprops.DIBHeight = -jcprops.JPGHeight; //Implies a bottom-up DIB.
jcprops.DIBChannels = 3; //jcprops.JPGChannels; //3????
jcprops.DIBColor = IJL_BGR;
jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
jcprops.DIBBytes = reinterpret_cast<BYTE*>(pbits);
//jcprops.JPGSizeBytes = imageSize;
if ((jerr = ijlRead(&jcprops, IJL_JFILE_READWHOLEIMAGE)) == IJL_OK)
{
result = JPEG_SUCCESS;
}
else
{
free(pbi);
}
}
}
ijlFree(&jcprops);
return result;
}
int readJpgBuffer(const LPBYTE src, DWORD size, PBITMAPINFO& pbi)
{
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
int result = JPEG_FAILURE;
PBITMAPINFOHEADER pbhi;
int imageSize = 0;;
int bufferSize = 0;
int widthBytes = 0;
LPBYTE pbits = NULL;
if (src == NULL || size <= 0)
{
return JPEG_ERROR_INVALID_PARAM;
}
if ((jerr = ijlInit( &jcprops)) != IJL_OK)
{
return JPEG_ERROR_IJL_INIT;
}
jcprops.JPGBytes = src;
jcprops.JPGSizeBytes = size;
//Read JPEG parameters from the file
if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS)) == IJL_OK)
{
widthBytes = (jcprops.JPGWidth * 3 + 31) & (~31);
imageSize = widthBytes * jcprops.JPGHeight;
bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
if ((pbi = (PBITMAPINFO)malloc(bufferSize)) != NULL)
{
pbhi = (PBITMAPINFOHEADER) pbi;
pbhi->biSize = sizeof(BITMAPINFOHEADER);
pbhi->biPlanes = 1;
pbhi->biClrUsed = 0;
pbhi->biWidth = jcprops.JPGWidth;
pbhi->biHeight = jcprops.JPGHeight;
pbhi->biCompression = BI_RGB;
pbhi->biClrImportant = 0;
pbhi->biBitCount = 24;
pbhi->biXPelsPerMeter= 0;
pbhi->biYPelsPerMeter= 0;
pbhi->biSizeImage = imageSize;
pbits = (LPBYTE)pbi + pbhi->biSize;
//Set up the DIB specification for the JPEG decoder
jcprops.DIBWidth = jcprops.JPGWidth;
jcprops.DIBHeight = - jcprops.JPGHeight; //Implies a bottom-up DIB.
jcprops.DIBChannels = 3; //jcprops.JPGChannels; //3????
jcprops.DIBColor = IJL_BGR;
jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
jcprops.DIBBytes = reinterpret_cast<BYTE*>(pbits);
jcprops.JPGSizeBytes = imageSize;
jcprops.jquality = 100;
if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READWHOLEIMAGE)) == IJL_OK)
{
result = JPEG_SUCCESS;
}
else
{
free(pbi);
}
}
}
jerr=ijlFree(&jcprops);
return result;
}
int scaleBmp(PBITMAPINFO pbi, LPBYTE pbits, LPBYTE& lpNewBits, int width, int height)
{
HDC hdc, srcDC=NULL, destDC=NULL;
int result = JPEG_FAILURE;
int srcWidthBytes =0, destWidthBytes = 0;
HBITMAP hSrcBmp = NULL, hDestBmp = NULL;
PBITMAPINFOHEADER pbhi = NULL;
if (pbi == NULL || width < 0 || height < 0)
{
return JPEG_ERROR_INVALID_PARAM;
}
pbhi = (PBITMAPINFOHEADER) pbi;
if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
{
if ((srcDC = CreateCompatibleDC(hdc)) != NULL &&
(destDC = CreateCompatibleDC(hdc)) != NULL)
{
srcWidthBytes = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;
if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
{
SelectObject(srcDC, hSrcBmp);
if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
{
destWidthBytes = ((width * pbhi->biBitCount + 31) & (~31)) / 8;
if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
{
SelectObject(destDC, hDestBmp);
if (SetStretchBltMode(srcDC, HALFTONE)&&SetStretchBltMode(destDC, HALFTONE)
&&SetBrushOrgEx(srcDC, 0, 0, NULL)&&SetBrushOrgEx(destDC, 0, 0, NULL))
{
if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0,
pbhi->biWidth, pbhi->biHeight, SRCCOPY))
{
if ((lpNewBits = (LPBYTE)malloc(destWidthBytes * height))!= NULL)
{
pbhi->biWidth = width;
pbhi->biHeight = height;
pbhi->biSizeImage = destWidthBytes * height;
if (GetDIBits(destDC, hDestBmp, 0, height, lpNewBits, pbi, DIB_RGB_COLORS))
{
result = JPEG_SUCCESS;
}
}
else
{
result = JPEG_ERROR_MEMORY_ALLOC;
}
}
}
DeleteObject(hDestBmp);
}
}
DeleteObject(hSrcBmp);
}
DeleteDC(srcDC);
DeleteDC(destDC);
}
DeleteDC(hdc);
}
return result;
}
int scaleBmp(PBITMAPINFO pbi, LPBYTE& lpNewBits, int width, int height)
{
HDC hdc, srcDC=NULL, destDC=NULL;
int result = JPEG_FAILURE;
int srcWidthBytes =0, destWidthBytes = 0;
HBITMAP hSrcBmp = NULL, hDestBmp = NULL;
PBITMAPINFOHEADER pbhi = NULL;
LPBYTE pbits = NULL;
int mode ;
if (pbi == NULL || width < 0 || height < 0)
{
return JPEG_ERROR_INVALID_PARAM;
}
pbhi = (PBITMAPINFOHEADER) pbi;
pbits = (LPBYTE)pbi + sizeof(BITMAPINFOHEADER);
if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
{
if ((srcDC = CreateCompatibleDC(hdc)) != NULL &&
(destDC = CreateCompatibleDC(hdc)) != NULL)
{
srcWidthBytes = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;
if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
{
SelectObject(srcDC, hSrcBmp);
if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
{
destWidthBytes = ((width * pbhi->biBitCount + 31) & (~31)) / 8;
if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
{
SelectObject(destDC, hDestBmp);
mode = GetStretchBltMode(srcDC);
if (SetStretchBltMode(srcDC, HALFTONE))
{
if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0,
pbhi->biWidth, pbhi->biHeight, SRCCOPY))
{
if ((lpNewBits = (LPBYTE)malloc(destWidthBytes * height))!= NULL)
{
pbi->bmiHeader.biWidth = width;
pbi->bmiHeader.biHeight = height;
pbi->bmiHeader.biSizeImage = destWidthBytes * height;
if (GetDIBits(destDC, hDestBmp, 0, height, lpNewBits, pbi, DIB_RGB_COLORS))
{
result = JPEG_SUCCESS;
}
}
else
{
result = JPEG_ERROR_MEMORY_ALLOC;
}
}
}
DeleteObject(hDestBmp);
}
}
DeleteObject(hSrcBmp);
}
DeleteDC(srcDC);
DeleteDC(destDC);
}
DeleteDC(hdc);
}
return result;
}
int scaleBmp(PBITMAPINFO pbi, int width, int height)
{
HDC hdc = NULL, srcDC = NULL, destDC=NULL;
int result = JPEG_FAILURE;
int srcWidthBytes = 0, destWidthBytes = 0;
int srcImageSize = 0, destImageSize = 0;
HBITMAP hSrcBmp = NULL, hDestBmp = NULL;
PBITMAPINFOHEADER pbhi = NULL;
LPBYTE pbits = NULL;
LPBYTE lpNewBits = NULL;
int mode = 0;
if (pbi == NULL || width < 0 || height < 0)
{
return JPEG_ERROR_INVALID_PARAM;
}
pbhi = (PBITMAPINFOHEADER) pbi;
srcWidthBytes = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;
destWidthBytes = ((width * pbhi->biBitCount + 31) & (~31)) / 8;
srcImageSize = pbhi->biHeight * srcWidthBytes;
destImageSize = height * destWidthBytes;
if (destImageSize > srcImageSize)
{
if ((lpNewBits = (LPBYTE) realloc(pbi, sizeof(BITMAPINFOHEADER) + destImageSize)) == NULL)
{
return JPEG_ERROR_MEMORY_ALLOC;
}
else
{
pbi = (PBITMAPINFO)lpNewBits;
pbhi = (PBITMAPINFOHEADER) pbi;
}
}
pbits = (LPBYTE)pbi + sizeof(BITMAPINFOHEADER);
if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
{
if ((srcDC = CreateCompatibleDC(hdc)) != NULL &&
(destDC = CreateCompatibleDC(hdc)) != NULL)
{
mode = SetStretchBltMode(srcDC, HALFTONE);
mode = SetStretchBltMode(destDC, HALFTONE);
if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
{
SelectObject(srcDC, hSrcBmp);
if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
{
if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
{
SelectObject(destDC, hDestBmp);
if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0,
pbhi->biWidth, pbhi->biHeight, SRCCOPY))
{
pbi->bmiHeader.biWidth = width;
pbi->bmiHeader.biHeight = height;
pbi->bmiHeader.biSizeImage = destImageSize;
if ((result = GetDIBits(destDC, hDestBmp, 0,
height, pbits, pbi, DIB_RGB_COLORS)) != 0)
{
result = JPEG_SUCCESS;
}
else
{
result = JPEG_ERROR_READ_BITS;
}
}
DeleteObject(hDestBmp);
}
}
DeleteObject(hSrcBmp);
}
DeleteDC(srcDC);
DeleteDC(destDC);
}
DeleteDC(hdc);
}
return result;
}
int createBmpInfoStruct(const BITMAP& bmp, PBITMAPINFO& pbmi)
{
WORD cClrBits;
int result = 0;
int colorNumber = 0;
int bufferSize = 0;
int imageSize = 0;
// Convert the color format to a count of bits.
imageSize = bmp.bmWidthBytes * bmp.bmHeight;
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
switch (cClrBits)
{
case 1:
case 2:
case 4:
case 8:
colorNumber = 1<< cClrBits;
bufferSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * colorNumber + imageSize;
break;
case 16:
case 24:
case 32:
bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
break;
default:
return JPEG_ERROR_INVALID_FORMAT; //failed ! this means we don't support "jpg" or "png" which has "0" here
}
if (pbmi == NULL)
{
return JPEG_ERROR_MEMORY_ALLOC;
}
// Initialize the fields in the BITMAPINFO structure.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biClrUsed = 0;
pbmi = (PBITMAPINFO) malloc(sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * colorNumber);
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT/2000, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits + 31) & ~31) /8
* pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the device colors are important.
pbmi->bmiHeader.biClrImportant = 0;
return JPEG_SUCCESS;
}
bool readBmpFile(const TCHAR* pszFile, PBITMAPINFO& pbi)
{
HANDLE hf = NULL; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
BITMAPINFOHEADER bih;
DWORD bytesRead;
int colorNumber = 0;
bool result = false;
int bufferSize = 0;
int bitSize = 0;
if (pszFile == NULL)
{
return false;
}
if ((hf = CreateFile(pszFile, GENERIC_READ , (DWORD) 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
{
if (ReadFile(hf, &hdr, sizeof(BITMAPFILEHEADER), &bytesRead, NULL)&& bytesRead==sizeof(BITMAPFILEHEADER))
{
if (hdr.bfType == 0x4d42)
{
if (ReadFile(hf, &bih, sizeof(BITMAPINFOHEADER), &bytesRead, NULL) && bytesRead==sizeof(BITMAPINFOHEADER))
{
//only support true color bmp
if (bih.biBitCount >= 24)
{
bitSize = hdr.bfSize - hdr.bfOffBits;
bufferSize = bitSize + sizeof(BITMAPINFOHEADER);
if ((pbi = (PBITMAPINFO)malloc(bufferSize)) != NULL)
{
memcpy(pbi, &bih, sizeof(BITMAPINFOHEADER));
if (ReadFile(hf, pbi->bmiColors, bitSize, &bytesRead, NULL)&& bytesRead==bitSize)
{
result = true;
}
}
}
}
}
}
CloseHandle(hf);
}
return result;
}
bool readImageFile(LPCTSTR fileName, PBITMAPINFO& pbi)
{
LPBYTE imagePtr = NULL;
DWORD imageSize = 0;
ImageFileFormat imgFormat;
PBITMAPFILEHEADER pbhr; // bitmap file-header
PBITMAPINFOHEADER pbih;
DWORD bytesRead;
int result = JPEG_FAILURE;
int bufferSize = 0;
if (mapFile(fileName, imagePtr, imageSize))
{
imgFormat = imageFileFormat(imagePtr);
switch (imgFormat)
{
case Image_File_Format_BMP:
pbhr = (PBITMAPFILEHEADER) imagePtr;
pbih = (PBITMAPINFOHEADER) ((LPSTR)(imagePtr) + sizeof(BITMAPFILEHEADER));
bufferSize = pbhr->bfSize - pbhr->bfOffBits;
if (bufferSize > 0 && (pbi =(PBITMAPINFO)malloc(bufferSize))!= NULL)
{
memcpy(pbi, pbih, bufferSize);
result = JPEG_SUCCESS;
}
break;
case Image_File_Format_JPG:
result = readJpgBuffer(imagePtr, imageSize, pbi);
break;
default:
break;
}
unmapFile(imagePtr);
}
return result == JPEG_SUCCESS;
}
int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi, LPBYTE lpBits)
{
HANDLE hf = NULL; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
DWORD dwTmp;
int colorNumber = 0;
int result = JPEG_ERROR_FILE_WRITE;
DWORD imageSize = 0, widthInBytes = 0;
if (pszFile == NULL || pbi == NULL || lpBits == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
memset(&hdr, 0, sizeof(BITMAPFILEHEADER));
pbih = (PBITMAPINFOHEADER) pbi;
colorNumber = pbi->bmiHeader.biClrUsed;
if (pbi->bmiHeader.biBitCount < 16 && pbi->bmiHeader.biClrUsed == 0)
{
colorNumber = (1 << pbi->bmiHeader.biBitCount);
}
hf = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
if(hf == INVALID_HANDLE_VALUE)
{
return JPEG_ERROR_FILE_CREATE;
}
widthInBytes = ((pbih->biWidth * pbih->biBitCount + 31) & (~31)) /8;
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
if (pbih->biSizeImage == 0)
{
imageSize = pbih->biHeight * widthInBytes;
}
else
{
imageSize = pbih->biSizeImage;
}
pbih->biSizeImage = imageSize;
pbih->biXPelsPerMeter = 3768;
pbih->biYPelsPerMeter = 3768;
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + colorNumber *
sizeof(RGBQUAD) + imageSize);
// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize +
colorNumber * sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
if(WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL))
{
if(WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER), (LPDWORD) &dwTmp, ( NULL)))
{
if(WriteFile(hf, (LPVOID) pbi->bmiColors, colorNumber * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, ( NULL)))
{
if(WriteFile(hf, (LPSTR) lpBits, imageSize, (LPDWORD) &dwTmp,NULL))
{
result = JPEG_SUCCESS;
}
}
}
}
SetEndOfFile(hf);
CloseHandle(hf);
return result;
}
int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi)
{
PBITMAPINFOHEADER pbih; // bitmap info-header
int colorNumber = 0;
LPBYTE lpBits = NULL;
if (pszFile == NULL || pbi == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
pbih = (PBITMAPINFOHEADER) pbi;
colorNumber = pbi->bmiHeader.biClrUsed;
if (pbi->bmiHeader.biBitCount < 16 && pbi->bmiHeader.biClrUsed == 0)
{
colorNumber = (1 << pbi->bmiHeader.biBitCount);
}
lpBits = (LPBYTE)pbi + pbih->biSize + colorNumber * sizeof(RGBQUAD);
return createBmpFile(pszFile, pbi, lpBits);
}
void saveToFile(TCHAR* fileName)
{
LPBYTE imagePtr;
DWORD imageSize;
int imageWidth;
int imageHeight;
int stretchedWidth;
int stretchedHeight;
LPBYTE thumbPtr;
LPBYTE stretchedPtr;
DWORD thumbDataSize;
DWORD stretchedSize;
if (!mapFile(fileName, imagePtr, imageSize))
{
_tprintf(_T("fileMapping error %d fileName=%s\n"), GetLastError(), fileName);
return;
}
if (imageProcess(imagePtr, imageSize, DefaultMaxHeight, DefaultThumbnailSize,
imageWidth, imageHeight, stretchedWidth, stretchedHeight, thumbPtr,
stretchedPtr, thumbDataSize, stretchedSize) == JPEG_SUCCESS)
{
saveJpgFile(_T("original.jpg"), imagePtr, imageSize);
saveJpgFile(_T("stretched.jpg"), stretchedPtr, stretchedSize);
saveJpgFile(_T("thumbnail.jpg"), thumbPtr, thumbDataSize);
free(thumbPtr);
free(stretchedPtr);
}
unmapFile(imagePtr);
}
bool generateUniqueFileName(LPTSTR buffer, int bufferSize)
{
UUID uuid;
if (bufferSize < 33)
{
return false;
}
if (UuidCreate(&uuid) == RPC_S_OK)
{
_stprintf(buffer, _T("%X%X%X"), uuid.Data1, uuid.Data2, uuid.Data3);
return true;
}
return false;
}
bool savePictureFile(LPBYTE buffer, DWORD size, FILE* log)
{
TCHAR nameBuffer[MAX_PATH];
ImageFileFormat imageType;
LPTSTR ptr = NULL;
if (size <= MinPictureSize)
{
return false;
}
imageType = imageFileFormat(buffer);
generateUniqueFileName(nameBuffer, MAX_PATH - 1);
switch (imageType)
{
case Image_File_Format_BMP:
_tcscat(nameBuffer, _T(".bmp"));
break;
case Image_File_Format_JPG:
_tcscat(nameBuffer, _T(".jpg"));
break;
default:
return false;
}
_tprintf(_T("file name is [%s]\n"), nameBuffer);
if (saveFile(nameBuffer, (char*)buffer, size))
{
saveCounter ++;
if (log != NULL)
{
_ftprintf(log, _T("file name is [%s]\n"), nameBuffer);
}
return true;
}
return false;
}
/*
int readJpgBuffer(const LPBYTE src, PBITMAPINFO& pbi)
{
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
PBITMAPINFOHEADER pbhi;
int imageSize = 0;;
int bufferSize = 0;
int widthBytes = 0;
LPBYTE pbits = NULL;
if (src == NULL)
{
return JPEG_ERROR_INVALID_PARAM;
}
if ((jerr = ijlInit( &jcprops)) != IJL_OK)
{
return JPEG_ERROR_IJL_INIT;
}
jcprops.JPGBytes = src;
jcprops.JPGSizeBytes = 400;
//Read JPEG parameters from the file
if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS)) != IJL_OK)
{
ijlFree(&jcprops);
return JPEG_ERROR_IJL_READ_PARAM;
}
widthBytes = IJL_DIB_AWIDTH(jcprops.JPGWidth, jcprops.JPGChannels);
imageSize = widthBytes * jcprops.JPGHeight;
bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
if ((pbi = (PBITMAPINFO)malloc(bufferSize)) == NULL)
{
ijlFree(&jcprops);
return JPEG_ERROR_MEMORY_ALLOC;
}
pbhi = (PBITMAPINFOHEADER) pbi;
pbhi->biSize = sizeof(BITMAPINFOHEADER);
pbhi->biPlanes = 1;
pbhi->biClrUsed = 0;
pbhi->biWidth = jcprops.JPGWidth;
pbhi->biHeight = jcprops.JPGHeight;
pbhi->biCompression = BI_RGB;
pbhi->biClrImportant = 0;
pbhi->biBitCount = 24;
pbhi->biXPelsPerMeter= 0;
pbhi->biYPelsPerMeter= 0;
pbhi->biSizeImage = imageSize;
pbits = (LPBYTE)pbi + pbhi->biSize;
//Set up the DIB specification for the JPEG decoder
jcprops.DIBWidth = jcprops.JPGWidth;
jcprops.DIBHeight = - jcprops.JPGHeight; //Implies a bottom-up DIB.
jcprops.DIBChannels = 3; //jcprops.JPGChannels; //3????
jcprops.DIBColor = IJL_BGR;
jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
jcprops.DIBBytes = reinterpret_cast<BYTE*>(pbits);
//Set the JPG color space ... this will always be somewhat of an
//educated guess at best because JPEG is "color blind" (i.e.,
//nothing in the bit stream tells you what color space the data was
//encoded from. However, in this example we assume that we are
//reading JFIF files which means that 3 channel images are in the
//YCbCr color space and 1 channel images are in the Y color space.
//jcprops.JPGColor = IJL_OTHER;
jcprops.JPGSizeBytes = imageSize;
jcprops.jquality = 100;
jerr = ijlRead(&jcprops, IJL_JBUFF_READWHOLEIMAGE);
//Make sure the read was successful
if (jerr != IJL_OK)
{
return JPEG_ERROR_IJL_READ_DATA;
}
jerr=ijlFree(&jcprops);
if (jerr != IJL_OK)
{
return JPEG_ERROR_IJL_FREE;
}
return JPEG_SUCCESS;
}
#endif
*/
//filename : ijl.h
/*M*
//
//
// INTEL CORPORATION PROPRIETARY INFORMATION
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Intel Corporation and may not be copied
// or disclosed except in accordance with the terms of that agreement.
// Copyright (c) 1998 Intel Corporation. All Rights Reserved.
//
//
// File:
// ijl.h
//
// Purpose:
// IJL Common Header File
// This file contains: definitions for data types, data
// structures, error codes, and function prototypes used
// in the Intel(R) JPEG Library (IJL).
//
// Version:
// 1.5
//
*M*/
#ifndef __IJL_H__
#define __IJL_H__
#if defined( __cplusplus )
extern "C" {
#endif
#ifndef IJL_ALL_WARNINGS
#if _MSC_VER >= 1000
/* nonstandard extension used : nameless struct/union */
#pragma warning(disable : 4201)
/* nonstandard extension used : bit field types other than int */
#pragma warning(disable : 4214)
/* unreferenced inline function has been removed */
#pragma warning(disable : 4514)
/* named type definition in parentheses */
#pragma warning(disable : 4115)
#endif /* _MSC_VER >= 1000 */
#endif /* IJL_ALL_WARNINGS */
#define IJL_STDCALL __stdcall
/* align struct on 8 bytes boundary */
#pragma pack (8)
/* /////////////////////////////////////////////////////////////////////////
// Macros/Constants */
/* Size of file I/O buffer (4K). */
#define JBUFSIZE 4096
#define IJL_INT64 __int64
#define IJL_UINT64 unsigned IJL_INT64
#ifndef IJLAPI
#ifdef IJL_MSEXPORTS
#define IJLAPI(type,name,arg) \
extern __declspec(dllimport) type IJL_STDCALL name arg
#else
#define IJLAPI(type,name,arg) \
extern type IJL_STDCALL name arg
#endif
#endif
#define IJL_DIB_ALIGN (sizeof(int) - 1)
#define IJL_DIB_UWIDTH(width,nchannels) \
((width) * (nchannels))
#define IJL_DIB_AWIDTH(width,nchannels) \
( ((IJL_DIB_UWIDTH(width,nchannels) + IJL_DIB_ALIGN) & (~IJL_DIB_ALIGN)) )
#define IJL_DIB_PAD_BYTES(width,nchannels) \
( IJL_DIB_AWIDTH(width,nchannels) - IJL_DIB_UWIDTH(width,nchannels) )
#define IJL_DIB_SCALE_SIZE(jpgsize,scale) \
( ((jpgsize) + (scale) - 1) / (scale) )
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJLibVersion
//
// Purpose: Stores library version info.
//
// Context:
//
// Example:
// major - 1
// minor - 0
// build - 1
// Name - "ijl10.dll"
// Version - "1.0.1 Beta1"
// InternalVersion - "1.0.1.1"
// BuildDate - "Sep 22 1998"
// CallConv - "DLL"
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _IJLibVersion
{
int major;
int minor;
int build;
const char* Name;
const char* Version;
const char* InternalVersion;
const char* BuildDate;
const char* CallConv;
} IJLibVersion;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_RECT
//
// Purpose: Keep coordinates for rectangle region of image
//
// Context: Used to specify roi
//
// Fields:
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _IJL_RECT
{
long left;
long top;
long right;
long bottom;
} IJL_RECT;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_HANDLE
//
// Purpose: file handle
//
// Context: used internally
//
// Fields:
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef void* IJL_HANDLE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJLIOTYPE
//
// Purpose: Possible types of data read/write/other operations to be
// performed by the functions IJL_Read and IJL_Write.
//
// See the Developer's Guide for details on appropriate usage.
//
// Fields:
//
// IJL_JFILE_XXXXXXX Indicates JPEG data in a stdio file.
//
// IJL_JBUFF_XXXXXXX Indicates JPEG data in an addressable buffer.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _IJLIOTYPE
{
IJL_SETUP = -1,
/* Read JPEG parameters (i.e., height, width, channels, sampling, etc.) */
/* from a JPEG bit stream. */
IJL_JFILE_READPARAMS = 0,
IJL_JBUFF_READPARAMS = 1,
/* Read a JPEG Interchange Format image. */
IJL_JFILE_READWHOLEIMAGE = 2,
IJL_JBUFF_READWHOLEIMAGE = 3,
/* Read JPEG tables from a JPEG Abbreviated Format bit stream. */
IJL_JFILE_READHEADER = 4,
IJL_JBUFF_READHEADER = 5,
/* Read image info from a JPEG Abbreviated Format bit stream. */
IJL_JFILE_READENTROPY = 6,
IJL_JBUFF_READENTROPY = 7,
/* Write an entire JFIF bit stream. */
IJL_JFILE_WRITEWHOLEIMAGE = 8,
IJL_JBUFF_WRITEWHOLEIMAGE = 9,
/* Write a JPEG Abbreviated Format bit stream. */
IJL_JFILE_WRITEHEADER = 10,
IJL_JBUFF_WRITEHEADER = 11,
/* Write image info to a JPEG Abbreviated Format bit stream. */
IJL_JFILE_WRITEENTROPY = 12,
IJL_JBUFF_WRITEENTROPY = 13,
/* Scaled Decoding Options: */
/* Reads a JPEG image scaled to 1/2 size. */
IJL_JFILE_READONEHALF = 14,
IJL_JBUFF_READONEHALF = 15,
/* Reads a JPEG image scaled to 1/4 size. */
IJL_JFILE_READONEQUARTER = 16,
IJL_JBUFF_READONEQUARTER = 17,
/* Reads a JPEG image scaled to 1/8 size. */
IJL_JFILE_READONEEIGHTH = 18,
IJL_JBUFF_READONEEIGHTH = 19,
/* Reads an embedded thumbnail from a JFIF bit stream. */
IJL_JFILE_READTHUMBNAIL = 20,
IJL_JBUFF_READTHUMBNAIL = 21
} IJLIOTYPE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_COLOR
//
// Purpose: Possible color space formats.
//
// Note these formats do *not* necessarily denote
// the number of channels in the color space.
// There exists separate "channel" fields in the
// JPEG_CORE_PROPERTIES data structure specifically
// for indicating the number of channels in the
// JPEG and/or DIB color spaces.
//
// See the Developer's Guide for details on appropriate usage.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _IJL_COLOR
{
IJL_RGB = 1, /* Red-Green-Blue color space. */
IJL_BGR = 2, /* Reversed channel ordering from IJL_RGB. */
IJL_YCBCR = 3, /* Luminance-Chrominance color space as defined */
/* by CCIR Recommendation 601. */
IJL_G = 4, /* Grayscale color space. */
IJL_RGBA_FPX = 5, /* FlashPix RGB 4 channel color space that */
/* has pre-multiplied opacity. */
IJL_YCBCRA_FPX = 6, /* FlashPix YCbCr 4 channel color space that */
/* has pre-multiplied opacity. */
IJL_OTHER = 255 /* Some other color space not defined by the IJL. */
/* (This means no color space conversion will */
/* be done by the IJL.) */
} IJL_COLOR;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_JPGSUBSAMPLING
//
// Purpose: Possible subsampling formats used in the JPEG.
//
// See the Developer's Guide for details on appropriate usage.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _IJL_JPGSUBSAMPLING
{
IJL_NONE = 0, /* Corresponds to "No Subsampling". */
/* Valid on a JPEG w/ any number of channels. */
IJL_411 = 1, /* Valid on a JPEG w/ 3 channels. */
IJL_422 = 2, /* Valid on a JPEG w/ 3 channels. */
IJL_4114 = 3, /* Valid on a JPEG w/ 4 channels. */
IJL_4224 = 4 /* Valid on a JPEG w/ 4 channels. */
} IJL_JPGSUBSAMPLING;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_DIBSUBSAMPLING
//
// Purpose: Possible subsampling formats used in the DIB.
//
// See the Developer's Guide for details on appropriate usage.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef IJL_JPGSUBSAMPLING IJL_DIBSUBSAMPLING;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: HUFFMAN_TABLE
//
// Purpose: Stores Huffman table information in a fast-to-use format.
//
// Context: Used by Huffman encoder/decoder to access Huffman table
// data. Raw Huffman tables are formatted to fit this
// structure prior to use.
//
// Fields:
// huff_class 0 == DC Huffman or lossless table, 1 == AC table.
// ident Huffman table identifier, 0-3 valid (Extended Baseline).
// huffelem Huffman elements for codes <= 8 bits long;
// contains both zero run-length and symbol length in bits.
// huffval Huffman values for codes 9-16 bits in length.
// mincode Smallest Huffman code of length n.
// maxcode Largest Huffman code of length n.
// valptr Starting index into huffval[] for symbols of length k.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _HUFFMAN_TABLE
{
int huff_class;
int ident;
unsigned int huffelem[256];
unsigned short huffval[256];
unsigned short mincode[17];
short maxcode[18];
unsigned short valptr[17];
} HUFFMAN_TABLE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: JPEGHuffTable
//
// Purpose: Stores pointers to JPEG-binary spec compliant
// Huffman table information.
//
// Context: Used by interface and table methods to specify encoder
// tables to generate and store JPEG images.
//
// Fields:
// bits Points to number of codes of length i (<=16 supported).
// vals Value associated with each Huffman code.
// hclass 0 == DC table, 1 == AC table.
// ident Specifies the identifier for this table.
// 0-3 for extended JPEG compliance.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _JPEGHuffTable
{
unsigned char* bits;
unsigned char* vals;
unsigned char hclass;
unsigned char ident;
} JPEGHuffTable;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: QUANT_TABLE
//
// Purpose: Stores quantization table information in a
// fast-to-use format.
//
// Context: Used by quantizer/dequantizer to store formatted
// quantization tables.
//
// Fields:
// precision 0 => elements contains 8-bit elements,
// 1 => elements contains 16-bit elements.
// ident Table identifier (0-3).
// elements Pointer to 64 table elements + 16 extra elements to catch
// input data errors that may cause malfunction of the
// Huffman decoder.
// elarray Space for elements (see above) plus 8 bytes to align
// to a quadword boundary.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _QUANT_TABLE
{
int precision;
int ident;
short* elements;
short elarray [84];
} QUANT_TABLE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: JPEGQuantTable
//
// Purpose: Stores pointers to JPEG binary spec compliant
// quantization table information.
//
// Context: Used by interface and table methods to specify encoder
// tables to generate and store JPEG images.
//
// Fields:
// quantizer Zig-zag order elements specifying quantization factors.
// ident Specifies identifier for this table.
// 0-3 valid for Extended Baseline JPEG compliance.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _JPEGQuantTable
{
unsigned char* quantizer;
unsigned char ident;
} JPEGQuantTable;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: FRAME_COMPONENT
//
// Purpose: One frame-component structure is allocated per component
// in a frame.
//
// Context: Used by Huffman decoder to manage components.
//
// Fields:
// ident Component identifier. The tables use this ident to
// determine the correct table for each component.
// hsampling Horizontal subsampling factor for this component,
// 1-4 are legal.
// vsampling Vertical subsampling factor for this component,
// 1-4 are legal.
// quant_sel Quantization table selector. The quantization table
// used by this component is determined via this selector.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _FRAME_COMPONENT
{
int ident;
int hsampling;
int vsampling;
int quant_sel;
} FRAME_COMPONENT;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: FRAME
//
// Purpose: Stores frame-specific data.
//
// Context: One Frame structure per image.
//
// Fields:
// precision Sample precision in bits.
// width Width of the source image in pixels.
// height Height of the source image in pixels.
// MCUheight Height of a frame MCU.
// MCUwidth Width of a frame MCU.
// max_hsampling Max horiz sampling ratio of any component in the frame.
// max_vsampling Max vert sampling ratio of any component in the frame.
// ncomps Number of components/channels in the frame.
// horMCU Number of horizontal MCUs in the frame.
// totalMCU Total number of MCUs in the frame.
// comps Array of 'ncomps' component descriptors.
// restart_interv Indicates number of MCUs after which to restart the
// entropy parameters.
// SeenAllDCScans Used when decoding Multiscan images to determine if
// all channels of an image have been decoded.
// SeenAllACScans (See SeenAllDCScans)
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _FRAME
{
int precision;
int width;
int height;
int MCUheight;
int MCUwidth;
int max_hsampling;
int max_vsampling;
int ncomps;
int horMCU;
long totalMCU;
FRAME_COMPONENT* comps;
int restart_interv;
int SeenAllDCScans;
int SeenAllACScans;
} FRAME;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: SCAN_COMPONENT
//
// Purpose: One scan-component structure is allocated per component
// of each scan in a frame.
//
// Context: Used by Huffman decoder to manage components within scans.
//
// Fields:
// comp Component number, index to the comps member of FRAME.
// hsampling Horizontal sampling factor.
// vsampling Vertical sampling factor.
// dc_table DC Huffman table pointer for this scan.
// ac_table AC Huffman table pointer for this scan.
// quant_table Quantization table pointer for this scan.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _SCAN_COMPONENT
{
int comp;
int hsampling;
int vsampling;
HUFFMAN_TABLE* dc_table;
HUFFMAN_TABLE* ac_table;
QUANT_TABLE* quant_table;
} SCAN_COMPONENT;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: SCAN
//
// Purpose: One SCAN structure is allocated per scan in a frame.
//
// Context: Used by Huffman decoder to manage scans.
//
// Fields:
// ncomps Number of image components in a scan, 1-4 legal.
// gray_scale If TRUE, decode only the Y channel.
// start_spec Start coefficient of spectral or predictor selector.
// end_spec End coefficient of spectral selector.
// approx_high High bit position in successive approximation
// Progressive coding.
// approx_low Low bit position in successive approximation
// Progressive coding.
// restart_interv Restart interval, 0 if disabled.
// curxMCU Next horizontal MCU index to be processed after
// an interrupted SCAN.
// curyMCU Next vertical MCU index to be processed after
// an interrupted SCAN.
// dc_diff Array of DC predictor values for DPCM modes.
// comps Array of ncomps SCAN_COMPONENT component identifiers.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _SCAN
{
int ncomps;
int gray_scale;
int start_spec;
int end_spec;
int approx_high;
int approx_low;
unsigned int restart_interv;
int curxMCU;
int curyMCU;
int dc_diff[4];
SCAN_COMPONENT* comps;
} SCAN;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: DCTTYPE
//
// Purpose: Possible algorithms to be used to perform the discrete
// cosine transform (DCT).
//
// Fields:
// IJL_AAN The AAN (Arai, Agui, and Nakajima) algorithm from
// Trans. IEICE, vol. E 71(11), 1095-1097, Nov. 1988.
// IJL_IPP The modified K. R. Rao and P. Yip algorithm from
// Intel Performance Primitives Library
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _DCTTYPE
{
IJL_AAN = 0,
IJL_IPP = 1
} DCTTYPE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: UPSAMPLING_TYPE
//
// Purpose: - Possible algorithms to be used to perform upsampling
//
// Fields:
// IJL_BOX_FILTER - the algorithm is simple replication of the input pixel
// onto the corresponding output pixels (box filter);
// IJL_TRIANGLE_FILTER - 3/4 * nearer pixel + 1/4 * further pixel in each
// dimension
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _UPSAMPLING_TYPE
{
IJL_BOX_FILTER = 0,
IJL_TRIANGLE_FILTER = 1
} UPSAMPLING_TYPE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: SAMPLING_STATE
//
// Purpose: Stores current conditions of sampling. Only for upsampling
// with triangle filter is used now.
//
// Fields:
// top_row - pointer to buffer with MCUs, that are located above than
// current row of MCUs;
// cur_row - pointer to buffer with current row of MCUs;
// bottom_row - pointer to buffer with MCUs, that are located below than
// current row of MCUs;
// last_row - pointer to bottom boundary of last row of MCUs
// cur_row_number - number of row of MCUs, that is decoding;
// user_interrupt - field to store jprops->interrupt, because of we prohibit
// interrupts while top row of MCUs is upsampling.
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _SAMPLING_STATE
{
short* top_row;
short* cur_row;
short* bottom_row;
short* last_row;
int cur_row_number;
} SAMPLING_STATE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: PROCESSOR_TYPE
//
// Purpose: Possible types of processors.
// Note that the enums are defined in ascending order
// depending upon their various IA32 instruction support.
//
// Fields:
//
// IJL_OTHER_PROC
// Does not support the CPUID instruction and
// assumes no Pentium(R) processor instructions.
//
// IJL_PENTIUM_PROC
// Corresponds to an Intel(R) Pentium(R) processor
// (or a 100% compatible) that supports the
// Pentium(R) processor instructions.
//
// IJL_PENTIUM_PRO_PROC
// Corresponds to an Intel(R) Pentium(R) Pro processor
// (or a 100% compatible) that supports the
// Pentium(R) Pro processor instructions.
//
// IJL_PENTIUM_PROC_MMX_TECH
// Corresponds to an Intel(R) Pentium(R) processor
// with MMX(TM) technology (or a 100% compatible)
// that supports the MMX(TM) instructions.
//
// IJL_PENTIUM_II_PROC
// Corresponds to an Intel(R) Pentium(R) II processor
// (or a 100% compatible) that supports both the
// Pentium(R) Pro processor instructions and the
// MMX(TM) instructions.
//
// IJL_PENTIUM_III_PROC
// Corresponds to an Intel(R) Pentium(R) III processor
//
// IJL_NEW_PROCESSOR
// Correponds to new processor
//
// Any additional processor types that support a superset
// of both the Pentium(R) Pro processor instructions and the
// MMX(TM) instructions should be given an enum value greater
// than IJL_PENTIUM_III_PROC.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _PROCESSOR_TYPE
{
IJL_OTHER_PROC = 0,
IJL_PENTIUM_PROC = 1,
IJL_PENTIUM_PRO_PROC = 2,
IJL_PENTIUM_PROC_MMX_TECH = 3,
IJL_PENTIUM_II_PROC = 4,
IJL_PENTIUM_III_PROC = 5,
IJL_PENTIUM_4_PROC = 6,
IJL_NEW_PROCESSOR = 7
} PROCESSOR_TYPE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: RAW_DATA_TYPES_STATE
//
// Purpose: Stores data types: raw dct coefficients or raw sampled data.
// Pointer to structure in JPEG_PROPERTIES is NULL, if any raw
// data isn't request (DIBBytes!=NULL).
//
// Fields:
// short* raw_ptrs[4] - pointers to buffers with raw data; one pointer
// corresponds one JPG component;
// data_type - 0 - raw dct coefficients, 1 - raw sampled data.
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _RAW_DATA_TYPES_STATE
{
int data_type;
unsigned short* raw_ptrs[4];
} RAW_DATA_TYPES_STATE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: ENTROPYSTRUCT
//
// Purpose: Stores the decoder state information necessary to "jump"
// to a particular MCU row in a compressed entropy stream.
//
// Context: Used to persist the decoder state within Decode_Scan when
// decoding using ROIs.
//
// Fields:
// offset Offset (in bytes) into the entropy stream
// from the beginning.
// dcval1 DC val at the beginning of the MCU row
// for component 1.
// dcval2 DC val at the beginning of the MCU row
// for component 2.
// dcval3 DC val at the beginning of the MCU row
// for component 3.
// dcval4 DC val at the beginning of the MCU row
// for component 4.
// bit_buffer_64 64-bit Huffman bit buffer. Stores current
// bit buffer at the start of a MCU row.
// Also used as a 32-bit buffer on 32-bit
// architectures.
// bitbuf_bits_valid Number of valid bits in the above bit buffer.
// unread_marker Have any markers been decoded but not
// processed at the beginning of a MCU row?
// This entry holds the unprocessed marker, or
// 0 if none.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _ENTROPYSTRUCT
{
unsigned int offset;
int dcval1;
int dcval2;
int dcval3;
int dcval4;
IJL_UINT64 bit_buffer_64;
int bitbuf_bits_valid;
unsigned char unread_marker;
} ENTROPYSTRUCT;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: STATE
//
// Purpose: Stores the active state of the IJL.
//
// Context: Used by all low-level routines to store pseudo-global or
// state variables.
//
// Fields:
// bit_buffer_64 64-bit bitbuffer utilized by Huffman
// encoder/decoder algorithms utilizing routines
// designed for MMX(TM) technology.
// bit_buffer_32 32-bit bitbuffer for all other Huffman
// encoder/decoder algorithms.
// bitbuf_bits_valid Number of bits in the above two fields that
// are valid.
//
// cur_entropy_ptr Current position (absolute address) in
// the entropy buffer.
// start_entropy_ptr Starting position (absolute address) of
// the entropy buffer.
// end_entropy_ptr Ending position (absolute address) of
// the entropy buffer.
// entropy_bytes_processed Number of bytes actually processed
// (passed over) in the entropy buffer.
// entropy_buf_maxsize Max size of the entropy buffer.
// entropy_bytes_left Number of bytes left in the entropy buffer.
// Prog_EndOfBlock_Run Progressive block run counter.
//
// DIB_ptr Temporary offset into the input/output DIB.
//
// unread_marker If a marker has been read but not processed,
// stick it in this field.
// processor_type (0, 1, or 2) == current processor does not
// support MMX(TM) instructions.
// (3 or 4) == current processor does
// support MMX(TM) instructions.
// cur_scan_comp On which component of the scan are we working?
// file Process file handle, or
// 0x00000000 if no file is defined.
// JPGBuffer Entropy buffer (~4K).
//
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _STATE
{
/* Bit buffer. */
IJL_UINT64 bit_buffer_64;
unsigned int bit_buffer_32;
int bitbuf_bits_valid;
/* Entropy. */
unsigned char* cur_entropy_ptr;
unsigned char* start_entropy_ptr;
unsigned char* end_entropy_ptr;
int entropy_bytes_processed;
int entropy_buf_maxsize;
int entropy_bytes_left;
int Prog_EndOfBlock_Run;
/* Input or output DIB. */
unsigned char* DIB_ptr;
/* Control. */
unsigned char unread_marker;
PROCESSOR_TYPE processor_type;
int cur_scan_comp;
IJL_HANDLE file;
unsigned char JPGBuffer [JBUFSIZE];
} STATE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: FAST_MCU_PROCESSING_TYPE
//
// Purpose: Advanced Control Option. Do NOT modify.
// WARNING: Used for internal reference only.
//
// Fields:
//
// IJL_(sampling)_(JPEG color space)_(sampling)_(DIB color space)
// Decode is read left to right w/ upsampling.
// Encode is read right to left w/ subsampling.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _FAST_MCU_PROCESSING_TYPE
{
IJL_NO_CC_OR_US = 0,
IJL_111_YCBCR_111_RGB = 1,
IJL_111_YCBCR_111_BGR = 2,
IJL_411_YCBCR_111_RGB = 3,
IJL_411_YCBCR_111_BGR = 4,
IJL_422_YCBCR_111_RGB = 5,
IJL_422_YCBCR_111_BGR = 6,
IJL_111_YCBCR_1111_RGBA_FPX = 7,
IJL_411_YCBCR_1111_RGBA_FPX = 8,
IJL_422_YCBCR_1111_RGBA_FPX = 9,
IJL_1111_YCBCRA_FPX_1111_RGBA_FPX = 10,
IJL_4114_YCBCRA_FPX_1111_RGBA_FPX = 11,
IJL_4224_YCBCRA_FPX_1111_RGBA_FPX = 12,
IJL_111_RGB_1111_RGBA_FPX = 13,
IJL_1111_RGBA_FPX_1111_RGBA_FPX = 14,
IJL_111_OTHER_111_OTHER = 15,
IJL_411_OTHER_111_OTHER = 16,
IJL_422_OTHER_111_OTHER = 17,
IJL_YCBYCR_YCBCR = 18,
IJL_YCBCR_YCBYCR = 19 // decoding to YCbCr 422 format
} FAST_MCU_PROCESSING_TYPE;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: JPEG_PROPERTIES
//
// Purpose: Stores low-level and control information. It is used by
// both the encoder and decoder. An advanced external user
// may access this structure to expand the interface
// capability.
//
// See the Developer's Guide for an expanded description
// of this structure and its use.
//
// Context: Used by all interface methods and most IJL routines.
//
// Fields:
//
// iotype IN: Specifies type of data operation
// (read/write/other) to be
// performed by IJL_Read or IJL_Write.
// roi IN: Rectangle-Of-Interest to read from, or
// write to, in pixels.
// dcttype IN: DCT alogrithm to be used.
// fast_processing OUT: Supported fast pre/post-processing path.
// This is set by the IJL.
// interrupt IN: Signals an interrupt has been requested.
//
// DIBBytes IN: Pointer to buffer of uncompressed data.
// DIBWidth IN: Width of uncompressed data.
// DIBHeight IN: Height of uncompressed data.
// DIBPadBytes IN: Padding (in bytes) at end of each
// row in the uncompressed data.
// DIBChannels IN: Number of components in the
// uncompressed data.
// DIBColor IN: Color space of uncompressed data.
// DIBSubsampling IN: Required to be IJL_NONE or IJL_422.
// DIBLineBytes OUT: Number of bytes in an output DIB line
// including padding.
//
// JPGFile IN: Pointer to file based JPEG.
// JPGBytes IN: Pointer to buffer based JPEG.
// JPGSizeBytes IN: Max buffer size. Used with JPGBytes.
// OUT: Number of compressed bytes written.
// JPGWidth IN: Width of JPEG image.
// OUT: After reading (except READHEADER).
// JPGHeight IN: Height of JPEG image.
// OUT: After reading (except READHEADER).
// JPGChannels IN: Number of components in JPEG image.
// OUT: After reading (except READHEADER).
// JPGColor IN: Color space of JPEG image.
// JPGSubsampling IN: Subsampling of JPEG image.
// OUT: After reading (except READHEADER).
// JPGThumbWidth OUT: JFIF embedded thumbnail width [0-255].
// JPGThumbHeight OUT: JFIF embedded thumbnail height [0-255].
//
// cconversion_reqd OUT: If color conversion done on decode, TRUE.
// upsampling_reqd OUT: If upsampling done on decode, TRUE.
// jquality IN: [0-100] where highest quality is 100.
// jinterleaveType IN/OUT: 0 => MCU interleaved file, and
// 1 => 1 scan per component.
// numxMCUs OUT: Number of MCUs in the x direction.
// numyMCUs OUT: Number of MCUs in the y direction.
//
// nqtables IN/OUT: Number of quantization tables.
// maxquantindex IN/OUT: Maximum index of quantization tables.
// nhuffActables IN/OUT: Number of AC Huffman tables.
// nhuffDctables IN/OUT: Number of DC Huffman tables.
// maxhuffindex IN/OUT: Maximum index of Huffman tables.
// jFmtQuant IN/OUT: Formatted quantization table info.
// jFmtAcHuffman IN/OUT: Formatted AC Huffman table info.
// jFmtDcHuffman IN/OUT: Formatted DC Huffman table info.
//
// jEncFmtQuant IN/OUT: Pointer to one of the above, or
// to externally persisted table.
// jEncFmtAcHuffman IN/OUT: Pointer to one of the above, or
// to externally persisted table.
// jEncFmtDcHuffman IN/OUT: Pointer to one of the above, or
// to externally persisted table.
//
// use_default_qtables IN: Set to default quantization tables.
// Clear to supply your own.
// use_default_htables IN: Set to default Huffman tables.
// Clear to supply your own.
// rawquanttables IN: Up to 4 sets of quantization tables.
// rawhufftables IN: Alternating pairs (DC/AC) of up to 4
// sets of raw Huffman tables.
// HuffIdentifierAC IN: Indicates what channel the user-
// supplied Huffman AC tables apply to.
// HuffIdentifierDC IN: Indicates what channel the user-
// supplied Huffman DC tables apply to.
//
// jframe OUT: Structure with frame-specific info.
// needframe OUT: TRUE when a frame has been detected.
//
// jscan Persistence for current scan pointer when
// interrupted.
//
// state OUT: Contains info on the state of the IJL.
// SawAdobeMarker OUT: Decoder saw an APP14 marker somewhere.
// AdobeXform OUT: If SawAdobeMarker TRUE, this indicates
// the JPEG color space given by that marker.
//
// rowoffsets Persistence for the decoder MCU row origins
// when decoding by ROI. Offsets (in bytes
// from the beginning of the entropy data)
// to the start of each of the decoded rows.
// Fill the offsets with -1 if they have not
// been initalized and NULL could be the
// offset to the first row.
//
// MCUBuf OUT: Quadword aligned internal buffer.
// Big enough for the largest MCU
// (10 blocks) with extra room for
// additional operations.
// tMCUBuf OUT: Version of above, without alignment.
//
// processor_type OUT: Determines type of processor found
// during initialization.
//
// raw_coefs IN: Place to hold pointers to raw data buffers or
// raw DCT coefficients buffers
//
// progressive_found OUT: 1 when progressive image detected.
// coef_buffer IN: Pointer to a larger buffer containing
// frequency coefficients when they
// cannot be decoded dynamically
// (i.e., as in progressive decoding).
//
// upsampling_type IN: Type of sampling:
// IJL_BOX_FILTER or IJL_TRIANGLE_FILTER.
// SAMPLING_STATE* OUT: pointer to structure, describing current
// condition of upsampling
//
// AdobeVersion OUT version field, if Adobe APP14 marker detected
// AdobeFlags0 OUT flags0 field, if Adobe APP14 marker detected
// AdobeFlags1 OUT flags1 field, if Adobe APP14 marker detected
//
// jfif_app0_detected OUT: 1 - if JFIF APP0 marker detected,
// 0 - if not
// jfif_app0_version IN/OUT The JFIF file version
// jfif_app0_units IN/OUT units for the X and Y densities
// 0 - no units, X and Y specify
// the pixel aspect ratio
// 1 - X and Y are dots per inch
// 2 - X and Y are dots per cm
// jfif_app0_Xdensity IN/OUT horizontal pixel density
// jfif_app0_Ydensity IN/OUT vertical pixel density
//
// jpeg_comment IN pointer to JPEG comments
// jpeg_comment_size IN/OUT size of JPEG comments, in bytes
//
// raw_coefs IN/OUT if !NULL, then pointer to vector of pointers
// (size = JPGChannels) to buffers for raw (short)
// dct coefficients. 1 pointer corresponds to one
// component;
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _JPEG_PROPERTIES
{
/* Compression/Decompression control. */
IJLIOTYPE iotype; /* default = IJL_SETUP */
IJL_RECT roi; /* default = 0 */
DCTTYPE dcttype; /* default = IJL_AAN */
FAST_MCU_PROCESSING_TYPE fast_processing; /* default = IJL_NO_CC_OR_US */
int interrupt; /* default = FALSE */
/* DIB specific I/O data specifiers. */
unsigned char* DIBBytes; /* default = NULL */
int DIBWidth; /* default = 0 */
int DIBHeight; /* default = 0 */
int DIBPadBytes; /* default = 0 */
int DIBChannels; /* default = 3 */
IJL_COLOR DIBColor; /* default = IJL_BGR */
IJL_DIBSUBSAMPLING DIBSubsampling; /* default = IJL_NONE */
int DIBLineBytes; /* default = 0 */
/* JPEG specific I/O data specifiers. */
const char* JPGFile; /* default = NULL */
unsigned char* JPGBytes; /* default = NULL */
int JPGSizeBytes; /* default = 0 */
int JPGWidth; /* default = 0 */
int JPGHeight; /* default = 0 */
int JPGChannels; /* default = 3 */
IJL_COLOR JPGColor; /* default = IJL_YCBCR */
IJL_JPGSUBSAMPLING JPGSubsampling; /* default = IJL_411 */
int JPGThumbWidth; /* default = 0 */
int JPGThumbHeight; /* default = 0 */
/* JPEG conversion properties. */
int cconversion_reqd; /* default = TRUE */
int upsampling_reqd; /* default = TRUE */
int jquality; /* default = 75 */
int jinterleaveType; /* default = 0 */
int numxMCUs; /* default = 0 */
int numyMCUs; /* default = 0 */
/* Tables. */
int nqtables;
int maxquantindex;
int nhuffActables;
int nhuffDctables;
int maxhuffindex;
QUANT_TABLE jFmtQuant[4];
HUFFMAN_TABLE jFmtAcHuffman[4];
HUFFMAN_TABLE jFmtDcHuffman[4];
short* jEncFmtQuant[4];
HUFFMAN_TABLE* jEncFmtAcHuffman[4];
HUFFMAN_TABLE* jEncFmtDcHuffman[4];
/* Allow user-defined tables. */
int use_external_qtables;
int use_external_htables;
JPEGQuantTable rawquanttables[4];
JPEGHuffTable rawhufftables[8];
char HuffIdentifierAC[4];
char HuffIdentifierDC[4];
/* Frame specific members. */
FRAME jframe;
int needframe;
/* SCAN persistent members. */
SCAN* jscan;
/* State members. */
STATE state;
int SawAdobeMarker;
int AdobeXform;
/* ROI decoder members. */
ENTROPYSTRUCT* rowoffsets;
/* Intermediate buffers. */
unsigned char* MCUBuf;
unsigned char tMCUBuf[720*2];
/* Processor detected. */
PROCESSOR_TYPE processor_type;
RAW_DATA_TYPES_STATE* raw_coefs;
/* Progressive mode members. */
int progressive_found;
short* coef_buffer;
/* Upsampling mode members. */
UPSAMPLING_TYPE upsampling_type;
SAMPLING_STATE* sampling_state_ptr;
/* Adobe APP14 segment variables */
unsigned short AdobeVersion; /* default = 100 */
unsigned short AdobeFlags0; /* default = 0 */
unsigned short AdobeFlags1; /* default = 0 */
/* JFIF APP0 segment variables */
int jfif_app0_detected;
unsigned short jfif_app0_version; /* default = 0x0101 */
unsigned char jfif_app0_units; /* default = 0 - pixel */
unsigned short jfif_app0_Xdensity; /* default = 1 */
unsigned short jfif_app0_Ydensity; /* default = 1 */
/* comments related fields */
char* jpeg_comment; /* default = NULL */
unsigned short jpeg_comment_size; /* default = 0 */
} JPEG_PROPERTIES;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: JPEG_CORE_PROPERTIES
//
// Purpose: This is the primary data structure between the IJL and
// the external user. It stores JPEG state information
// and controls the IJL. It is user-modifiable.
//
// See the Developer's Guide for details on appropriate usage.
//
// Context: Used by all low-level IJL routines to store
// pseudo-global information.
//
// Fields:
//
// UseJPEGPROPERTIES Set this flag != 0 if you wish to override
// the JPEG_CORE_PROPERTIES "IN" parameters with
// the JPEG_PROPERTIES parameters.
//
// DIBBytes IN: Pointer to buffer of uncompressed data.
// DIBWidth IN: Width of uncompressed data.
// DIBHeight IN: Height of uncompressed data.
// DIBPadBytes IN: Padding (in bytes) at end of each
// row in the uncompressed data.
// DIBChannels IN: Number of components in the
// uncompressed data.
// DIBColor IN: Color space of uncompressed data.
// DIBSubsampling IN: Required to be IJL_NONE or IJL_422.
//
// JPGFile IN: Pointer to file based JPEG.
// JPGBytes IN: Pointer to buffer based JPEG.
// JPGSizeBytes IN: Max buffer size. Used with JPGBytes.
// OUT: Number of compressed bytes written.
// JPGWidth IN: Width of JPEG image.
// OUT: After reading (except READHEADER).
// JPGHeight IN: Height of JPEG image.
// OUT: After reading (except READHEADER).
// JPGChannels IN: Number of components in JPEG image.
// OUT: After reading (except READHEADER).
// JPGColor IN: Color space of JPEG image.
// JPGSubsampling IN: Subsampling of JPEG image.
// OUT: After reading (except READHEADER).
// JPGThumbWidth OUT: JFIF embedded thumbnail width [0-255].
// JPGThumbHeight OUT: JFIF embedded thumbnail height [0-255].
//
// cconversion_reqd OUT: If color conversion done on decode, TRUE.
// upsampling_reqd OUT: If upsampling done on decode, TRUE.
// jquality IN: [0-100] where highest quality is 100.
//
// jprops "Low-Level" IJL data structure.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef struct _JPEG_CORE_PROPERTIES
{
int UseJPEGPROPERTIES; /* default = 0 */
/* DIB specific I/O data specifiers. */
unsigned char* DIBBytes; /* default = NULL */
int DIBWidth; /* default = 0 */
int DIBHeight; /* default = 0 */
int DIBPadBytes; /* default = 0 */
int DIBChannels; /* default = 3 */
IJL_COLOR DIBColor; /* default = IJL_BGR */
IJL_DIBSUBSAMPLING DIBSubsampling; /* default = IJL_NONE */
/* JPEG specific I/O data specifiers. */
const char* JPGFile; /* default = NULL */
unsigned char* JPGBytes; /* default = NULL */
int JPGSizeBytes; /* default = 0 */
int JPGWidth; /* default = 0 */
int JPGHeight; /* default = 0 */
int JPGChannels; /* default = 3 */
IJL_COLOR JPGColor; /* default = IJL_YCBCR */
IJL_JPGSUBSAMPLING JPGSubsampling; /* default = IJL_411 */
int JPGThumbWidth; /* default = 0 */
int JPGThumbHeight; /* default = 0 */
/* JPEG conversion properties. */
int cconversion_reqd; /* default = TRUE */
int upsampling_reqd; /* default = TRUE */
int jquality; /* default = 75 */
/* Low-level properties. */
JPEG_PROPERTIES jprops;
} JPEG_CORE_PROPERTIES;
/*D*
////////////////////////////////////////////////////////////////////////////
// Name: IJLERR
//
// Purpose: Listing of possible "error" codes returned by the IJL.
//
// See the Developer's Guide for details on appropriate usage.
//
// Context: Used for error checking.
//
////////////////////////////////////////////////////////////////////////////
*D*/
typedef enum _IJLERR
{
/* The following "error" values indicate an "OK" condition. */
IJL_OK = 0,
IJL_INTERRUPT_OK = 1,
IJL_ROI_OK = 2,
/* The following "error" values indicate an error has occurred. */
IJL_EXCEPTION_DETECTED = -1,
IJL_INVALID_ENCODER = -2,
IJL_UNSUPPORTED_SUBSAMPLING = -3,
IJL_UNSUPPORTED_BYTES_PER_PIXEL = -4,
IJL_MEMORY_ERROR = -5,
IJL_BAD_HUFFMAN_TABLE = -6,
IJL_BAD_QUANT_TABLE = -7,
IJL_INVALID_JPEG_PROPERTIES = -8,
IJL_ERR_FILECLOSE = -9,
IJL_INVALID_FILENAME = -10,
IJL_ERROR_EOF = -11,
IJL_PROG_NOT_SUPPORTED = -12,
IJL_ERR_NOT_JPEG = -13,
IJL_ERR_COMP = -14,
IJL_ERR_SOF = -15,
IJL_ERR_DNL = -16,
IJL_ERR_NO_HUF = -17,
IJL_ERR_NO_QUAN = -18,
IJL_ERR_NO_FRAME = -19,
IJL_ERR_MULT_FRAME = -20,
IJL_ERR_DATA = -21,
IJL_ERR_NO_IMAGE = -22,
IJL_FILE_ERROR = -23,
IJL_INTERNAL_ERROR = -24,
IJL_BAD_RST_MARKER = -25,
IJL_THUMBNAIL_DIB_TOO_SMALL = -26,
IJL_THUMBNAIL_DIB_WRONG_COLOR = -27,
IJL_BUFFER_TOO_SMALL = -28,
IJL_UNSUPPORTED_FRAME = -29,
IJL_ERR_COM_BUFFER = -30,
IJL_RESERVED = -99
} IJLERR;
/* /////////////////////////////////////////////////////////////////////////
// Function Prototypes (API Calls) //
///////////////////////////////////////////////////////////////////////// */
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: ijlInit
//
// Purpose: Used to initalize the IJL.
//
// See the Developer's Guide for details on appropriate usage.
//
// Context: Always call this before anything else.
// Also, only call this with a new jcprops structure, or
// after calling IJL_Free. Otherwise, dynamically
// allocated memory may be leaked.
//
// Returns: Any IJLERR value. IJL_OK indicates success.
//
// Parameters:
// jcprops Pointer to an externally allocated
// JPEG_CORE_PROPERTIES structure.
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(IJLERR, ijlInit, ( JPEG_CORE_PROPERTIES* jcprops ));
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: ijlFree
//
// Purpose: Used to properly close down the IJL.
//
// See the Developer's Guide for details on appropriate usage.
//
// Context: Always call this when done using the IJL to perform
// clean-up of dynamically allocated memory.
// Note, IJL_Init will have to be called to use the
// IJL again.
//
// Returns: Any IJLERR value. IJL_OK indicates success.
//
// Parameters:
// jcprops Pointer to an externally allocated
// JPEG_CORE_PROPERTIES structure.
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(IJLERR, ijlFree, ( JPEG_CORE_PROPERTIES* jcprops ));
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: IJL_Read
//
// Purpose: Used to read JPEG data (entropy, or header, or both) into
// a user-supplied buffer (to hold the image data) and/or
// into the JPEG_CORE_PROPERTIES structure (to hold the
// header info).
//
// Context: See the Developer's Guide for a detailed description
// on the use of this function. The jcprops main data
// members are checked for consistency.
//
// Returns: Any IJLERR value. IJL_OK indicates success.
//
// Parameters:
// jcprops Pointer to an externally allocated
// JPEG_CORE_PROPERTIES structure.
// iotype Specifies what type of read operation to perform.
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(IJLERR, ijlRead, ( JPEG_CORE_PROPERTIES* jcprops, IJLIOTYPE iotype ));
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: ijlWrite
//
// Purpose: Used to write JPEG data (entropy, or header, or both) into
// a user-supplied buffer (to hold the image data) and/or
// into the JPEG_CORE_PROPERTIES structure (to hold the
// header info).
//
// Context: See the Developer's Guide for a detailed description
// on the use of this function. The jcprops main data
// members are checked for consistency.
//
// Returns: Any IJLERR value. IJL_OK indicates success.
//
// Parameters:
// jcprops Pointer to an externally allocated
// JPEG_CORE_PROPERTIES structure.
// iotype Specifies what type of write operation to perform.
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(IJLERR, ijlWrite, ( JPEG_CORE_PROPERTIES* jcprops, IJLIOTYPE iotype ));
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: ijlGetLibVersion
//
// Purpose: To identify the version number of the IJL.
//
// Context: Call to get the IJL version number.
//
// Returns: pointer to IJLibVersion struct
//
// Parameters: none
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(const IJLibVersion*, ijlGetLibVersion, (void));
/*F*
////////////////////////////////////////////////////////////////////////////
// Name: ijlErrorStr
//
// Purpose: Gets the string to describe error code.
//
// Context: Is called to get descriptive string on arbitrary IJLERR code.
//
// Returns: pointer to string
//
// Parameters: IJLERR - IJL error code
//
////////////////////////////////////////////////////////////////////////////
*F*/
IJLAPI(const char*, ijlErrorStr, (IJLERR code));
#if defined( __cplusplus )
}
#endif
#endif /* __IJL_H__ */
//file name main.cpp
#include "stdafx.h"
// no more padding 0 at end of row since we calloc
void doScaleImageInBytes(PBYTE DstBuffer, DWORD DstSize, DWORD WidthInPixel, DWORD WidthInBytes, DWORD PageHeight, DWORD HardXDpi,
DWORD HardYDpi, DWORD SoftXDpi, DWORD SoftYDpi, PBYTE scaledBuffer, DWORD scaledBufferSize,
DWORD scaledWidthInPixel, DWORD scaledHeightInPixel, DWORD scaledWidthInBytes, DWORD BitCount)
{
DWORD BytesPerPixel = BitCount / 8;
int rowCarryon = 0, colCarryon = 0, rowDiff = SoftYDpi - PageHeight, colDiff = SoftXDpi - HardXDpi;
PBYTE srcRowPtr = NULL, dstRowPtr = NULL;
PBYTE srcColPtr = NULL, dstColPtr = NULL;
WidthInBytes = WidthInPixel * BitCount / 8;
srcRowPtr = DstBuffer;
dstRowPtr = scaledBuffer;
/*
int paddedBytes = 0;
paddedBytes = scaledWidthInBytes - BitCount / 8 * scaledWidthInPixel;
// init
*/
rowCarryon = 0;
for (int dstRow = 0; dstRow < scaledHeightInPixel; dstRow ++)
{
dstColPtr = dstRowPtr;
srcColPtr = srcRowPtr;
// definitely we need to init
colCarryon = 0;
for (int dstCol = 0; dstCol < scaledWidthInPixel; dstCol ++)
{
memcpy(dstColPtr, srcColPtr, BytesPerPixel);
//dst col ptr always advance
dstColPtr += BytesPerPixel;
//here we calculate col carryon to decide if src col ptr needs advancing.
if (colCarryon >= HardXDpi){
colCarryon -= HardXDpi;
}else{
srcColPtr += BytesPerPixel;
colCarryon += colDiff;
}
}
//dst row always move on
dstRowPtr += scaledWidthInBytes;
/*
// padding 0 at end of row;
dstColPtr += BytesPerPixel;//first, advance
memset(dstColPtr, 0, paddedBytes);
*/
//here we calculate carryon to decide if src row need to advance
if (rowCarryon >= HardYDpi){
//in this case, we copy current row by not advancing
rowCarryon -= HardYDpi;
}else{
//we advance src row to next
srcRowPtr += WidthInBytes;
rowCarryon += rowDiff;
}
}
}
// QH: handling bits copying is painful, so I decide to only support of 1bpp, or BitCount=1
// actually, the padding 0 is really not necessary if we use "calloc" to initialize memory
void doScaleImageInBits(PBYTE DstBuffer, DWORD DstSize, DWORD WidthInPixel, DWORD WidthInBytes, DWORD PageHeight, DWORD HardXDpi,
DWORD HardYDpi, DWORD SoftXDpi, DWORD SoftYDpi, PBYTE scaledBuffer, DWORD scaledBufferSize,
DWORD scaledWidthInPixel, DWORD scaledHeightInPixel, DWORD scaledWidthInBytes, DWORD BitCount)
{
int rowCarryon = 0, colCarryon = 0, rowDiff = SoftYDpi - PageHeight, colDiff = SoftXDpi - HardXDpi;
PBYTE srcRowPtr = NULL, dstRowPtr = NULL;
PBYTE srcColPtr = NULL, dstColPtr = NULL;
BYTE srcMask, dstMask;
WidthInBytes = WidthInPixel * BitCount / 8;
srcRowPtr = DstBuffer;
dstRowPtr = scaledBuffer;
/*
int paddedBytes = 0;
paddedBytes = scaledWidthInBytes - (scaledWidthInPixel + 7) / 8;
// init
*/
for (int dstRow = 0; dstRow < scaledHeightInPixel; dstRow ++)
{
dstColPtr = dstRowPtr;
srcColPtr = srcRowPtr;
colCarryon = 0; //don't forget!!!
srcMask = 0x80;
srcMask = 0x80;
for (int dstCol = 0; dstCol < scaledWidthInPixel; dstCol ++)
{
// get src bit and then copy dst bit
if (srcMask & (*srcColPtr)){
*dstColPtr |= dstMask;
}
// we don't write 0 because we use "calloc" to initialize to 0
/*
else {
*dstColPtr &= (~dstMask);//set to 0
}
*/
//dst col ptr always advance
dstMask = dstMask >> 1;
if (! dstMask){
// this means we cross byte
dstColPtr ++; //1bpp
dstMask = 0x80;
}
//here we calculate col carryon to decide if src col ptr needs advancing.
if (colCarryon >= HardXDpi){
// here we don't advance, we repeat source by not advancing srcColptr
colCarryon -= HardXDpi;
}else{
//here we move srcColptr
colCarryon += colDiff;
srcMask = srcMask >> 1;
if (! srcMask){
srcColPtr ++;
srcMask = 0x80;
}
}
}
//dst row always move on
dstRowPtr += scaledWidthInBytes;
// here we need pad 0 till end of row
//first, we need position our pointer correctly
/*
if (dstMask){
dstColPtr ++;
}
while (dstMask)
{
*dstColPtr &= (~dstMask);//set to 0
dstMask = dstMask >> 1;
}
memset(dstColPtr, 0, paddedBytes);
*/
//here we calculate carryon to decide if src row need to advance
if (rowCarryon >= HardYDpi){
//in this case, we copy current row by not advancing
rowCarryon -= HardYDpi;
}else{
//we advance src row to next
rowCarryon += rowDiff;
srcRowPtr += WidthInBytes;
}
}
}
BOOL scaleImage(PBYTE &DstBuffer, DWORD &DstSize, PBYTE srcBuffer, DWORD srcSize, DWORD BitCount,
LONG& WidthInPixel, LONG& WidthInBytes,
LONG& PageHeight, DWORD HardXDpi, DWORD HardYDpi, DWORD SoftXDpi, DWORD SoftYDpi)
{
DWORD scaledWidthInPixel =0, scaledHeightInPixel = 0, scaledWidthInBytes = 0, scaledBufferSize = 0;
PBYTE scaledBuffer = NULL;
scaledWidthInPixel = (WidthInPixel * SoftXDpi) / HardXDpi;
scaledHeightInPixel = (PageHeight * SoftYDpi) / HardYDpi;
scaledWidthInBytes = ((scaledWidthInPixel * BitCount + 31) & (~31)) / 8;
scaledBufferSize = scaledWidthInBytes * scaledHeightInPixel;
if (scaledBufferSize >= srcSize){
// we initialize to 0, then we don't have to pad 0
if ((scaledBuffer = (PBYTE)calloc(scaledBufferSize, 1)) == NULL){
return FALSE;
}
}
switch (BitCount)
{
case 8:
case 24:
doScaleImageInBytes(srcBuffer, srcSize, WidthInPixel, WidthInBytes, PageHeight, HardXDpi, HardYDpi,
SoftXDpi, SoftYDpi, scaledBuffer, scaledBufferSize, scaledWidthInPixel,
scaledHeightInPixel, scaledWidthInBytes, BitCount);
break;
case 1:
doScaleImageInBits(srcBuffer, srcSize, WidthInPixel, WidthInBytes, PageHeight, HardXDpi, HardYDpi,
SoftXDpi, SoftYDpi, scaledBuffer, scaledBufferSize, scaledWidthInPixel,
scaledHeightInPixel, scaledWidthInBytes, BitCount);
break;
}
//swap buffer
DstBuffer = scaledBuffer;
DstSize = scaledBufferSize;
WidthInPixel = scaledWidthInPixel;
PageHeight = scaledHeightInPixel;
WidthInBytes = scaledWidthInBytes;
return TRUE;
}
bool scalePicture(LPCTSTR fileName)
{
RGBQUAD monoColor[2] =
{
{0, 0, 255, 0},
{255, 0, 0, 0}
};
bool result = false;
PBITMAPINFO pbi = NULL;
PBITMAPINFOHEADER pbih;
LPBYTE pbits;
long widthBytes = 0;
LPBYTE dstBuffer = NULL;
DWORD dstSize = 0, srcSize;
LPBYTE ptr;
int colorNumber = 0;
long scaledWidth, scaledHeight;
DWORD bitCount;
if (readImageFile(fileName, pbi))
{
pbih = (PBITMAPINFOHEADER)(pbi);
widthBytes = ((pbih->biWidth * pbih->biBitCount + 31)&(~31)) / 8;
colorNumber = pbih->biClrUsed;
if (pbih->biBitCount < 16 && pbih->biClrUsed == 0)
{
colorNumber = (1 << pbih->biBitCount);
}
pbits = ((LPBYTE)(pbi)+ colorNumber * sizeof(RGBQUAD) + sizeof(BITMAPINFOHEADER));
scaledWidth = pbih->biWidth;
scaledHeight = pbih->biHeight;
srcSize = widthBytes * scaledHeight;
scaleImage(dstBuffer, dstSize, pbits, srcSize, pbih->biBitCount, scaledWidth, widthBytes, scaledHeight, pbih->biWidth,
pbih->biHeight, pbih->biWidth * 1, pbih->biHeight * 1);
result = true;
bitCount = pbih->biBitCount;
free(pbi);
if (result)
{
pbi = (PBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + dstSize);
pbih = (PBITMAPINFOHEADER)(pbi);
memset(pbi, 0, sizeof(BITMAPINFOHEADER));
pbih->biBitCount= bitCount;
pbih->biSize = sizeof(BITMAPINFOHEADER);
pbih->biWidth = scaledWidth;
pbih->biHeight = scaledHeight;
pbih->biPlanes =1;
colorNumber = pbih->biClrUsed;
// only support mono
if (pbih->biBitCount == 1)
{
colorNumber = (1 << pbih->biBitCount);
memcpy(&pbi->bmiColors[0], monoColor, sizeof(RGBQUAD) * 2);
}
pbits = (LPBYTE)pbi + pbih->biSize + colorNumber * sizeof(RGBQUAD);
memcpy(pbits, dstBuffer, dstSize);
createBmpFile(_T("result.bmp"), pbi);
}
}
return result;
}
int _tmain(int argc, LPCTSTR* argv)
{
/*
if (argc == 2)
{
if (countColor(argv[1]))
{
printf("succeed\n");
}
}
*/
scalePicture(_T("input.bmp"));
return 0;
}