1123323fda
o applied new coding standards to all .c files o moved some files around
239 lines
5.9 KiB
C
239 lines
5.9 KiB
C
/**
|
||
* 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 <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <sys/types.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <stdint.h>
|
||
#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 opeing %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;
|
||
}
|