fixed a couple of issues, but lots of work remains, doesn't crash with up side down BMPs in Windows format anymore... could someone provide me with a BMP that actually uses the alpha channel? I could not make one in Windows with Adobe Photoshop Elements.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17098 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2006-04-11 21:11:44 +00:00
parent f9ff1193f7
commit a5a38476ea

View File

@ -1,36 +1,26 @@
/*****************************************************************************/ /*
// BMPTranslator * Copyright 2002-2006, Haiku.
// BMPTranslator.cpp * Distributed under the terms of the MIT License.
// *
// This BTranslator based object is for opening and writing BMP files. * Authors:
// * Michael Wilber <mwilber@users.berlios.de>
// */
// Copyright (c) 2002 OpenBeOS Project
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#include <string.h>
#include <stdio.h>
#include "BMPTranslator.h" #include "BMPTranslator.h"
#include <new>
#include <stdio.h>
#include <string.h>
#include "BMPView.h" #include "BMPView.h"
using std::nothrow;
//#define INFO(x) printf(x);
#define INFO(x)
//#define ERROR(x) printf(x);
#define ERROR(x)
// The input formats that this translator supports. // The input formats that this translator supports.
translation_format gInputFormats[] = { translation_format gInputFormats[] = {
{ {
@ -67,7 +57,7 @@ translation_format gOutputFormats[] = {
BMP_OUT_QUALITY, BMP_OUT_QUALITY,
BMP_OUT_CAPABILITY, BMP_OUT_CAPABILITY,
"image/x-bmp", "image/x-bmp",
"BMP image (MS format)" "BMP image"
} }
}; };
@ -382,7 +372,9 @@ identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
if (pmsheader) { if (pmsheader) {
pmsheader->size = msheader.size; pmsheader->size = msheader.size;
pmsheader->width = msheader.width; pmsheader->width = msheader.width;
pmsheader->height = msheader.height; pmsheader->height = abs((int32)msheader.height);
// TODO: negative height means the BMP is up side down
// -> support this...
pmsheader->planes = msheader.planes; pmsheader->planes = msheader.planes;
pmsheader->bitsperpixel = msheader.bitsperpixel; pmsheader->bitsperpixel = msheader.bitsperpixel;
pmsheader->compression = msheader.compression; pmsheader->compression = msheader.compression;
@ -574,6 +566,9 @@ status_t
translate_from_bits_to_bmp24(BPositionIO *inSource, translate_from_bits_to_bmp24(BPositionIO *inSource,
BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader) BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader)
{ {
// TODO: WHOHA! big switch statement for the innermost loop!
// make a loop per colorspace and put the switch outside!!!
// remove memcpy() to copy 3 bytes
int32 bitsBytesPerPixel = 0; int32 bitsBytesPerPixel = 0;
switch (fromspace) { switch (fromspace) {
case B_RGB32: case B_RGB32:
@ -616,14 +611,13 @@ BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader)
uint32 bmppixrow = 0; uint32 bmppixrow = 0;
off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
inSource->Seek(bitsoffset, SEEK_CUR); inSource->Seek(bitsoffset, SEEK_CUR);
uint8 *bmpRowData = new uint8[bmpRowBytes]; uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
if (!bmpRowData) if (!bmpRowData)
return B_ERROR; return B_NO_MEMORY;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) { if (!bitsRowData) {
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL; return B_NO_MEMORY;
return B_ERROR;
} }
memset(bmpRowData + (bmpRowBytes - padding), 0, padding); memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
@ -759,9 +753,7 @@ BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader)
} // while (rd == bitsRowBytes) } // while (rd == bitsRowBytes)
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL;
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
return B_OK; return B_OK;
} }
@ -800,14 +792,13 @@ translate_from_bits8_to_bmp8(BPositionIO *inSource,
uint32 bmppixrow = 0; uint32 bmppixrow = 0;
off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
inSource->Seek(bitsoffset, SEEK_CUR); inSource->Seek(bitsoffset, SEEK_CUR);
uint8 *bmpRowData = new uint8[bmpRowBytes]; uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
if (!bmpRowData) if (!bmpRowData)
return B_ERROR; return B_NO_MEMORY;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) { if (!bitsRowData) {
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL; return B_NO_MEMORY;
return B_ERROR;
} }
memset(bmpRowData + (bmpRowBytes - padding), 0, padding); memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
@ -826,9 +817,7 @@ translate_from_bits8_to_bmp8(BPositionIO *inSource,
} // while (rd == bitsRowBytes) } // while (rd == bitsRowBytes)
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL;
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
return B_OK; return B_OK;
} }
@ -867,14 +856,13 @@ translate_from_bits1_to_bmp1(BPositionIO *inSource,
uint32 bmppixrow = 0; uint32 bmppixrow = 0;
off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
inSource->Seek(bitsoffset, SEEK_CUR); inSource->Seek(bitsoffset, SEEK_CUR);
uint8 *bmpRowData = new uint8[bmpRowBytes]; uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
if (!bmpRowData) if (!bmpRowData)
return B_ERROR; return B_NO_MEMORY;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) { if (!bitsRowData) {
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL; return B_NO_MEMORY;
return B_ERROR;
} }
ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
while (rd == bitsRowBytes) { while (rd == bitsRowBytes) {
@ -914,9 +902,7 @@ translate_from_bits1_to_bmp1(BPositionIO *inSource,
} // while (rd == bitsRowBytes) } // while (rd == bitsRowBytes)
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL;
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
return B_OK; return B_OK;
} }
@ -1117,48 +1103,52 @@ BMPTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
bitsHeader.colors, msheader); bitsHeader.colors, msheader);
case B_CMAP8: case B_CMAP8:
case B_GRAY8:
{ {
// write Be's system palette to the BMP file // write palette to BMP file
uint8 pal[1024] = { 0 }; uint8 pal[1024];
const color_map *pmap = system_colors(); uint8* palHandle = pal;
if (!pmap) if (bitsHeader.colors == B_CMAP8) {
return B_ERROR; // write system palette
for (int32 i = 0; i < 256; i++) { const color_map *pmap = system_colors();
uint8 *palent = pal + (i * 4); if (!pmap)
rgb_color c = pmap->color_list[i]; return B_ERROR;
palent[0] = c.blue; for (int32 i = 0; i < 256; i++) {
palent[1] = c.green; rgb_color c = pmap->color_list[i];
palent[2] = c.red; palHandle[0] = c.blue;
} palHandle[1] = c.green;
if (outDestination->Write(pal, 1024) != 1024) palHandle[2] = c.red;
palHandle[3] = c.alpha;
palHandle += 4;
}
} else {
// write gray palette
for (int32 i = 0; i < 256; i++) {
palHandle[0] = i;
palHandle[1] = i;
palHandle[2] = i;
palHandle[3] = 255;
palHandle += 4;
}
}
ssize_t written = outDestination->Write(pal, 1024);
if (written < 0)
return written;
if (written != 1024)
return B_ERROR; return B_ERROR;
return translate_from_bits8_to_bmp8(inSource, outDestination, return translate_from_bits8_to_bmp8(inSource, outDestination,
bitsHeader.rowBytes, msheader); bitsHeader.rowBytes, msheader);
} }
case B_GRAY8:
{
// write out a grayscale palette to the BMP file
uint8 pal[1024] = { 0 };
for (int32 i = 0; i < 256; i++) {
uint8 *palent = pal + (i * 4);
palent[0] = i;
palent[1] = i;
palent[2] = i;
}
if (outDestination->Write(pal, 1024) != 1024)
return B_ERROR;
return translate_from_bits8_to_bmp8(inSource, outDestination,
bitsHeader.rowBytes, msheader);
}
case B_GRAY1: case B_GRAY1:
{ {
// write monochrome palette to the BMP file // write monochrome palette to the BMP file
const uint32 monopal[] = { 0x00ffffff, 0x00000000 }; const uint32 monopal[] = { 0x00ffffff, 0x00000000 };
if (outDestination->Write(monopal, 8) != 8) ssize_t written = outDestination->Write(monopal, 8);
if (written < 0)
return written;
if (written != 8)
return B_ERROR; return B_ERROR;
return translate_from_bits1_to_bmp1(inSource, outDestination, return translate_from_bits1_to_bmp1(inSource, outDestination,
@ -1200,61 +1190,86 @@ translate_from_bmpnpal_to_bits(BPositionIO *inSource,
int32 bmpBytesPerPixel = msheader.bitsperpixel / 8; int32 bmpBytesPerPixel = msheader.bitsperpixel / 8;
int32 bmpRowBytes = int32 bmpRowBytes =
get_rowbytes(msheader.width, msheader.bitsperpixel); get_rowbytes(msheader.width, msheader.bitsperpixel);
printf("bitsRowBytes: %ld, bmpBytesPerPixel: %ld, bmpRowBytes: %ld\n",
bitsRowBytes, bmpBytesPerPixel, bmpRowBytes);
// Setup outDestination so that it can be written to // Setup outDestination so that it can be written to
// from the end of the file to the beginning instead of // from the end of the file to the beginning instead of
// the other way around // the other way around
off_t bitsFileSize = (bitsRowBytes * msheader.height) + off_t bitsFileSize = (bitsRowBytes * msheader.height) +
sizeof(TranslatorBitmap); sizeof(TranslatorBitmap);
if (outDestination->SetSize(bitsFileSize) != B_OK) if (outDestination->SetSize(bitsFileSize) != B_OK) {
// This call should work for BFile and BMallocIO objects, // This call should work for BFile and BMallocIO objects,
// but may not work for other BPositionIO based types // but may not work for other BPositionIO based types
ERROR("BMPTranslator::translate_from_bmpnpal_to_bits() - failed to SetSize()\n");
return B_ERROR; return B_ERROR;
}
off_t bitsoffset = (msheader.height - 1) * bitsRowBytes; off_t bitsoffset = (msheader.height - 1) * bitsRowBytes;
outDestination->Seek(bitsoffset, SEEK_CUR); outDestination->Seek(bitsoffset, SEEK_CUR);
// allocate row buffers // allocate row buffers
uint8 *bmpRowData = new uint8[bmpRowBytes]; uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
if (!bmpRowData) if (!bmpRowData)
return B_ERROR; return B_NO_MEMORY;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) { if (!bitsRowData) {
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL; return B_NO_MEMORY;
return B_ERROR;
} }
// perform the actual translation // perform the actual translation
uint32 bmppixrow = 0; if (bmpBytesPerPixel != 4) {
memset(bitsRowData, 0xff, bitsRowBytes); // clean out buffer so that we don't have to write
ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes); // alpha for each row
while (rd == static_cast<ssize_t>(bmpRowBytes)) { memset(bitsRowData, 0xff, bitsRowBytes);
uint8 *pBitsPixel = bitsRowData; }
uint8 *pBmpPixel = bmpRowData;
for (uint32 i = 0; i < msheader.width; i++) {
memcpy(pBitsPixel, pBmpPixel, 3);
pBitsPixel += 4;
pBmpPixel += bmpBytesPerPixel;
}
outDestination->Write(bitsRowData, bitsRowBytes);
bmppixrow++;
// if I've read all of the pixel data, break
// out of the loop so I don't try to read
// non-pixel data
if (bmppixrow == msheader.height)
break;
status_t ret = B_OK;
printf("height: %ld\n", msheader.height);
for (uint32 y = 0; y < msheader.height; y++) {
ssize_t read = inSource->Read(bmpRowData, bmpRowBytes);
if (read != bmpRowBytes) {
// break on read error
if (read >= 0)
ret = B_ERROR;
else
ret = read;
break;
}
if (bmpBytesPerPixel == 4) {
memcpy(bitsRowData, bmpRowData, bmpRowBytes);
} else {
uint8 *pBitsPixel = bitsRowData;
uint8 *pBmpPixel = bmpRowData;
for (uint32 i = 0; i < msheader.width; i++) {
printf("24 bits\n");
pBitsPixel[0] = pBmpPixel[0];
pBitsPixel[1] = pBmpPixel[1];
pBitsPixel[2] = pBmpPixel[2];
pBitsPixel += 4;
pBmpPixel += bmpBytesPerPixel;
}
}
// write row and seek backward by two rows
ssize_t written = outDestination->Write(bitsRowData, bitsRowBytes);
outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
rd = inSource->Read(bmpRowData, bmpRowBytes);
if (written != bitsRowBytes) {
// break on write error
if (written >= 0)
ret = B_ERROR;
else
ret = read;
break;
}
} }
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL;
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
return B_OK; return ret;
} }
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -1278,7 +1293,7 @@ translate_from_bmpnpal_to_bits(BPositionIO *inSource,
// //
// Postconditions: // Postconditions:
// //
// Returns: B_ERROR, if there is an error allocating memory // Returns: B_NO_MEMORY, if there is an error allocating memory
// //
// B_OK, if all went well // B_OK, if all went well
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -1316,14 +1331,13 @@ translate_from_bmppal_to_bits(BPositionIO *inSource,
outDestination->Seek(bitsoffset, SEEK_CUR); outDestination->Seek(bitsoffset, SEEK_CUR);
// allocate row buffers // allocate row buffers
uint8 *bmpRowData = new uint8[bmpRowBytes]; uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
if (!bmpRowData) if (!bmpRowData)
return B_ERROR; return B_NO_MEMORY;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) { if (!bitsRowData) {
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL; return B_NO_MEMORY;
return B_ERROR;
} }
memset(bitsRowData, 0xff, bitsRowBytes); memset(bitsRowData, 0xff, bitsRowBytes);
ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes); ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes);
@ -1351,9 +1365,7 @@ translate_from_bmppal_to_bits(BPositionIO *inSource,
} }
delete[] bmpRowData; delete[] bmpRowData;
bmpRowData = NULL;
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
return B_OK; return B_OK;
} }
@ -1433,13 +1445,12 @@ translate_from_bmppalr_to_bits(BPositionIO *inSource,
// This call should work for BFile and BMallocIO objects, // This call should work for BFile and BMallocIO objects,
// but may not work for other BPositionIO based types // but may not work for other BPositionIO based types
return B_ERROR; return B_ERROR;
uint8 *bitsRowData = new uint8[bitsRowBytes]; uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
if (!bitsRowData) if (!bitsRowData)
return B_ERROR; return B_NO_MEMORY;
memset(bitsRowData, 0xff, bitsRowBytes); memset(bitsRowData, 0xff, bitsRowBytes);
uint32 bmppixcol = 0, bmppixrow = 0; uint32 bmppixcol = 0, bmppixrow = 0;
uint32 defaultcolor = 0; uint32 defaultcolor = *(uint32*)palette;
memcpy(&defaultcolor, palette, 4);
// set bits output to last row in the image // set bits output to last row in the image
off_t bitsoffset = ((msheader.height - (bmppixrow + 1)) * bitsRowBytes) + off_t bitsoffset = ((msheader.height - (bmppixrow + 1)) * bitsRowBytes) +
(bmppixcol * 4); (bmppixcol * 4);
@ -1610,7 +1621,6 @@ translate_from_bmppalr_to_bits(BPositionIO *inSource,
} }
delete[] bitsRowData; delete[] bitsRowData;
bitsRowData = NULL;
if (!rd) if (!rd)
return B_OK; return B_OK;
@ -1657,8 +1667,10 @@ BMPTranslator::translate_from_bmp(BPositionIO *inSource, uint32 outType,
status_t result; status_t result;
result = identify_bmp_header(inSource, NULL, &fileHeader, &msheader, result = identify_bmp_header(inSource, NULL, &fileHeader, &msheader,
&frommsformat, &os2skip); &frommsformat, &os2skip);
if (result != B_OK) if (result != B_OK) {
INFO("BMPTranslator::translate_from_bmp() - identify_bmp_header failed\n");
return result; return result;
}
// if the user wants to translate a BMP to a BMP, easy enough :) // if the user wants to translate a BMP to a BMP, easy enough :)
if (outType == B_BMP_FORMAT) { if (outType == B_BMP_FORMAT) {