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 + -
显示快捷键?