/*$
Copyright (C) 2016-2020 Azel.
This file is part of AzPainterB.
AzPainterB is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
AzPainterB 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
$*/
/*****************************************
* ImageBuf24
*
* 24bit RGB イメージ
*****************************************/
/*
* - "R-G-B" のバイト順で並んでいる。
* - レイヤ合成後のイメージなどで使われる。
*/
#include
#include "mDef.h"
#include "mLoadImage.h"
#include "ImageBuf24.h"
/** 32bit カラー値から ImageBuf24Pix に変換 */
void ImageBuf24_coltopix(ImageBuf24Pix *dst,uint32_t col)
{
dst->r = (uint8_t)(col >> 16);
dst->g = (uint8_t)(col >> 8);
dst->b = (uint8_t)col;
}
/** 解放 */
void ImageBuf24_free(ImageBuf24 *p)
{
if(p)
{
mFree(p->buf);
mFree(p);
}
}
/** 作成 */
ImageBuf24 *ImageBuf24_new(int w,int h)
{
ImageBuf24 *p;
p = (ImageBuf24 *)mMalloc(sizeof(ImageBuf24), TRUE);
if(!p) return NULL;
p->w = w;
p->h = h;
p->pitch = w * 3;
//バッファ確保
p->buf = (uint8_t *)mMalloc(w * h * 3, FALSE);
if(!p->buf)
{
mFree(p);
return NULL;
}
return p;
}
/** 指定位置のポインタを取得
*
* @return NULL で範囲外 */
uint8_t *ImageBuf24_getPixelBuf(ImageBuf24 *p,int x,int y)
{
if(x < 0 || y < 0 || x >= p->w || y >= p->h)
return NULL;
else
return p->buf + y * p->pitch + x * 3;
}
/** 全体を指定色で埋める */
void ImageBuf24_fill(ImageBuf24 *p,uint32_t col)
{
uint8_t *pd;
ImageBuf24Pix pix;
int i,pitch;
ImageBuf24_coltopix(&pix, col);
//Y1列分を埋める
pd = p->buf;
for(i = p->w; i > 0; i--, pd += 3)
{
pd[0] = pix.r;
pd[1] = pix.g;
pd[2] = pix.b;
}
//残りは、前の列をコピー
pitch = p->pitch;
pd = p->buf + pitch;
for(i = p->h - 1; i > 0; i--, pd += pitch)
memcpy(pd, pd - pitch, pitch);
}
/** 白色で全体を埋める */
void ImageBuf24_fillWhite(ImageBuf24 *p)
{
memset(p->buf, 255, p->pitch * p->h);
}
/** 範囲を指定色で埋める */
void ImageBuf24_fillBox(ImageBuf24 *p,mBox *box,uint32_t col)
{
uint8_t *pd;
ImageBuf24Pix pix;
int i,pitch,wsize;
ImageBuf24_coltopix(&pix, col);
pitch = p->pitch;
wsize = box->w * 3;
//Y1列分を埋める
pd = p->buf + box->y * pitch + box->x * 3;
for(i = box->w; i > 0; i--, pd += 3)
{
pd[0] = pix.r;
pd[1] = pix.g;
pd[2] = pix.b;
}
//前の列をコピー
pd -= wsize;
for(i = box->h - 1; i > 0; i--, pd += pitch)
memcpy(pd + pitch, pd, wsize);
}
/** チェック柄で範囲を埋める */
void ImageBuf24_fillPlaid_box(ImageBuf24 *p,mBox *box,uint32_t col1,uint32_t col2)
{
ImageBuf24Pix *pd,pix[2];
uint8_t *bufd,*bufs;
int ix,iy,pitch,xx,yy,fy;
ImageBuf24_coltopix(pix, col1);
ImageBuf24_coltopix(pix + 1, col2);
//高さを 16px まで埋める
pd = (ImageBuf24Pix *)(p->buf + box->y * p->pitch + box->x * 3);
pitch = p->w - box->w;
yy = box->y & 15;
for(iy = (box->h > 16)? 16: box->h; iy > 0; iy--)
{
xx = box->x & 15;
fy = yy >> 3;
for(ix = box->w; ix > 0; ix--)
{
*(pd++) = pix[fy ^ (xx >> 3)];
xx = (xx + 1) & 15;
}
pd += pitch;
yy = (yy + 1) & 15;
}
//残りの高さをコピーして埋める
if(box->h > 16)
{
pitch = p->pitch;
bufd = (uint8_t *)pd;
bufs = bufd - (pitch << 4);
xx = box->w * 3;
for(iy = box->h - 16; iy > 0; iy--)
{
memcpy(bufd, bufs, xx);
bufd += pitch;
bufs += pitch;
}
}
}
/** パレット取得 (最大256色)
*
* @param tpindex 透過色を入れておく。透過色のインデックス番号が入る。
* @return 確保されたバッファ (R-G-B-A)。256色より多い場合は NULL */
uint8_t *ImageBuf24_getPalette(ImageBuf24 *p,int *pnum,int *tpcol)
{
uint8_t *palbuf,*ps,*ppal,tr,tg,tb;
uint32_t i;
int j,cnt = 0,settp;
//バッファ確保
palbuf = (uint8_t *)mMalloc(256 * 4, FALSE);
if(!palbuf) return NULL;
//透過色 RGB
if(*tpcol < 0)
settp = FALSE;
else
{
tr = M_GET_R(*tpcol);
tg = M_GET_G(*tpcol);
tb = M_GET_B(*tpcol);
settp = TRUE;
}
//
ps = p->buf;
for(i = p->w * p->h; i; i--, ps += 3)
{
//すでに存在する色か
for(j = 0, ppal = palbuf; j < cnt; j++, ppal += 4)
{
if(ps[0] == ppal[0] && ps[1] == ppal[1] && ps[2] == ppal[2])
break;
}
//追加
if(j == cnt)
{
//256色を超えた
if(cnt == 256)
{
mFree(palbuf);
return NULL;
}
//透過色のインデックスセット
if(settp && ps[0] == tr && ps[1] == tg && ps[2] == tb)
{
*tpcol = cnt;
settp = FALSE;
}
//
ppal[0] = ps[0];
ppal[1] = ps[1];
ppal[2] = ps[2];
ppal[3] = 0;
cnt++;
}
}
*pnum = cnt;
return palbuf;
}
/** パレットイメージ保存用、Y1行セット */
void ImageBuf24_setRow_forPalette(ImageBuf24 *p,uint8_t *dst,uint8_t *src,uint8_t *palbuf,int palnum)
{
uint8_t *ppal;
int i,j;
for(i = p->w; i; i--, src += 3)
{
//パレットから検索
for(j = 0, ppal = palbuf; j < palnum; j++, ppal += 4)
{
if(src[0] == ppal[0] && src[1] == ppal[1] && src[2] == ppal[2])
break;
}
if(j == palnum) j = 0;
*(dst++) = j;
}
}
//==============================
// 画像読み込み
//==============================
typedef struct
{
mLoadImage base;
ImageBuf24 *img;
uint8_t *dstbuf;
ImageBuf24Pix bgpix;
}_loadimageinfo;
/** 情報取得 */
static int _loadfile_getinfo(mLoadImage *param,mLoadImageInfo *info)
{
_loadimageinfo *p = (_loadimageinfo *)param;
//作成
p->img = ImageBuf24_new(info->width, info->height);
if(!p->img) return MLOADIMAGE_ERR_ALLOC;
p->dstbuf = p->img->buf;
if(info->bottomup) p->dstbuf += (info->height - 1) * p->img->pitch;
return MLOADIMAGE_ERR_OK;
}
/** Y1行取得 */
static int _loadfile_getrow(mLoadImage *param,uint8_t *buf,int pitch)
{
_loadimageinfo *p = (_loadimageinfo *)param;
int i,a;
uint8_t *pd;
ImageBuf24Pix pix;
pd = p->dstbuf;
pix = p->bgpix;
for(i = param->info.width; i > 0; i--, buf += 4, pd += 3)
{
a = buf[3];
if(a == 255)
pd[0] = buf[0], pd[1] = buf[1], pd[2] = buf[2];
else if(a == 0)
pd[0] = pix.r, pd[1] = pix.g, pd[2] = pix.b;
else
{
pd[0] = (buf[0] - pix.r) * a / 255 + pix.r;
pd[1] = (buf[1] - pix.g) * a / 255 + pix.g;
pd[2] = (buf[2] - pix.b) * a / 255 + pix.b;
}
}
p->dstbuf += (param->info.bottomup)? -(p->img->pitch): p->img->pitch;
return MLOADIMAGE_ERR_OK;
}
/** 画像ファイルを読み込み (BMP/PNG/GIF/JPEG)
*
* @param bkgndcol アルファ値または透過色がある場合は、この背景色と合成される */
ImageBuf24 *ImageBuf24_loadFile(const char *filename,uint32_t bkgndcol)
{
_loadimageinfo *p;
mLoadImageFunc func;
ImageBuf24 *img = NULL;
p = (_loadimageinfo *)mLoadImage_create(sizeof(_loadimageinfo));
if(!p) return NULL;
ImageBuf24_coltopix(&p->bgpix, bkgndcol);
p->base.format = MLOADIMAGE_FORMAT_RGBA;
p->base.src.type = MLOADIMAGE_SOURCE_TYPE_PATH;
p->base.src.filename = filename;
p->base.getinfo = _loadfile_getinfo;
p->base.getrow = _loadfile_getrow;
//実行
if(mLoadImage_checkFormat(&p->base.src, &func, MLOADIMAGE_CHECKFORMAT_F_ALL))
{
if((func)(M_LOADIMAGE(p)))
img = p->img;
else
ImageBuf24_free(p->img);
}
mLoadImage_free(M_LOADIMAGE(p));
return img;
}