msrle32.c
来自「Wine-20031016」· C语言 代码 · 共 1,915 行 · 第 1/4 页
C
1,915 行
/* * Copyright 2002-2003 Michael G黱newig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* TODO: * - some improvements possible * - implement DecompressSetPalette? -- does we need it for anything? */#include <assert.h>#include "msrle_private.h"#include "winnls.h"#include "winuser.h"#include "windowsx.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(msrle32);static HINSTANCE MSRLE32_hModule = 0;#define ABS(a) ((a) < 0 ? -(a) : (a))#define SQR(a) ((a) * (a))#define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)inline WORD ColorCmp(WORD clr1, WORD clr2){ register UINT a = (clr1-clr2); return SQR(a);}inline WORD Intensity(RGBQUAD clr){ return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;}#define GetRawPixel(lpbi,lp,x) \ ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \ ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))/*****************************************************************************//* utility functions */static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);static void LoadWideString(UINT id, LPWSTR str, INT len);static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);/* compression functions */static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn);static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);/* decompression functions */static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, LPBYTE lpIn, LPBYTE lpOut);static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, LPBYTE lpIn, LPBYTE lpOut);/* API functions */static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut);static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPCBITMAPINFOHEADER lpbiOut);static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPCBITMAPINFOHEADER lpbiOut);static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPCBITMAPINFOHEADER lpbiOut);static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);static LRESULT CompressEnd(CodecInfo *pi);static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut);static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPCBITMAPINFOHEADER lpbiOut);static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPCBITMAPINFOHEADER lpbiOut);static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);static LRESULT DecompressEnd(CodecInfo *pi);static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut);/*****************************************************************************/static void LoadWideString(UINT id, LPWSTR str, INT len){ char szTemp[80]; LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp)); MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len);}static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi){ /* pre-conditions */ assert(lpbi != NULL); if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \ lpbi->biPlanes != 1) return FALSE; if (lpbi->biCompression == BI_RLE4) { if (lpbi->biBitCount != 4 || \ (lpbi->biWidth % 2) != 0) return FALSE; } else if (lpbi->biCompression == BI_RLE8) { if (lpbi->biBitCount != 8) return FALSE; } else return FALSE; return TRUE;}static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi){ /* pre-conditions */ assert(lpbi != NULL); /* check structure version/planes/compression */ if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || lpbi->biPlanes != 1) return FALSE; if (lpbi->biCompression != BI_RGB && lpbi->biCompression != BI_BITFIELDS) return FALSE; /* check bit-depth */ if (lpbi->biBitCount != 1 && lpbi->biBitCount != 4 && lpbi->biBitCount != 8 && lpbi->biBitCount != 15 && lpbi->biBitCount != 16 && lpbi->biBitCount != 24 && lpbi->biBitCount != 32) return FALSE; /* check for size(s) */ if (!lpbi->biWidth || !lpbi->biHeight) return FALSE; /* image with zero size, makes no sense so error ! */ if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1) return FALSE; /* image too big ! */ /* check for non-existent colortable for hi- and true-color DIB's */ if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0) return FALSE; return TRUE;}static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr){ INT diff = 0x00FFFFFF; UINT i; UINT idx = 0; /* pre-conditions */ assert(clrs != NULL); for (i = 0; i < count; i++) { int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed); int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen); int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue); r = r*r + g*g + b*b; if (r < diff) { idx = i; diff = r; if (diff == 0) break; } } return idx;}/*****************************************************************************/void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn){ WORD wIntensityTbl[256]; DWORD lInLine, lOutLine; LPWORD lpOut; UINT i; LONG y; /* pre-conditions */ assert(pi != NULL && lpbiIn != NULL && lpIn != NULL); assert(pi->pCurFrame != NULL); lInLine = DIBWIDTHBYTES(*lpbiIn); lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u; lpOut = pi->pCurFrame; assert(lpbiIn->biClrUsed != 0); { const RGBQUAD *lp = (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize); for (i = 0; i < lpbiIn->biClrUsed; i++) wIntensityTbl[i] = Intensity(lp[i]); } for (y = 0; y < lpbiIn->biHeight; y++) { LONG x; switch (lpbiIn->biBitCount) { case 1: for (x = 0; x < lpbiIn->biWidth / 8; x++) { for (i = 0; i < 7; i++) lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1]; } break; case 4: for (x = 0; x < lpbiIn->biWidth / 2; x++) { lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)]; lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)]; } break; case 8: for (x = 0; x < lpbiIn->biWidth; x++) lpOut[x] = wIntensityTbl[lpIn[x]]; break; } lpIn += lInLine; lpOut += lOutLine; }}static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi){ LONG a, b, size; /* pre-condition */ assert(lpbi != NULL); a = lpbi->biWidth / 255; b = lpbi->biWidth % 255; if (lpbi->biBitCount <= 4) { a /= 2; b /= 2; } size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2))); return size * lpbi->biHeight;}/* lpP => current pos in previous frame * lpA => previous pos in current frame * lpB => current pos in current frame */static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width){ INT count; WORD clr1, clr2; /* pre-conditions */ assert(lpA && lpB && lDist >= 0 && width > 0); if (pos >= width) return 0; if (pos+1 == width) return 1; clr1 = lpB[pos++]; clr2 = lpB[pos]; count = 2; while (pos + 1 < width) { WORD clr3, clr4; clr3 = lpB[++pos]; if (pos + 1 >= width) return count + 1; clr4 = lpB[++pos]; if (ColorCmp(clr1, clr3) <= lDist && ColorCmp(clr2, clr4) <= lDist) { /* diff at end? -- look-ahead for atleast ?? more encodable pixel */ if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist && ColorCmp(clr2,lpB[pos+2]) <= lDist) { if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist && ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist) return count - 3; /* followed by atleast 4 encodable pixels */ return count - 2; } } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { /* 'compare' with previous frame for end of diff */ INT count2 = 0; /* FIXME */ if (count2 >= 8) return count; pos -= count2; } count += 2; clr1 = clr3; clr2 = clr4; } return count;}/* lpP => current pos in previous frame * lpA => previous pos in current frame * lpB => current pos in current frame */static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width){ INT count; for (count = 0; pos < width; pos++, count++) { if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) { /* diff at end? -- look-ahead for some more encodable pixel */ if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist) return count - 1; if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist) return count - 1; } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { /* 'compare' with previous frame for end of diff */ INT count2 = 0; for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) { if (ColorCmp(lpP[pos], lpB[pos]) > lDist) break; } if (count2 > 4) return count; pos -= count2; } } return count;}static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage){ LPBYTE lpOut = *ppOut; INT count, pos; WORD clr1, clr2; /* try to encode as many pixel as possible */ count = 1; pos = x; clr1 = lpC[pos++]; if (pos < lpbi->biWidth) { clr2 = lpC[pos]; for (++count; pos + 1 < lpbi->biWidth; ) { ++pos; if (ColorCmp(clr1, lpC[pos]) > lDist) break; count++; if (pos + 1 >= lpbi->biWidth) break; ++pos; if (ColorCmp(clr2, lpC[pos]) > lDist) break; count++; } } if (count < 4) { /* add some pixel for absoluting if possible */ count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); assert(count > 0); /* check for near end of line */ if (x + count > lpbi->biWidth) count = lpbi->biWidth - x; /* absolute pixel(s) in groups of atleast 3 and maximal 254 pixel */ while (count > 2) { INT i; INT size = min(count, 254); int bytes = ((size + 1) & (~1)) / 2; BOOL extra_byte = bytes & 0x01; *lpSizeImage += 2 + bytes + extra_byte; assert(((*lpSizeImage) % 2) == 0); count -= size; *lpOut++ = 0; *lpOut++ = size; for (i = 0; i < size; i += 2) { clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; x++; if (i + 1 < size) { clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; x++; } else clr2 = 0; *lpOut++ = (clr1 << 4) | clr2; } if (extra_byte) *lpOut++ = 0; } if (count > 0) { /* too less for absoluting so we must encode them */ assert(count <= 2); *lpSizeImage += 2; clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; x++; if (count == 2) { clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; x++; } else clr2 = 0; *lpOut++ = count; *lpOut++ = (clr1 << 4) | clr2; } } else { /* encode count pixel(s) */ clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) | pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]); x += count; while (count > 0) { INT size = min(count, 254); *lpSizeImage += 2; count -= size; *lpOut++ = size; *lpOut++ = clr1; } } *ppOut = lpOut; return x;}static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage){ LPBYTE lpOut = *ppOut; INT count, pos; WORD clr; assert(lpbi->biBitCount <= 8); assert(lpbi->biCompression == BI_RGB); /* try to encode as much as possible */ pos = x; clr = lpC[pos++]; for (count = 1; pos < lpbi->biWidth; count++) { if (ColorCmp(clr, lpC[pos++]) > lDist) break; } if (count < 2) { /* add some more pixels for absoluting if possible */ count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); assert(count > 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?