diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Main.hs | 53 | ||||
| -rw-r--r-- | main.c | 145 |
3 files changed, 147 insertions, 53 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41cd10b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.bmp +a.out diff --git a/Main.hs b/Main.hs deleted file mode 100644 index e433b09..0000000 --- a/Main.hs +++ /dev/null @@ -1,53 +0,0 @@ -import Data.Array.MArray -import Data.Array.IO -import System.IO -import qualified Data.ByteString.Builder as B - -data Picture = Picture - { picWidth :: Int - , picHeight :: Int - , picArray :: IOUArray Int Float} - -newPicture :: Int -> Int -> IO Picture -newPicture w h = do { - arr <- newArray (0, w * h * 3) 0.0; - return $ Picture w h arr; -} - -setPixel :: (Int, Int) -> (Float, Float, Float) -> Picture -> IO () -setPixel (x, y) (r, g, b) pic = let { - idx = (y * picWidth pic + x) * 3; -} in do { - writeArray (picArray pic) idx r; - writeArray (picArray pic) (idx+1) g; - writeArray (picArray pic) (idx+2) b; -} - -outputPicture :: String -> Picture -> IO () -outputPicture fileName pic = withBinaryFile fileName WriteMode $ \h -> let { - fileLength = undefined; - width = undefined; - height = undefined; - imageSize = undefined; -} in do { - B.hPutBuilder h $ mconcat - [ -- header - B.word16LE 0x4d42 - , B.word32LE fileLength - , B.word32LE 0 - , B.word32LE 54 - -- info - , B.word32LE 40 - , B.int32LE width - , B.int32LE height - , B.word16LE 1 - , B.word16LE 24 - , B.word32LE 0 -- BI_RGB - , B.word32LE imageSize - , B.word32LE 0 - , B.word32LE 0 - , B.word32LE 0 - , B.word32LE 0 - ]; -} - @@ -0,0 +1,145 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +typedef enum { + kRetSucc, + kRetFail, +} Ret; + +typedef struct { + int width; + int height; + float *buffer; +} Picture; + + +Picture new_picture(int width, int height) { + Picture ret; + ret.width = width; + ret.height = height; + ret.buffer = malloc(sizeof(float) * width * height * 3); + return ret; +} + +void delete_picture(Picture pic) { + free(pic.buffer); +} + +void set_pixel(Picture pic, int x, int y, float r, float g, float b) { + int idx = y * pic.width * 3 + x * 3; + pic.buffer[idx] = b; + pic.buffer[idx+1] = g; + pic.buffer[idx+2] = r; +} + +Ret fwrite_word16le(FILE* fp, uint16_t x) { + uint8_t buf[2]; + buf[0] = x & 0xff; + buf[1] = (x >> 8) & 0xff; + int r = fwrite(buf, 1, 2, fp); + if (r != 2) return kRetFail; + return kRetSucc; +} + +Ret fwrite_word32le(FILE* fp, uint32_t x) { + Ret ret; + uint16_t buf[2]; + + buf[0] = x & 0xffff; + buf[1] = (x >> 16) & 0xffff; + ret = fwrite_word16le(fp, buf[0]); + if (ret != kRetSucc) return ret; + ret = fwrite_word16le(fp, buf[1]); + if (ret != kRetSucc) return ret; + return kRetSucc; +} + + +Ret writeBMP(const char* filename, Picture pic) { + Ret ret = kRetFail; + FILE *fp = NULL; + uint8_t *databuf = NULL; + + fp = fopen(filename, "wb"); + if (!fp) goto end; + + int row_data_len = 3 * pic.width; + int padding = (4 - row_data_len % 4) % 4; + int row_len = row_data_len + padding; + int img_len = row_len * pic.height; + int file_len = 53 + img_len; + + ret = fwrite_word16le(fp, 0x4d42); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, file_len); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 54); + if (ret != kRetSucc) goto end; + + ret = fwrite_word32le(fp, 40); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, pic.width); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, -pic.height); + if (ret != kRetSucc) goto end; + ret = fwrite_word16le(fp, 1); + if (ret != kRetSucc) goto end; + ret = fwrite_word16le(fp, 24); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); // BI_RGB + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, img_len); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); + if (ret != kRetSucc) goto end; + ret = fwrite_word32le(fp, 0); + if (ret != kRetSucc) goto end; + + databuf = malloc(img_len); + memset(databuf, 0, img_len); + for (int i = 0; i < pic.height; i++) { + for (int j = 0; j < pic.width * 3; j++) { + int fromidx = i * pic.width * 3 + j; + int toidx = i * row_len + j; + float value = pic.buffer[fromidx]; + if (value < 0) databuf[toidx] = 0; + else if (value > 1.0) { + databuf[toidx] = 255; + } else databuf[toidx] = 255 * value; + } + } + if (fwrite(databuf, 1, img_len, fp) != img_len) { + ret = kRetFail; + goto end; + } + ret = kRetSucc; + +end: + if (databuf != NULL) free(databuf); + if (fp != NULL) fclose(fp); + return ret; +} + +int main() { + Picture pic = new_picture(1600, 900); + for (int i = 0; i < 900; i++) { + for (int j = 0; j < 1600; j++) { + float r = (i + j) % 177 / 177.0; + float g = (i + j) % 71 / 71.0; + float b = (i + j) % 337 / 337.0; + set_pixel(pic, j, i, r, g, b); + } + } + writeBMP("test.bmp", pic); + delete_picture(pic); + return 0; +} + |
