⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 image.cpp

📁 俄罗斯人开发的大名鼎鼎的Pocket Pc 阅读器haaliread的源代码,visual c
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2001,2002,2003 Mike Matsnev.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice immediately at the beginning of the file, without modification,
 *    this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Absolutely no warranty of function or purpose is made by the author
 *    Mike Matsnev.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * $Id: Image.cpp,v 1.12.2.7 2003/09/21 12:07:35 mike Exp $
 * 
 */

// XXX handle out of memory exceptions gracefully

#ifdef STANDALONE
#include <windows.h>
#else
#include <afxwin.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <math.h>

extern "C" {
  #include <jpeglib.h>
  #include <jerror.h>
  #include <png.h>
};

#include "ptr.h"
#include "Image.h"

#ifndef STANDALONE
#include "config.h"
#include "TextViewNG.h"
#endif

#define	INBUF_SIZE    4096

// supported bitmap formats
enum {
  BF_UNKNOWN,
  BF_565,
  BF_555,
  BF_888
};

struct GXDisplayProperties {
	DWORD cxWidth;
	DWORD cyHeight;			// notice lack of 'th' in the word height.
	long cbxPitch;			// number of bytes to move right one x pixel - can be negative.
	long cbyPitch;			// number of bytes to move down one y pixel - can be negative.
	long cBPP;				// # of bits in each pixel
	DWORD ffFormat;			// format flags.
};

#define kfDirect555	0x40		// 5 bits each for red, green and blue values in a pixel.
#define kfDirect565	0x80		// 5 red bits, 6 green bits and 5 blue bits per pixel
#define kfDirect888	0x100		// 8 bits each for red, green and blue values in a pixel.
#define kfDirect444	0x200		// 4 red, 4 green, 4 blue

typedef unsigned char u8;
typedef unsigned int u32;
typedef signed int s32;
typedef unsigned short u16;

static u8   gamma_table[256];

static void	set_gamma(double image_gamma) {
  double    disp_gamma=
#ifdef STANDALONE
    1.8;
#else
    CTVApp::GetInt(_T("Gamma"),DEF_GAMMA)/1000000.0;
#endif
  if (disp_gamma<1)
    disp_gamma=1;
  if (disp_gamma>5)
    disp_gamma=5;
  double    g=1/(image_gamma*disp_gamma);
  int	    i;

  for (i=0;i<256;++i)
    gamma_table[i]=((int)(pow(i/256.0,g)*256.0));
}

// returns resized line with pixels scaled by inw
static void	resize_line_plain(u8 *in,u32 inw,u32 *out,u32 outw,u8 * /* bg */) {
  u32	  inptr=0; // input pixel position inside the output pixel
  u32	  outptr=inw;
  u8	  *top=in+inw*3; // pixel after the last

  out[0]=out[1]=out[2]=0; // initialize first output pixel
  do { // for each input pixel
    if (inptr+outw>outptr) { // input pixel crosses two output pixels
      // red
      out[0] += in[0] * (outptr - inptr); // add to current pixel
      out[3] = in[0] * (outw - (outptr - inptr)); // and initialize the next one
      // green
      out[1] += in[1] * (outptr - inptr); // add to current pixel
      out[4] = in[1] * (outw - (outptr - inptr)); // and initialize the next one
      // blue
      out[2] += in[2] * (outptr - inptr); // add to current pixel
      out[5] = in[2] * (outw - (outptr - inptr)); // and initialize the next one
      // advance to next pixel
      out += 3;
      outptr += inw;
    } else { // completely contained
      out[0] += in[0] * outw;
      out[1] += in[1] * outw;
      out[2] += in[2] * outw;
    }
    in+=3; // next input pixel
    inptr+=outw;
  } while (in<top);
}

// returns resized line with pixels scaled by inw
static void	resize_line_alpha(u8 *in,u32 inw,u32 *out,u32 outw,u8 *bg) {
  u32	  inptr=0; // input pixel position inside the output pixel
  u32	  outptr=inw;
  u8	  *top=in+inw*4; // pixel after the last
  u8	  pval; // current pixel value
  u8	  transp;
  u8	  opacity;

  out[0]=out[1]=out[2]=0; // initialize first output pixel
  do { // for each input pixel
    opacity = in[3];
    transp = 255 - in[3];
    if (inptr+outw>outptr) { // input pixel crosses two output pixels
      // red
      pval = (in[0]*opacity + bg[0]*transp)>>8;
      out[0] += pval * (outptr - inptr); // add to current pixel
      out[3] = pval * (outw - (outptr - inptr)); // and initialize the next one
      // green
      pval = (in[1]*opacity + bg[1]*transp)>>8;
      out[1] += pval * (outptr - inptr); // add to current pixel
      out[4] = pval * (outw - (outptr - inptr)); // and initialize the next one
      // blue
      pval = (in[2]*opacity + bg[2]*transp)>>8;
      out[2] += pval * (outptr - inptr); // add to current pixel
      out[5] = pval * (outw - (outptr - inptr)); // and initialize the next one
      // advance to next pixel
      out += 3;
      outptr += inw;
    } else { // completely contained
      out[0] += ((in[0]*opacity + bg[0]*transp) * outw) >> 8;
      out[1] += ((in[1]*opacity + bg[1]*transp) * outw) >> 8;
      out[2] += ((in[2]*opacity + bg[2]*transp) * outw) >> 8;
    }
    in+=4; // next input pixel
    inptr+=outw;
  } while (in<top);
}

struct imagestore {
  HBITMAP bmp;

  u8	  *bits;
  int	  hstep;
  int	  vstep;
  u32	  width;
  u32	  height;
  u32	  realwidth;
  u32	  realheight;
  int	  bmformat;
  void	  (*packbits)(imagestore *is,u8* src);
};

struct resize_state {
  u32	  *accum;
  u32	  *lb;
  s32	  *error;
  s32	  *nexterror;
  u32	  inptr;
  u32	  outptr;
  u8	  *dest;
  u32	  inw,inh;
  u32	  outw,outh;
  u32	  outscale;
  u32	  inscale;
  s32	  max;
  u32	  mask[3];
  u32	  *membuf;
  int	  odd;
  u8	  bg[4]; // background color for transparent images
  // we store a function pointer here to handle transparency properly
  void	  (*resize_line)(u8 *in,u32 inw,u32 *out,u32 outw,u8 *bg);
  imagestore  *output;
};

static void	packbits_24_to_15(imagestore *is,u8 *src) {
  u32	  i;
  u8	  *bits=is->bits;
  s32	  hstep=is->hstep;
  u32	  width=is->width;

  for (i=0;i<width;++i) {
    *(u16*)bits=((u16)(gamma_table[src[0]]&0xF8)<<7)|
      ((u16)(gamma_table[src[1]]&0xF8)<<2)|
      (gamma_table[src[2]]>>3);
    src+=3;
    bits+=hstep;
  }
  is->bits+=is->vstep;
}

static void	packbits_24_to_16(imagestore *is,u8 *src) {
  u32	  i;
  u8	  *bits=is->bits;
  s32	  hstep=is->hstep;
  u32	  width=is->width;

  for (i=0;i<width;++i) {
    *(u16*)bits=((u16)(gamma_table[src[0]]&0xF8)<<8)|
      ((u16)(gamma_table[src[1]]&0xFC)<<3)|
      (gamma_table[src[2]]>>3);
    src+=3;
    bits+=hstep;
  }
  is->bits+=is->vstep;
}

static void	packbits_24_to_24(imagestore *is,u8 *src) {
  u32	  i;
  u8	  *bits=is->bits;
  s32	  hstep=is->hstep;
  u32	  width=is->width;

  for (i=0;i<width;i++) {
    bits[0]=gamma_table[src[2]];
    bits[1]=gamma_table[src[1]];
    bits[2]=gamma_table[src[0]];
    src+=3;
    bits+=hstep;
  }
  is->bits+=is->vstep;
}

static bool resize_state_init(resize_state *rs,u32 iinw,u32 iinh,imagestore *iout)
{
  rs->output=iout;
  rs->inw=iinw;
  rs->inh=iinh;
  rs->outw=iout->width;
  rs->outh=iout->height;
  u32 *p=(u32*)malloc(sizeof(u32)*13*(rs->outw+2));
  if (!p)
    return false;
  memset(p,0,sizeof(u32)*(6*rs->outw+6*(rs->outw+2)+rs->outw));
  rs->membuf=p;
  rs->odd=0;
  switch (iout->bmformat) {
  case BF_555:
    rs->mask[0]=rs->mask[1]=rs->mask[2]=0xfffffff8;
    break;
  case BF_565:
    rs->mask[0]=0xfffffff8;
    rs->mask[1]=0xfffffffc;
    rs->mask[2]=0xfffffff8;
    break;
  case BF_888:
    rs->mask[0]=rs->mask[1]=rs->mask[2]=0xffffffff;
    break;
#ifndef STANDALONE
  default:
    ASSERT(0);
#endif
  }
  rs->inptr=0;
  rs->outptr=rs->inh;
  rs->accum=p; p+=3*(rs->outw+2);
  rs->lb=p; p+=3*(rs->outw+2);
  rs->nexterror=(s32*)p+3; p+=3*(rs->outw+2);
  rs->error=(s32*)p+3; p+=3*(rs->outw+2);
  rs->dest=(u8*)p; p+=rs->outw;
  rs->outscale=(u32)(4294967296.0/(rs->inw*rs->inh));
  rs->inscale=rs->inw*rs->inh;
  rs->max=rs->inscale*256-1;
  rs->resize_line=resize_line_plain;
  return true;
}

static void resize_set_alpha(resize_state *rs,COLORREF bg) {
  rs->resize_line=resize_line_alpha;
  rs->bg[0]=GetRValue(bg);
  rs->bg[1]=GetGValue(bg);
  rs->bg[2]=GetBValue(bg);
}

static void resize_state_destroy(resize_state *rs) {
  if (rs) {
    free(rs->membuf);
    free(rs);
  }
}

static resize_state *resize_state_create(u32 iinw,u32 iinh,imagestore *out) {
  resize_state *rs=(resize_state *)malloc(sizeof(resize_state));
  if (rs && resize_state_init(rs,iinw,iinh,out))
    return rs;
  free(rs);
  return NULL;
}

__inline s32 CLIP(s32 v,s32 m) {
  return v<0 ? 0 : v>m ? m : v;
}

#define	CLIPADD(rs,i,n) CLIP(rs->lb[i+n]+rs->error[i+n],rs->max)
#define	M64(a,b,m) ((unsigned int)(((__int64)(a)*(b))>>32)&(m))
#define	PIXEL_EVEN(rs,i,c) \
  u = CLIPADD(rs,i,c); \
  v = M64(u,rs->outscale,rs->mask[c]); \
  e = u - v*rs->inscale; \
  rs->error[i+3+c] += (e*7)>>4; \
  rs->nexterror[i-3+c] += (e*3)>>4; \
  rs->nexterror[i+0+c] += (e*5)>>4; \
  rs->nexterror[i+3+c] += e>>4; \
  rs->dest[i+c] = v;
#define PIXEL_ODD(rs,i,c) \
  u = CLIPADD(rs,i,c); \
  v = M64(u,rs->outscale,rs->mask[c]); \
  e = u-v*rs->inscale; \
  rs->error[i-3+c] += (e*7)>>4; \
  rs->nexterror[i+3+c] += (e*3)>>4; \
  rs->nexterror[i+0+c] += (e*5)>>4; \
  rs->nexterror[i-3+c] += e>>4; \
  rs->dest[i+c]=v;

// dither lb into dest, left to right
void	resize_dither_even(struct resize_state *rs) {
  u32	  i;
  s32	  u,v,e;

  for (i=0;i<3*rs->outw;i+=3) {
    PIXEL_EVEN(rs,i,0);
    PIXEL_EVEN(rs,i,1);
    PIXEL_EVEN(rs,i,2);
  }
}

// dither lb into dest, right to left
void	resize_dither_odd(struct resize_state *rs) {
  s32	  i;
  s32	  u,v,e;

  for (i=3*rs->outw-3;i>=0;i-=3) {
    PIXEL_ODD(rs,i,0);
    PIXEL_ODD(rs,i,1);
    PIXEL_ODD(rs,i,2);
  }
}

// dither lb into dest
void  resize_dither(struct resize_state *rs) {
  s32	  *tmp;

  if (rs->odd)
    resize_dither_odd(rs);
  else
    resize_dither_even(rs);
  tmp=rs->error;
  rs->error=rs->nexterror;
  rs->nexterror=tmp;
  memset(tmp,0,sizeof(s32)*3*rs->outw);
  rs->odd=!rs->odd;
  rs->output->packbits(rs->output,rs->dest);
}

void	resize_add_line(struct resize_state *rs,u8 *line) {
  u32	  i;

  // resize the line horizontally
  rs->resize_line(line,rs->inw,rs->lb,rs->outw,rs->bg);
  // perform one loop iteration
  if (rs->inptr+rs->outh>=rs->outptr) {
    u32	    c1=rs->outptr-rs->inptr;
    u32	    c2=rs->outh-c1;
    u32	    v;
    for (i=0;i<3*rs->outw;i+=3) {
      v = rs->accum[i+0]+rs->lb[i+0]*c1;
      rs->accum[i+0] = rs->lb[i+0]*c2;
      rs->lb[i+0] = v;
      v = rs->accum[i+1]+rs->lb[i+1]*c1;
      rs->accum[i+1] = rs->lb[i+1]*c2;
      rs->lb[i+1] = v;
      v = rs->accum[i+2]+rs->lb[i+2]*c1;
      rs->accum[i+2] = rs->lb[i+2]*c2;
      rs->lb[i+2] = v;
    }
    resize_dither(rs);
    rs->outptr+=rs->inh;
  } else {
    for (i=0;i<3*rs->outw;i+=3) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -