static size_t ppm2rgb(ss_t **rgb, struct RGB_Info *ri, const ss_t *ppm) { RETURN_IF(!ppm || !ri, 0); const char *p = ss_get_buffer_r(ppm); size_t ps = ss_size(ppm); ri->chn = p[1] == '5' ? 1 : p[1] == '6' ? 3 : 0; RETURN_IF(ps < 16 || p[0] != 'P' || !ri->chn, 0); size_t off = 2, nf = 0, nl, nl2, i = 0; int f[PPM_NFIELDS]; for (; i != S_NPOS && nf < PPM_NFIELDS && off < ps; off = nl + 1) { nl = ss_findc(ppm, off, '\n'); if (nl == S_NPOS) break; nl2 = ss_findrc(ppm, off, nl, '#'); /* skip comments */ nl2 = nl2 == S_NPOS ? nl : nl2; for (i = off; i < nl2;) { /* get fields */ i = ss_findrbm(ppm, i, nl2, 0x30, 0xc0); /* digits */ if (i == S_NPOS) break; f[nf++] = atoi(p + i); if (nf == PPM_NFIELDS) break; i = ss_findrb(ppm, i + 1, nl2); } } RETURN_IF(nf != PPM_NFIELDS, 0); ri->bpp = ri->chn * (f[2] <= 255 ? 1 : f[2] <= 65535 ? 2 : 0) * 8; set_rgbi(ri, f[0], f[1], ri->bpp, ri->chn); RETURN_IF(!valid_rgbi(ri), 0); ss_cpy_cn(rgb, p + off, ps - off); /* Copy pixel data */ return ss_size(*rgb); }
static size_t tga2rgb(ss_t **rgb, struct RGB_Info *ri, const ss_t *tga) { const char *t = ss_get_buffer_r(tga); const size_t ts = ss_size(tga); RETURN_IF(ts < TGA_RGBHDR || !valid_tga(t), 0); set_rgbi(ri, S_LD_LE_U16(t + TGA_W), S_LD_LE_U16(t + TGA_H), t[TGA_BPP], t[TGA_TYPE] == TGA_RAW_GRAY ? 1 : t[TGA_BPP]/8); RETURN_IF(!valid_rgbi(ri), 0); size_t rgb_bytes = ri->row_size * ri->height; RETURN_IF(ts < rgb_bytes + TGA_RGBHDR, 0); RETURN_IF(ss_reserve(rgb, rgb_bytes) < rgb_bytes, 0); if ((t[TGA_DESC] & TGA_TOP_LEFT) != 0) { if (ri->chn == 1) ss_cpy_cn(rgb, t + TGA_RGBHDR, rgb_bytes); else tga_rgb_swap(ri->bpp, rgb_bytes, ss_get_buffer_r(tga) + TGA_RGBHDR, ss_get_buffer(*rgb)); } else { ss_set_size(*rgb, 0); ssize_t i = (ssize_t)(ri->height - 1) * ri->row_size; for (; i >= 0; i -= ri->row_size) if (ri->chn == 1) ss_cat_cn(rgb, t + TGA_RGBHDR + i, ri->row_size); else tga_rgb_swap(ri->bpp, ri->row_size, t + TGA_RGBHDR + i, ss_get_buffer(*rgb) + i); } ss_set_size(*rgb, rgb_bytes); return rgb_bytes; }
static size_t rgb2tga(ss_t **tga, const ss_t *rgb, const struct RGB_Info *ri) { RETURN_IF(!rgb || (!valid_rgbi(ri) && (ri->bpp / ri->chn) != 8), 0); RETURN_IF(ri->chn != 1 && ri->chn != 3 && ri->chn != 4, 0); size_t buf_size = ri->bmp_size + TGA_RGBHDR; RETURN_IF(ss_reserve(tga, buf_size) < buf_size, 0); char *h = ss_get_buffer(*tga); memset(h, 0, TGA_RGBHDR); h[TGA_ID] = TGA_NO_X_INFO; h[TGA_CMAP] = TGA_NO_CMAP; h[TGA_TYPE] = ri->chn == 1 ? TGA_RAW_GRAY : TGA_RAW_RGB; S_ST_LE_U16(h + TGA_W, ri->width); S_ST_LE_U16(h + TGA_H, ri->height); h[TGA_BPP] = ri->bpp; h[TGA_DESC] = TGA_TOP_LEFT; ss_cpy_cn(tga, h, TGA_RGBHDR); if (ri->chn == 1) ss_cat(tga, rgb); else tga_rgb_swap(ri->bpp, ri->bmp_size, ss_get_buffer_r(rgb), ss_get_buffer(*tga) + TGA_RGBHDR); ss_set_size(*tga, buf_size); return ss_size(*tga); }
ss_t *ss_dup_cn(const char *src, const size_t src_size) { ss_t *s = NULL; return ss_cpy_cn(&s, src, src_size); }