/** * xrdp: A Remote Desktop Protocol server. * * Copyright (C) Laxmikant Rashinkar 2004-2012 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "common.h" // multi byte values are stored in little endian struct bmp_magic { char magic[2]; }; struct bmp_hdr { uint32_t size; // file size in bytes uint16_t reserved1; uint16_t reserved2; uint32_t offset; // offset to image data, in bytes }; struct dib_hdr { uint32_t hdr_size; int32_t width; int32_t height; uint16_t nplanes; uint16_t bpp; uint32_t compress_type; uint32_t image_size; int32_t hres; int32_t vres; uint32_t ncolors; uint32_t nimpcolors; }; // forward declarations int parse_bmp(char *filename, struct pic_info *pic_info); int parse_bmp_24(struct bmp_hdr *bmp_hdr, struct dib_hdr *dib_hdr, int fd, struct pic_info *pic_info); int parse_bmp(char *filename, struct pic_info *pic_info) { int got_magic; int fd; int rval; struct bmp_magic magic; struct bmp_hdr bmp_hdr; struct dib_hdr dib_hdr; if ((fd = open(filename, O_RDONLY)) < 0) { printf("error opening %s\n", filename); return -1; } // read BMP magic... if ((rval = read(fd, magic.magic, 2)) != 2) { fprintf(stderr, "error reading BMP signature from file %s\n", filename); return -1; } got_magic = 0; // ...and confirm that this is indeed a BMP file if ((magic.magic[0] == 'B') && (magic.magic[1] == 'M')) { // BM – Windows 3.1x, 95, NT, ... etc got_magic = 1; } else if ((magic.magic[0] == 'B') && (magic.magic[1] == 'A')) { // BA – OS/2 struct Bitmap Array got_magic = 1; } else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'I')) { // CI – OS/2 struct Color Icon got_magic = 1; } else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'P')) { // CP – OS/2 const Color Pointer got_magic = 1; } else if ((magic.magic[0] == 'I') && (magic.magic[1] == 'C')) { // IC – OS/2 struct Icon got_magic = 1; } else if ((magic.magic[0] == 'P') && (magic.magic[1] == 'T')) { // PT – OS/2 Pointer got_magic = 1; } if (!got_magic) { fprintf(stderr, "%s is not a valid BMP file\n", filename); return -1; } // read BMP header if ((rval = read(fd, &bmp_hdr, sizeof(bmp_hdr))) < sizeof(bmp_hdr)) { fprintf(stderr, "error BMP header from file %s\n", filename); return -1; } // read DIB header if ((rval = read(fd, &dib_hdr, sizeof(dib_hdr))) < sizeof(dib_hdr)) { fprintf(stderr, "error reading DIB header from file %s\n", filename); return -1; } #if 0 printf("header size: %d\n", dib_hdr.hdr_size); printf("width: %d\n", dib_hdr.width); printf("height: %d\n", dib_hdr.height); printf("num planes: %d\n", dib_hdr.nplanes); printf("bpp: %d\n", dib_hdr.bpp); printf("comp type: %d\n", dib_hdr.compress_type); printf("image size: %d\n", dib_hdr.image_size); printf("hres: %d\n", dib_hdr.hres); printf("vres: %d\n", dib_hdr.vres); printf("ncolors: %d\n", dib_hdr.ncolors); printf("nimpcolors: %d\n", dib_hdr.nimpcolors); #endif if (dib_hdr.compress_type) { printf("TODO: compressed images not yet supported\n"); return -1; } pic_info->width = dib_hdr.width; pic_info->height = dib_hdr.height; if (dib_hdr.bpp == 24) { rval = parse_bmp_24(&bmp_hdr, &dib_hdr, fd, pic_info); } close(fd); return rval; } /** * extract 24bit BMP data from image file * * @return 0 on success * @return -1 on failure */ int parse_bmp_24( struct bmp_hdr *bmp_hdr, struct dib_hdr *dib_hdr, int fd, struct pic_info *pic_info ) { char *file_data; char *ptr_file_data; char *mem_data; char *ptr_mem_data; char *cptr; int w = dib_hdr->width; // picture width int h = dib_hdr->height; // picture height int bpl; // bytes per line int bytes; int i; int j; // bytes per image line = width x bytes_per_pixel + padding i = (w * 3) % 4; j = (i == 0) ? 0 : 4 - i; bpl = w * 3 + j; // 24 bit depth, no alpha channel file_data = (char *) malloc(h * bpl); // point to first line in image data, which is stored in reverse order ptr_file_data = (file_data + dib_hdr->image_size) - bpl; // 24 bit depth, with alpha channel mem_data = (char *) malloc(w * h * 4); ptr_mem_data = mem_data; pic_info->pixel_data = ptr_mem_data; // seek to beginning of pixel data lseek(fd, bmp_hdr->offset, SEEK_SET); // read all pixel data bytes = read(fd, file_data, dib_hdr->image_size); // convert 24bit to 24 bit with alpha and store in reverse for (i = 0; i < h; i ++) { cptr = ptr_file_data; for (j = 0; j < w; j++) { *ptr_mem_data++ = *cptr++; // blue value *ptr_mem_data++ = *cptr++; // green value *ptr_mem_data++ = *cptr++; // red value *ptr_mem_data++ = 0; // alpha channel } ptr_file_data -= bpl; } free(file_data); return 0; }