/*$ 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; }