initial check in for PPMTranslator from BeOS R5 sample-code folder
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3551 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
fae8d042d5
commit
60afeeca54
5
src/add-ons/translators/ppmtranslator/Jamfile
Normal file
5
src/add-ons/translators/ppmtranslator/Jamfile
Normal file
@ -0,0 +1,5 @@
|
||||
SubDir OBOS_TOP src add-ons translators ppmtranslator ;
|
||||
|
||||
Translator PPMTranslator : PPMMain.cpp PPMTranslator.cpp colorspace.cpp ;
|
||||
|
||||
LinkSharedOSLibs PPMTranslator : be translation ;
|
31
src/add-ons/translators/ppmtranslator/LICENSE
Normal file
31
src/add-ons/translators/ppmtranslator/LICENSE
Normal file
@ -0,0 +1,31 @@
|
||||
----------------------
|
||||
Be Sample Code License
|
||||
----------------------
|
||||
|
||||
Copyright 1991-1999, Be Incorporated.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
74
src/add-ons/translators/ppmtranslator/PPMMain.cpp
Normal file
74
src/add-ons/translators/ppmtranslator/PPMMain.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#include <TranslatorAddOn.h>
|
||||
#include <View.h>
|
||||
#include <Window.h>
|
||||
#include <Application.h>
|
||||
#include <Alert.h>
|
||||
#include <Screen.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
BPoint get_window_origin();
|
||||
void set_window_origin(BPoint pt);
|
||||
|
||||
class PPMWindow :
|
||||
public BWindow
|
||||
{
|
||||
public:
|
||||
PPMWindow(
|
||||
BRect area) :
|
||||
BWindow(area, "PPMTranslator", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
|
||||
{
|
||||
}
|
||||
~PPMWindow()
|
||||
{
|
||||
BPoint pt(0,0);
|
||||
ConvertToScreen(&pt);
|
||||
set_window_origin(pt);
|
||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
BApplication app("application/x-vnd.hplus-ppm-translator");
|
||||
BView * v = NULL;
|
||||
BRect r(0,0,200,100);
|
||||
if (MakeConfig(NULL, &v, &r)) {
|
||||
BAlert * err = new BAlert("Error", "Something is wrong with the PPMTranslator!", "OK");
|
||||
err->Go();
|
||||
return 1;
|
||||
}
|
||||
PPMWindow *w = new PPMWindow(r);
|
||||
v->ResizeTo(r.Width(), r.Height());
|
||||
w->AddChild(v);
|
||||
BPoint o = get_window_origin();
|
||||
{
|
||||
BScreen scrn;
|
||||
BRect f = scrn.Frame();
|
||||
f.InsetBy(10,23);
|
||||
/* if not in a good place, start where the cursor is */
|
||||
if (!f.Contains(o)) {
|
||||
uint32 i;
|
||||
v->GetMouse(&o, &i, false);
|
||||
o.x -= r.Width()/2;
|
||||
o.y -= r.Height()/2;
|
||||
/* clamp location to screen */
|
||||
if (o.x < f.left) o.x = f.left;
|
||||
if (o.y < f.top) o.y = f.top;
|
||||
if (o.x > f.right) o.x = f.right;
|
||||
if (o.y > f.bottom) o.y = f.bottom;
|
||||
}
|
||||
}
|
||||
w->MoveTo(o);
|
||||
w->Show();
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
992
src/add-ons/translators/ppmtranslator/PPMTranslator.cpp
Normal file
992
src/add-ons/translators/ppmtranslator/PPMTranslator.cpp
Normal file
@ -0,0 +1,992 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
/* Parse the ASCII and raw versions of PPM. */
|
||||
/* Note that the parsing of ASCII is very inefficient, because BFile */
|
||||
/* does not buffer data. We should wrap a buffering thing around */
|
||||
/* the input or output when they are in ASCII mode. */
|
||||
|
||||
#include <TranslatorAddOn.h>
|
||||
#include <TranslationKit.h>
|
||||
#include <ByteOrder.h>
|
||||
#include <Message.h>
|
||||
#include <Screen.h>
|
||||
#include <Locker.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Path.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <MenuField.h>
|
||||
#include <MenuItem.h>
|
||||
#include <CheckBox.h>
|
||||
#include <Bitmap.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "colorspace.h"
|
||||
|
||||
|
||||
#if DEBUG
|
||||
#define dprintf(x) printf x
|
||||
#else
|
||||
#define dprintf(x)
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(_PR3_COMPATIBLE_) /* R4 headers? Else we need to define these constants. */
|
||||
#define B_CMY24 ((color_space)0xC001) /* C[7:0] M[7:0] Y[7:0] No gray removal done */
|
||||
#define B_CMY32 ((color_space)0xC002) /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
|
||||
#define B_CMYA32 ((color_space)0xE002) /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
|
||||
#define B_CMYK32 ((color_space)0xC003) /* C[7:0] M[7:0] Y[7:0] K[7:0] */
|
||||
#endif
|
||||
|
||||
|
||||
/* These three data items are exported by every translator. */
|
||||
char translatorName[] = "PPMTranslator";
|
||||
char translatorInfo[] = "Reads and writes images in the PPM file format. http://www.be.com/";
|
||||
int32 translatorVersion = 100; /* format is revision+minor*10+major*100 */
|
||||
|
||||
|
||||
/* Be reserves all codes with non-lowecase letters in them. */
|
||||
/* Luckily, there is already a reserved code for PPM. If you */
|
||||
/* make up your own for a new type, use lower-case letters. */
|
||||
#define PPM_TYPE 'PPM '
|
||||
|
||||
|
||||
/* These two data arrays are a really good idea to export from Translators, but not required. */
|
||||
translation_format inputFormats[] = {
|
||||
{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMHandler)" },
|
||||
{ PPM_TYPE, B_TRANSLATOR_BITMAP, 0.3, 0.8, "image/x-ppm", "PPM portable pixmap format" },
|
||||
{ 0, 0, 0, 0, "\0", "\0" }
|
||||
}; /* optional (else Identify is always called) */
|
||||
|
||||
translation_format outputFormats[] = {
|
||||
{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMHandler)" },
|
||||
{ PPM_TYPE, B_TRANSLATOR_BITMAP, 0.3, 0.8, "image/x-ppm", "PPM portable pixmap format" },
|
||||
{ 0, 0, 0, 0, "\0", "\0" }
|
||||
}; /* optional (else Translate is called anyway) */
|
||||
|
||||
/* Translators that don't export outputFormats */
|
||||
/* will not be considered by files looking for */
|
||||
/* specific output formats. */
|
||||
|
||||
|
||||
/* We keep our settings in a global struct, and wrap a lock around them. */
|
||||
struct ppm_settings {
|
||||
color_space out_space;
|
||||
BPoint window_pos;
|
||||
bool write_ascii;
|
||||
bool settings_touched;
|
||||
};
|
||||
BLocker g_settings_lock("PPM settings lock");
|
||||
ppm_settings g_settings;
|
||||
|
||||
BPoint get_window_origin();
|
||||
void set_window_origin(BPoint pos);
|
||||
BPoint get_window_origin()
|
||||
{
|
||||
BPoint ret;
|
||||
g_settings_lock.Lock();
|
||||
ret = g_settings.window_pos;
|
||||
g_settings_lock.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void set_window_origin(BPoint pos)
|
||||
{
|
||||
g_settings_lock.Lock();
|
||||
g_settings.window_pos = pos;
|
||||
g_settings.settings_touched = true;
|
||||
g_settings_lock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
class PrefsLoader {
|
||||
public:
|
||||
PrefsLoader(
|
||||
const char * str)
|
||||
{
|
||||
dprintf(("PPMTranslator: PrefsLoader()\n"));
|
||||
/* defaults */
|
||||
g_settings.out_space = B_NO_COLOR_SPACE;
|
||||
g_settings.window_pos = B_ORIGIN;
|
||||
g_settings.write_ascii = false;
|
||||
g_settings.settings_touched = false;
|
||||
BPath path;
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path)) {
|
||||
path.SetTo("/tmp");
|
||||
}
|
||||
path.Append(str);
|
||||
FILE * f = fopen(path.Path(), "r");
|
||||
/* parse text settings file -- this should be a library... */
|
||||
if (f) {
|
||||
char line[1024];
|
||||
char name[32];
|
||||
char * ptr;
|
||||
while (true) {
|
||||
line[0] = 0;
|
||||
fgets(line, 1024, f);
|
||||
if (!line[0]) {
|
||||
break;
|
||||
}
|
||||
/* remember: line ends with \n, so printf()s don't have to */
|
||||
ptr = line;
|
||||
while (isspace(*ptr)) {
|
||||
ptr++;
|
||||
}
|
||||
if (*ptr == '#' || !*ptr) { /* comment or blank */
|
||||
continue;
|
||||
}
|
||||
if (sscanf(ptr, "%31[a-zA-Z_0-9] =", name) != 1) {
|
||||
fprintf(stderr, "unknown PPMTranslator settings line: %s", line);
|
||||
}
|
||||
else {
|
||||
if (!strcmp(name, "color_space")) {
|
||||
while (*ptr != '=') {
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
if (sscanf(ptr, "%d", (int*)&g_settings.out_space) != 1) {
|
||||
fprintf(stderr, "illegal color space in PPMTranslator settings: %s", ptr);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(name, "window_pos")) {
|
||||
while (*ptr != '=') {
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
if (sscanf(ptr, "%f,%f", &g_settings.window_pos.x, &g_settings.window_pos.y) != 2) {
|
||||
fprintf(stderr, "illegal window position in PPMTranslator settings: %s", ptr);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(name, "write_ascii")) {
|
||||
while (*ptr != '=') {
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
int ascii = g_settings.write_ascii;
|
||||
if (sscanf(ptr, "%d", &ascii) != 1) {
|
||||
fprintf(stderr, "illegal write_ascii value in PPMTranslator settings: %s", ptr);
|
||||
}
|
||||
else {
|
||||
g_settings.write_ascii = ascii;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "unknown PPMTranslator setting: %s", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
~PrefsLoader()
|
||||
{
|
||||
/* No need writing settings if there aren't any */
|
||||
if (g_settings.settings_touched) {
|
||||
BPath path;
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path)) {
|
||||
path.SetTo("/tmp");
|
||||
}
|
||||
path.Append("PPMTranslator_Settings");
|
||||
FILE * f = fopen(path.Path(), "w");
|
||||
if (f) {
|
||||
fprintf(f, "# PPMTranslator settings version %.2f\n", (float)translatorVersion/100.0);
|
||||
fprintf(f, "color_space = %d\n", g_settings.out_space);
|
||||
fprintf(f, "window_pos = %g,%g\n", g_settings.window_pos.x, g_settings.window_pos.y);
|
||||
fprintf(f, "write_ascii = %d\n", g_settings.write_ascii ? 1 : 0);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PrefsLoader g_prefs_loader("PPMTranslator_Settings");
|
||||
|
||||
/* Some prototypes for functions we use. */
|
||||
status_t read_ppm_header(BDataIO * io, int * width, int * rowbytes, int * height,
|
||||
int * max, bool * ascii, color_space * space, bool * is_ppm, char ** comment);
|
||||
status_t read_bits_header(BDataIO * io, int skipped, int * width, int * rowbytes,
|
||||
int * height, int * max, bool * ascii, color_space * space);
|
||||
status_t write_comment(const char * str, BDataIO * io);
|
||||
status_t copy_data(BDataIO * in, BDataIO * out, int rowbytes, int out_rowbytes,
|
||||
int height, int max, bool in_ascii, bool out_ascii, color_space in_space,
|
||||
color_space out_space);
|
||||
|
||||
/* Return B_NO_TRANSLATOR if not handling this data. */
|
||||
/* Even if inputFormats exists, may be called for data without hints */
|
||||
/* If outType is not 0, must be able to export in wanted format */
|
||||
|
||||
status_t
|
||||
Identify( /* required */
|
||||
BPositionIO * inSource,
|
||||
const translation_format * inFormat, /* can beNULL */
|
||||
BMessage * ioExtension, /* can be NULL */
|
||||
translator_info * outInfo,
|
||||
uint32 outType)
|
||||
{
|
||||
dprintf(("PPMTranslator: Identify()\n"));
|
||||
/* Silence compiler warnings. */
|
||||
inFormat = inFormat;
|
||||
ioExtension = ioExtension;
|
||||
|
||||
/* Check that requested format is something we can deal with. */
|
||||
if (outType == 0) {
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
}
|
||||
if (outType != B_TRANSLATOR_BITMAP && outType != PPM_TYPE) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
/* Check header. */
|
||||
int width, rowbytes, height, max;
|
||||
bool ascii, is_ppm;
|
||||
color_space space;
|
||||
status_t err = read_ppm_header(inSource, &width, &rowbytes, &height, &max, &ascii, &space, &is_ppm, NULL);
|
||||
if (err != B_OK) {
|
||||
return err;
|
||||
}
|
||||
/* Stuff info into info struct -- Translation Kit will do "translator" for us. */
|
||||
outInfo->group = B_TRANSLATOR_BITMAP;
|
||||
if (is_ppm) {
|
||||
outInfo->type = PPM_TYPE;
|
||||
outInfo->quality = 0.3; /* no alpha, etc */
|
||||
outInfo->capability = 0.8; /* we're pretty good at PPM reading, though */
|
||||
strcpy(outInfo->name, "PPM portable pixmap format");
|
||||
strcpy(outInfo->MIME, "image/x-ppm");
|
||||
}
|
||||
else {
|
||||
outInfo->type = B_TRANSLATOR_BITMAP;
|
||||
outInfo->quality = 0.4; /* B_TRANSLATOR_BITMAP can do alpha, at least */
|
||||
outInfo->capability = 0.8; /* and we might not know many variations thereof */
|
||||
strcpy(outInfo->name, "Be Bitmap Format (PPMHandler)");
|
||||
strcpy(outInfo->MIME, "image/x-be-bitmap"); /* this is the MIME type of B_TRANSLATOR_BITMAP */
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Return B_NO_TRANSLATOR if not handling the output format */
|
||||
/* If outputFormats exists, will only be called for those formats */
|
||||
|
||||
status_t
|
||||
Translate( /* required */
|
||||
BPositionIO * inSource,
|
||||
const translator_info * /* inInfo*/ , /* silence compiler warning */
|
||||
BMessage * ioExtension, /* can be NULL */
|
||||
uint32 outType,
|
||||
BPositionIO * outDestination)
|
||||
{
|
||||
dprintf(("PPMTranslator: Translate()\n"));
|
||||
inSource->Seek(0, SEEK_SET); /* paranoia */
|
||||
// inInfo = inInfo; /* silence compiler warning */
|
||||
/* Check what we're being asked to produce. */
|
||||
if (!outType) {
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
}
|
||||
dprintf(("PPMTranslator: outType is '%c%c%c%c'\n", char(outType>>24), char(outType>>16), char(outType>>8), char(outType)));
|
||||
if (outType != B_TRANSLATOR_BITMAP && outType != PPM_TYPE) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
/* Figure out what we've been given (again). */
|
||||
int width, rowbytes, height, max;
|
||||
bool ascii, is_ppm;
|
||||
color_space space;
|
||||
/* Read_ppm_header() will always return with stream at beginning of data */
|
||||
/* for both B_TRANSLATOR_BITMAP and PPM_TYPE, and indicate what it is. */
|
||||
char * comment = NULL;
|
||||
status_t err = read_ppm_header(inSource, &width, &rowbytes, &height, &max, &ascii, &space, &is_ppm, &comment);
|
||||
if (comment != NULL) {
|
||||
if (ioExtension != NULL) {
|
||||
#if defined(_PR3_COMPATIBLE_) /* R4 headers? */
|
||||
ioExtension->AddString(B_TRANSLATOR_EXT_COMMENT, comment);
|
||||
#else
|
||||
ioExtension->AddString("/comment", comment);
|
||||
#endif
|
||||
}
|
||||
free(comment);
|
||||
}
|
||||
if (err < B_OK) {
|
||||
dprintf(("read_ppm_header() error %s [%lx]\n", strerror(err), err));
|
||||
return err;
|
||||
}
|
||||
/* Check if we're configured to write ASCII format file. */
|
||||
bool out_ascii = false;
|
||||
if (outType == PPM_TYPE) {
|
||||
out_ascii = g_settings.write_ascii;
|
||||
if (ioExtension != NULL) {
|
||||
ioExtension->FindBool("ppm /ascii", &out_ascii);
|
||||
}
|
||||
}
|
||||
err = B_OK;
|
||||
/* Figure out which color space to convert to */
|
||||
color_space out_space;
|
||||
int out_rowbytes;
|
||||
g_settings_lock.Lock();
|
||||
if (outType == PPM_TYPE) {
|
||||
out_space = B_RGB24_BIG;
|
||||
out_rowbytes = 3*width;
|
||||
}
|
||||
else { /* When outputting to B_TRANSLATOR_BITMAP, follow user's wishes. */
|
||||
#if defined(_PR3_COMPATIBLE_) /* R4 headers? */
|
||||
if (!ioExtension || ioExtension->FindInt32(B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE, (int32*)&out_space) ||
|
||||
#else
|
||||
if (!ioExtension || ioExtension->FindInt32("bits/space", (int32*)&out_space) ||
|
||||
#endif
|
||||
(out_space == B_NO_COLOR_SPACE)) {
|
||||
if (g_settings.out_space == B_NO_COLOR_SPACE) {
|
||||
switch (space) { /* The 24-bit versions are pretty silly, use 32 instead. */
|
||||
case B_RGB24:
|
||||
case B_RGB24_BIG:
|
||||
out_space = B_RGB32;
|
||||
break;
|
||||
default:
|
||||
/* use whatever is there */
|
||||
out_space = space;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
out_space = g_settings.out_space;
|
||||
}
|
||||
}
|
||||
out_rowbytes = calc_rowbytes(out_space, width);
|
||||
}
|
||||
g_settings_lock.Unlock();
|
||||
/* Write file header */
|
||||
if (outType == PPM_TYPE) {
|
||||
dprintf(("PPMTranslator: write PPM\n"));
|
||||
/* begin PPM header */
|
||||
const char * magic;
|
||||
if (out_ascii)
|
||||
magic = "P3\n";
|
||||
else
|
||||
magic = "P6\n";
|
||||
err = outDestination->Write(magic, strlen(magic));
|
||||
if (err == (long)strlen(magic)) err = 0;
|
||||
//comment = NULL;
|
||||
const char* fsComment;
|
||||
#if defined(_PR3_COMPATIBLE_) /* R4 headers? */
|
||||
if ((ioExtension != NULL) && !ioExtension->FindString(B_TRANSLATOR_EXT_COMMENT, &fsComment)) {
|
||||
#else
|
||||
if ((ioExtension != NULL) && !ioExtension->FindString("/comment", &fsComment)) {
|
||||
#endif
|
||||
err = write_comment(fsComment, outDestination);
|
||||
}
|
||||
if (err == B_OK) {
|
||||
char data[40];
|
||||
sprintf(data, "%d %d %d\n", width, height, max);
|
||||
err = outDestination->Write(data, strlen(data));
|
||||
if (err == (long)strlen(data)) err = 0;
|
||||
}
|
||||
/* header done */
|
||||
}
|
||||
else {
|
||||
dprintf(("PPMTranslator: write B_TRANSLATOR_BITMAP\n"));
|
||||
/* B_TRANSLATOR_BITMAP header */
|
||||
TranslatorBitmap hdr;
|
||||
hdr.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
|
||||
hdr.bounds.left = B_HOST_TO_BENDIAN_FLOAT(0);
|
||||
hdr.bounds.top = B_HOST_TO_BENDIAN_FLOAT(0);
|
||||
hdr.bounds.right = B_HOST_TO_BENDIAN_FLOAT(width-1);
|
||||
hdr.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(height-1);
|
||||
hdr.rowBytes = B_HOST_TO_BENDIAN_INT32(out_rowbytes);
|
||||
hdr.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_space);
|
||||
hdr.dataSize = B_HOST_TO_BENDIAN_INT32(out_rowbytes*height);
|
||||
dprintf(("rowBytes is %d, width %d, out_space %x, space %x\n", out_rowbytes, width, out_space, space));
|
||||
err = outDestination->Write(&hdr, sizeof(hdr));
|
||||
dprintf(("PPMTranslator: Write() returns %lx\n", err));
|
||||
#if DEBUG
|
||||
{
|
||||
BBitmap * map = new BBitmap(BRect(0,0,width-1,height-1), out_space);
|
||||
printf("map rb = %ld\n", map->BytesPerRow());
|
||||
delete map;
|
||||
}
|
||||
#endif
|
||||
if (err == sizeof(hdr)) err = 0;
|
||||
/* header done */
|
||||
}
|
||||
if (err != B_OK) {
|
||||
return err > 0 ? B_IO_ERROR : err;
|
||||
}
|
||||
/* Write data. Luckily, PPM and B_TRANSLATOR_BITMAP both scan from left to right, top to bottom. */
|
||||
return copy_data(inSource, outDestination, rowbytes, out_rowbytes, height, max, ascii, out_ascii, space, out_space);
|
||||
}
|
||||
|
||||
|
||||
class PPMView :
|
||||
public BView
|
||||
{
|
||||
public:
|
||||
PPMView(
|
||||
const BRect & frame,
|
||||
const char * name,
|
||||
uint32 resize,
|
||||
uint32 flags) :
|
||||
BView(frame, name, resize, flags)
|
||||
{
|
||||
SetViewColor(220,220,220,0);
|
||||
mMenu = new BPopUpMenu("Color Space");
|
||||
mMenu->AddItem(new BMenuItem("None", CSMessage(B_NO_COLOR_SPACE)));
|
||||
mMenu->AddItem(new BMenuItem("RGB 8:8:8 32 bits", CSMessage(B_RGB32)));
|
||||
mMenu->AddItem(new BMenuItem("RGBA 8:8:8:8 32 bits", CSMessage(B_RGBA32)));
|
||||
mMenu->AddItem(new BMenuItem("RGB 5:5:5 16 bits", CSMessage(B_RGB15)));
|
||||
mMenu->AddItem(new BMenuItem("RGBA 5:5:5:1 16 bits", CSMessage(B_RGBA15)));
|
||||
mMenu->AddItem(new BMenuItem("RGB 5:6:5 16 bits", CSMessage(B_RGB16)));
|
||||
mMenu->AddItem(new BMenuItem("System Palette 8 bits", CSMessage(B_CMAP8)));
|
||||
mMenu->AddSeparatorItem();
|
||||
mMenu->AddItem(new BMenuItem("Grayscale 8 bits", CSMessage(B_GRAY8)));
|
||||
mMenu->AddItem(new BMenuItem("Bitmap 1 bit", CSMessage(B_GRAY1)));
|
||||
mMenu->AddItem(new BMenuItem("CMY 8:8:8 32 bits", CSMessage(B_CMY32)));
|
||||
mMenu->AddItem(new BMenuItem("CMYA 8:8:8:8 32 bits", CSMessage(B_CMYA32)));
|
||||
mMenu->AddItem(new BMenuItem("CMYK 8:8:8:8 32 bits", CSMessage(B_CMYK32)));
|
||||
mMenu->AddSeparatorItem();
|
||||
mMenu->AddItem(new BMenuItem("RGB 8:8:8 32 bits big-endian", CSMessage(B_RGB32_BIG)));
|
||||
mMenu->AddItem(new BMenuItem("RGBA 8:8:8:8 32 bits big-endian", CSMessage(B_RGBA32_BIG)));
|
||||
mMenu->AddItem(new BMenuItem("RGB 5:5:5 16 bits big-endian", CSMessage(B_RGB15_BIG)));
|
||||
mMenu->AddItem(new BMenuItem("RGBA 5:5:5:1 16 bits big-endian", CSMessage(B_RGBA15_BIG)));
|
||||
mMenu->AddItem(new BMenuItem("RGB 5:6:5 16 bits big-endian", CSMessage(B_RGB16)));
|
||||
mField = new BMenuField(BRect(20,70,180,90), "Color Space Field", "Color Space", mMenu);
|
||||
mField->SetViewColor(ViewColor());
|
||||
AddChild(mField);
|
||||
SelectColorSpace(g_settings.out_space);
|
||||
BMessage * msg = new BMessage(CHANGE_ASCII);
|
||||
mAscii = new BCheckBox(BRect(20,45,180,62), "Write ASCII", "Write ASCII", msg);
|
||||
if (g_settings.write_ascii) {
|
||||
mAscii->SetValue(1);
|
||||
}
|
||||
mAscii->SetViewColor(ViewColor());
|
||||
AddChild(mAscii);
|
||||
}
|
||||
~PPMView()
|
||||
{
|
||||
/* nothing here */
|
||||
}
|
||||
|
||||
enum {
|
||||
SET_COLOR_SPACE = 'ppm=',
|
||||
CHANGE_ASCII
|
||||
};
|
||||
|
||||
virtual void Draw(
|
||||
BRect area)
|
||||
{
|
||||
area = area; /* silence compiler */
|
||||
SetFont(be_bold_font);
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
char str[100];
|
||||
sprintf(str, "PPMTranslator %.2f", (float)translatorVersion/100.0);
|
||||
DrawString(str, BPoint(fh.descent+1, fh.ascent+fh.descent*2+fh.leading));
|
||||
}
|
||||
virtual void MessageReceived(
|
||||
BMessage * message)
|
||||
{
|
||||
if (message->what == SET_COLOR_SPACE) {
|
||||
SetSettings(message);
|
||||
}
|
||||
else if (message->what == CHANGE_ASCII) {
|
||||
BMessage msg;
|
||||
msg.AddBool("ppm /ascii", mAscii->Value());
|
||||
SetSettings(&msg);
|
||||
}
|
||||
else {
|
||||
BView::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
virtual void AllAttached()
|
||||
{
|
||||
BView::AllAttached();
|
||||
BMessenger msgr(this);
|
||||
/* Tell all menu items we're the man. */
|
||||
for (int ix=0; ix<mMenu->CountItems(); ix++) {
|
||||
BMenuItem * i = mMenu->ItemAt(ix);
|
||||
if (i) {
|
||||
i->SetTarget(msgr);
|
||||
}
|
||||
}
|
||||
mAscii->SetTarget(msgr);
|
||||
}
|
||||
|
||||
void SetSettings(
|
||||
BMessage * message)
|
||||
{
|
||||
g_settings_lock.Lock();
|
||||
color_space space;
|
||||
if (!message->FindInt32("space", (int32*)&space)) {
|
||||
g_settings.out_space = space;
|
||||
SelectColorSpace(space);
|
||||
g_settings.settings_touched = true;
|
||||
}
|
||||
bool ascii;
|
||||
if (!message->FindBool("ppm /ascii", &ascii)) {
|
||||
g_settings.write_ascii = ascii;
|
||||
g_settings.settings_touched = true;
|
||||
}
|
||||
g_settings_lock.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
BPopUpMenu * mMenu;
|
||||
BMenuField * mField;
|
||||
BCheckBox * mAscii;
|
||||
|
||||
BMessage * CSMessage(
|
||||
color_space space)
|
||||
{
|
||||
BMessage * ret = new BMessage(SET_COLOR_SPACE);
|
||||
ret->AddInt32("space", space);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SelectColorSpace(
|
||||
color_space space)
|
||||
{
|
||||
for (int ix=0; ix<mMenu->CountItems(); ix++) {
|
||||
int32 s;
|
||||
BMenuItem * i = mMenu->ItemAt(ix);
|
||||
if (i) {
|
||||
BMessage * m = i->Message();
|
||||
if (m && !m->FindInt32("space", &s) && (s == space)) {
|
||||
mMenu->Superitem()->SetLabel(i->Label());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* The view will get resized to what the parent thinks is */
|
||||
/* reasonable. However, it will still receive MouseDowns etc. */
|
||||
/* Your view should change settings in the translator immediately, */
|
||||
/* taking care not to change parameters for a translation that is */
|
||||
/* currently running. Typically, you'll have a global struct for */
|
||||
/* settings that is atomically copied into the translator function */
|
||||
/* as a local when translation starts. */
|
||||
/* Store your settings wherever you feel like it. */
|
||||
|
||||
status_t
|
||||
MakeConfig( /* optional */
|
||||
BMessage * ioExtension, /* can be NULL */
|
||||
BView * * outView,
|
||||
BRect * outExtent)
|
||||
{
|
||||
PPMView * v = new PPMView(BRect(0,0,200,100), "PPMTranslator Settings", B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
*outView = v;
|
||||
*outExtent = v->Bounds();
|
||||
if (ioExtension) {
|
||||
v->SetSettings(ioExtension);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Copy your current settings to a BMessage that may be passed */
|
||||
/* to BTranslators::Translate at some later time when the user wants to */
|
||||
/* use whatever settings you're using right now. */
|
||||
|
||||
status_t
|
||||
GetConfigMessage( /* optional */
|
||||
BMessage * ioExtension)
|
||||
{
|
||||
status_t err = B_OK;
|
||||
#if defined(_PR3_COMPATIBLE_)
|
||||
const char * name = B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE;
|
||||
#else
|
||||
const char * name = "bits/space";
|
||||
#endif
|
||||
g_settings_lock.Lock();
|
||||
(void)ioExtension->RemoveName(name);
|
||||
err = ioExtension->AddInt32(name, g_settings.out_space);
|
||||
g_settings_lock.Unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
read_ppm_header(
|
||||
BDataIO * inSource,
|
||||
int * width,
|
||||
int * rowbytes,
|
||||
int * height,
|
||||
int * max,
|
||||
bool * ascii,
|
||||
color_space * space,
|
||||
bool * is_ppm,
|
||||
char ** comment)
|
||||
{
|
||||
/* check for PPM magic number */
|
||||
char ch[2];
|
||||
if (inSource->Read(ch, 2) != 2) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
/* look for magic number */
|
||||
if (ch[0] != 'P') {
|
||||
/* B_TRANSLATOR_BITMAP magic? */
|
||||
if (ch[0] == 'b' && ch[1] == 'i') {
|
||||
*is_ppm = false;
|
||||
return read_bits_header(inSource, 2, width, rowbytes, height, max, ascii, space);
|
||||
}
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
*is_ppm = true;
|
||||
if (ch[1] == '6') {
|
||||
*ascii = false;
|
||||
}
|
||||
else if (ch[1] == '3') {
|
||||
*ascii = true;
|
||||
}
|
||||
else {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
// status_t err = B_NO_TRANSLATOR;
|
||||
enum scan_state {
|
||||
scan_width,
|
||||
scan_height,
|
||||
scan_max,
|
||||
scan_white
|
||||
} state = scan_width;
|
||||
int * scan = NULL;
|
||||
bool in_comment = false;
|
||||
*space = B_RGB24_BIG;
|
||||
/* The description of PPM is slightly ambiguous as far as comments */
|
||||
/* go. We choose to allow comments anywhere, in the spirit of laxness. */
|
||||
/* See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/PPM.txt */
|
||||
int comlen = 0;
|
||||
int comptr = 0;
|
||||
while (inSource->Read(ch, 1) == 1) {
|
||||
if (in_comment && (ch[0] != 10) && (ch[0] != 13)) {
|
||||
if (comment) { /* collect comment(s) into comment string */
|
||||
if (comptr >= comlen-1) {
|
||||
char * n = (char *)realloc(*comment, comlen+100);
|
||||
if (!n) {
|
||||
free(*comment);
|
||||
*comment = NULL;
|
||||
}
|
||||
*comment = n;
|
||||
comlen += 100;
|
||||
}
|
||||
(*comment)[comptr++] = ch[0];
|
||||
(*comment)[comptr] = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
in_comment = false;
|
||||
if (ch[0] == '#') {
|
||||
in_comment = true;
|
||||
continue;
|
||||
}
|
||||
/* once we're done with whitespace after max, we're done with header */
|
||||
if (isdigit(ch[0])) {
|
||||
if (!scan) { /* first digit for this value */
|
||||
switch(state) {
|
||||
case scan_width:
|
||||
scan = width;
|
||||
break;
|
||||
case scan_height:
|
||||
*rowbytes = *width*3;
|
||||
scan = height;
|
||||
break;
|
||||
case scan_max:
|
||||
scan = max;
|
||||
break;
|
||||
default:
|
||||
return B_OK; /* done with header, all OK */
|
||||
}
|
||||
*scan = 0;
|
||||
}
|
||||
*scan = (*scan)*10 + (ch[0]-'0');
|
||||
}
|
||||
else if (isspace(ch[0])) {
|
||||
if (scan) { /* are we done with one value? */
|
||||
scan = NULL;
|
||||
state = (enum scan_state)(state+1);
|
||||
}
|
||||
if (state == scan_white) { /* we only ever read one whitespace, since we skip space */
|
||||
return B_OK; /* when reading ASCII, and there is a single whitespace after max in raw mode */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state != scan_white) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
return B_OK; /* header done */
|
||||
}
|
||||
}
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
read_bits_header(
|
||||
BDataIO * io,
|
||||
int skipped,
|
||||
int * width,
|
||||
int * rowbytes,
|
||||
int * height,
|
||||
int * max,
|
||||
bool * ascii,
|
||||
color_space * space)
|
||||
{
|
||||
/* read the rest of a possible B_TRANSLATOR_BITMAP header */
|
||||
if (skipped < 0 || skipped > 4) return B_NO_TRANSLATOR;
|
||||
int rd = sizeof(TranslatorBitmap)-skipped;
|
||||
TranslatorBitmap hdr;
|
||||
/* pre-initialize magic because we might have skipped part of it already */
|
||||
hdr.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
|
||||
char * ptr = (char *)&hdr;
|
||||
if (io->Read(ptr+skipped, rd) != rd) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
/* swap header values */
|
||||
hdr.magic = B_BENDIAN_TO_HOST_INT32(hdr.magic);
|
||||
hdr.bounds.left = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.left);
|
||||
hdr.bounds.right = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.right);
|
||||
hdr.bounds.top = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.top);
|
||||
hdr.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.bottom);
|
||||
hdr.rowBytes = B_BENDIAN_TO_HOST_INT32(hdr.rowBytes);
|
||||
hdr.colors = (color_space)B_BENDIAN_TO_HOST_INT32(hdr.colors);
|
||||
hdr.dataSize = B_BENDIAN_TO_HOST_INT32(hdr.dataSize);
|
||||
/* sanity checking */
|
||||
if (hdr.magic != B_TRANSLATOR_BITMAP) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
if (hdr.colors & 0xffff0000) { /* according to <GraphicsDefs.h> this is a reasonable check. */
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
if (hdr.rowBytes * (hdr.bounds.Height()+1) > hdr.dataSize) {
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
/* return information about the data in the stream */
|
||||
*width = (int)hdr.bounds.Width()+1;
|
||||
*rowbytes = hdr.rowBytes;
|
||||
*height = (int)hdr.bounds.Height()+1;
|
||||
*max = 255;
|
||||
*ascii = false;
|
||||
*space = hdr.colors;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/* String may contain newlines, after which we need to insert extra hash signs. */
|
||||
status_t
|
||||
write_comment(
|
||||
const char * str,
|
||||
BDataIO * io)
|
||||
{
|
||||
const char * end = str+strlen(str);
|
||||
const char * ptr = str;
|
||||
status_t err = B_OK;
|
||||
/* write each line as it's found */
|
||||
while ((ptr < end) && !err) {
|
||||
if ((*ptr == 10) || (*ptr == 13)) {
|
||||
err = io->Write("# ", 2);
|
||||
if (err == 2) {
|
||||
err = io->Write(str, ptr-str);
|
||||
if (err == ptr-str) {
|
||||
if (io->Write("\n", 1) == 1) {
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
str = ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
/* write the last data, if any, as a line */
|
||||
if (ptr > str) {
|
||||
err = io->Write("# ", 2);
|
||||
if (err == 2) {
|
||||
err = io->Write(str, ptr-str);
|
||||
if (err == ptr-str) {
|
||||
if (io->Write("\n", 1) == 1) {
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (err > 0) {
|
||||
err = B_IO_ERROR;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
read_ascii_line(
|
||||
BDataIO * in,
|
||||
int max,
|
||||
unsigned char * data,
|
||||
int rowbytes)
|
||||
{
|
||||
char ch;
|
||||
status_t err;
|
||||
// int nread = 0;
|
||||
bool comment = false;
|
||||
int val = 0;
|
||||
bool dig = false;
|
||||
while ((err = in->Read(&ch, 1)) == 1) {
|
||||
if (comment) {
|
||||
if ((ch == '\n') || (ch == '\r')) {
|
||||
comment = false;
|
||||
}
|
||||
}
|
||||
if (isdigit(ch)) {
|
||||
dig = true;
|
||||
val = val * 10 + (ch - '0');
|
||||
}
|
||||
else {
|
||||
if (dig) {
|
||||
*(data++) = val*255/max;
|
||||
val = 0;
|
||||
rowbytes--;
|
||||
dig = false;
|
||||
}
|
||||
if (ch == '#') {
|
||||
comment = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (rowbytes < 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dig) {
|
||||
*(data++) = val*255/max;
|
||||
val = 0;
|
||||
rowbytes--;
|
||||
dig = false;
|
||||
}
|
||||
if (rowbytes < 1) {
|
||||
return B_OK;
|
||||
}
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
write_ascii_line(
|
||||
BDataIO * out,
|
||||
unsigned char * data,
|
||||
int rowbytes)
|
||||
{
|
||||
char buffer[20];
|
||||
int linelen = 0;
|
||||
while (rowbytes > 2) {
|
||||
sprintf(buffer, "%d %d %d ", data[0], data[1], data[2]);
|
||||
rowbytes -= 3;
|
||||
int l = strlen(buffer);
|
||||
if (l + linelen > 70) {
|
||||
out->Write("\n", 1);
|
||||
linelen = 0;
|
||||
}
|
||||
if (out->Write(buffer, l) != l) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
linelen += l;
|
||||
data += 3;
|
||||
}
|
||||
out->Write("\n", 1); /* terminate each scanline */
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char *
|
||||
make_scale_data(
|
||||
int max)
|
||||
{
|
||||
unsigned char * ptr = (unsigned char *)malloc(max);
|
||||
for (int ix=0; ix<max; ix++) {
|
||||
ptr[ix] = ix*255/max;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
scale_data(
|
||||
unsigned char * scale,
|
||||
unsigned char * data,
|
||||
int bytes)
|
||||
{
|
||||
for (int ix=0; ix<bytes; ix++) {
|
||||
data[ix] = scale[data[ix]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
copy_data(
|
||||
BDataIO * in,
|
||||
BDataIO * out,
|
||||
int rowbytes,
|
||||
int out_rowbytes,
|
||||
int height,
|
||||
int max,
|
||||
bool in_ascii,
|
||||
bool out_ascii,
|
||||
color_space in_space,
|
||||
color_space out_space)
|
||||
{
|
||||
dprintf(("copy_data(%x, %x, %x, %x, %x, %x)\n", rowbytes, out_rowbytes, height, max, in_space, out_space));
|
||||
/* We read/write one scanline at a time. */
|
||||
unsigned char * data = (unsigned char *)malloc(rowbytes);
|
||||
unsigned char * out_data = (unsigned char *)malloc(out_rowbytes);
|
||||
if (data == NULL || out_data == NULL) {
|
||||
free(data);
|
||||
free(out_data);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
unsigned char * scale = NULL;
|
||||
if (max != 255) {
|
||||
scale = make_scale_data(max);
|
||||
}
|
||||
status_t err = B_OK;
|
||||
/* There is no data format conversion, so we can just copy data. */
|
||||
while ((height-- > 0) && !err) {
|
||||
if (in_ascii) {
|
||||
err = read_ascii_line(in, max, data, rowbytes);
|
||||
}
|
||||
else {
|
||||
err = in->Read(data, rowbytes);
|
||||
if (err == rowbytes) {
|
||||
err = B_OK;
|
||||
}
|
||||
if (scale) { /* for reading PPM that is smaller than 8 bit */
|
||||
scale_data(scale, data, rowbytes);
|
||||
}
|
||||
}
|
||||
if (err == B_OK) {
|
||||
unsigned char * wbuf = data;
|
||||
if (in_space != out_space) {
|
||||
err = convert_space(in_space, out_space, data, rowbytes, out_data);
|
||||
wbuf = out_data;
|
||||
}
|
||||
if (!err && out_ascii) {
|
||||
err = write_ascii_line(out, wbuf, out_rowbytes);
|
||||
}
|
||||
else if (!err) {
|
||||
err = out->Write(wbuf, out_rowbytes);
|
||||
if (err == out_rowbytes) {
|
||||
err = B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
free(out_data);
|
||||
free(scale);
|
||||
return err > 0 ? B_IO_ERROR : err;
|
||||
}
|
||||
|
||||
|
618
src/add-ons/translators/ppmtranslator/colorspace.cpp
Normal file
618
src/add-ons/translators/ppmtranslator/colorspace.cpp
Normal file
@ -0,0 +1,618 @@
|
||||
/* colorspace.cpp */
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <Debug.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "colorspace.h"
|
||||
|
||||
|
||||
#if !defined(_PR3_COMPATIBLE_)
|
||||
#define B_CMY24 ((color_space)0xC001) /* C[7:0] M[7:0] Y[7:0] No gray removal done */
|
||||
#define B_CMY32 ((color_space)0xC002) /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
|
||||
#define B_CMYA32 ((color_space)0xE002) /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
|
||||
#define B_CMYK32 ((color_space)0xC003) /* C[7:0] M[7:0] Y[7:0] K[7:0] */
|
||||
#endif
|
||||
|
||||
int
|
||||
expand_data( /* expands to BGRA in the output buffer from <whatever> in the input buffer */
|
||||
color_space from_space,
|
||||
unsigned char * in_data,
|
||||
int rowbytes,
|
||||
unsigned char * out_buf)
|
||||
{
|
||||
ASSERT(in_data != out_buf);
|
||||
|
||||
/* We don't do YUV and friends yet. */
|
||||
/* It's important to replicate the most significant component bits to LSB when going 15->24 */
|
||||
unsigned char * in_out = out_buf;
|
||||
switch (from_space) {
|
||||
case B_RGB32:
|
||||
while (rowbytes > 3) {
|
||||
out_buf[0] = in_data[0];
|
||||
out_buf[1] = in_data[1];
|
||||
out_buf[2] = in_data[2];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGBA32:
|
||||
memcpy(out_buf, in_data, rowbytes);
|
||||
break;
|
||||
case B_RGB24:
|
||||
while (rowbytes > 2) {
|
||||
out_buf[0] = in_data[0];
|
||||
out_buf[1] = in_data[1];
|
||||
out_buf[2] = in_data[2];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 3;
|
||||
rowbytes -= 3;
|
||||
}
|
||||
break;
|
||||
case B_RGB15:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[0]+(in_data[1]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
|
||||
out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_RGBA15:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[0]+(in_data[1]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
|
||||
out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
|
||||
out_buf[3] = (val&0x8000) ? 255 : 0;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_RGB16:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[0]+(in_data[1]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x7e0)>>3)|((val&0x7e0)>>9);
|
||||
out_buf[2] = ((val&0xf800)>>8)|((val&0xf800)>>13);
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
while (rowbytes > 3) {
|
||||
out_buf[0] = in_data[3];
|
||||
out_buf[1] = in_data[2];
|
||||
out_buf[2] = in_data[1];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGBA32_BIG:
|
||||
while (rowbytes > 3) {
|
||||
out_buf[0] = in_data[3];
|
||||
out_buf[1] = in_data[2];
|
||||
out_buf[2] = in_data[1];
|
||||
out_buf[3] = in_data[0];
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB24_BIG:
|
||||
while (rowbytes > 2) {
|
||||
out_buf[0] = in_data[2];
|
||||
out_buf[1] = in_data[1];
|
||||
out_buf[2] = in_data[0];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 3;
|
||||
rowbytes -= 3;
|
||||
}
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[1]+(in_data[0]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
|
||||
out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_RGBA15_BIG:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[1]+(in_data[0]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
|
||||
out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
|
||||
out_buf[3] = (val&0x8000) ? 255 : 0;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
while (rowbytes > 1) {
|
||||
uint16 val = in_data[1]+(in_data[0]<<8);
|
||||
out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
|
||||
out_buf[1] = ((val&0x7e0)>>3)|((val&0x7e0)>>9);
|
||||
out_buf[2] = ((val&0xf800)>>8)|((val&0xf800)>>13);
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 2;
|
||||
rowbytes -= 2;
|
||||
}
|
||||
break;
|
||||
case B_CMAP8: {
|
||||
const color_map * map = system_colors();
|
||||
while (rowbytes > 0) {
|
||||
rgb_color c = map->color_list[in_data[0]];
|
||||
out_buf[0] = c.blue;
|
||||
out_buf[1] = c.green;
|
||||
out_buf[2] = c.red;
|
||||
out_buf[3] = c.alpha;
|
||||
out_buf += 4;
|
||||
in_data += 1;
|
||||
rowbytes -= 1;
|
||||
}
|
||||
} break;
|
||||
case B_GRAY8:
|
||||
while (rowbytes > 0) {
|
||||
unsigned char ch = *in_data;
|
||||
out_buf[0] = ch;
|
||||
out_buf[1] = ch;
|
||||
out_buf[2] = ch;
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 1;
|
||||
rowbytes -= 1;
|
||||
}
|
||||
break;
|
||||
case B_GRAY1:
|
||||
while (rowbytes > 0) { /* expansion 1->32 is pretty good :-) */
|
||||
unsigned char c1 = *in_data;
|
||||
for (int b = 128; b; b = b>>1) {
|
||||
unsigned char ch;
|
||||
if (c1 & b) {
|
||||
ch = 0;
|
||||
}
|
||||
else {
|
||||
ch = 255;
|
||||
}
|
||||
out_buf[0] = ch;
|
||||
out_buf[1] = ch;
|
||||
out_buf[2] = ch;
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
}
|
||||
in_data += 1;
|
||||
rowbytes -= 1;
|
||||
}
|
||||
break;
|
||||
case B_CMY24: /* We do the "clean" inversion which doesn't correct for printing ink deficiencies. */
|
||||
while (rowbytes > 2) {
|
||||
out_buf[0] = 255-in_data[2];
|
||||
out_buf[1] = 255-in_data[1];
|
||||
out_buf[2] = 255-in_data[0];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 3;
|
||||
rowbytes -= 3;
|
||||
}
|
||||
break;
|
||||
case B_CMY32:
|
||||
while (rowbytes > 3) {
|
||||
out_buf[0] = 255-in_data[2];
|
||||
out_buf[1] = 255-in_data[1];
|
||||
out_buf[2] = 255-in_data[0];
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMYA32:
|
||||
while (rowbytes > 3) {
|
||||
out_buf[0] = 255-in_data[2];
|
||||
out_buf[1] = 255-in_data[1];
|
||||
out_buf[2] = 255-in_data[0];
|
||||
out_buf[3] = in_data[3];
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMYK32: /* We assume uniform gray removal, and no under-color-removal. */
|
||||
while (rowbytes > 3) {
|
||||
int comp = 255-in_data[2]-in_data[3];
|
||||
out_buf[0] = comp < 0 ? 0 : comp;
|
||||
comp = 255-in_data[1]-in_data[3];
|
||||
out_buf[1] = comp < 0 ? 0 : comp;
|
||||
comp = 255-in_data[0]-in_data[3];
|
||||
out_buf[2] = comp < 0 ? 0 : comp;
|
||||
out_buf[3] = 255;
|
||||
out_buf += 4;
|
||||
in_data += 4;
|
||||
rowbytes -= 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return out_buf - in_out;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
collapse_data(
|
||||
unsigned char * in_buf,
|
||||
int num_bytes,
|
||||
color_space out_space,
|
||||
unsigned char * out_buf)
|
||||
{
|
||||
ASSERT(in_buf != out_buf);
|
||||
|
||||
unsigned char * in_out = out_buf;
|
||||
/* We could increase perceived image quality of down conversions by implementing */
|
||||
/* dithering. However, someone might want to operate on the images after */
|
||||
/* conversion, in which case dithering would be un-good. Besides, good error */
|
||||
/* diffusion requires more than one scan line to propagate errors to. */
|
||||
switch(out_space) {
|
||||
case B_RGB32:
|
||||
memcpy(out_buf, in_buf, num_bytes);
|
||||
break;
|
||||
case B_RGBA32:
|
||||
memcpy(out_buf, in_buf, num_bytes);
|
||||
break;
|
||||
case B_RGB24:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[0] = in_buf[0];
|
||||
out_buf[1] = in_buf[1];
|
||||
out_buf[2] = in_buf[2];
|
||||
out_buf += 3;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB16:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<3)&0x7e0)|((in_buf[2]<<8)&0xf800);
|
||||
out_buf[0] = val;
|
||||
out_buf[1] = val>>8;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB15:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00)|0x8000;
|
||||
out_buf[0] = val;
|
||||
out_buf[1] = val>>8;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGBA15:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
|
||||
if (in_buf[3] > 127) {
|
||||
val = val | 0x8000;
|
||||
}
|
||||
out_buf[0] = val;
|
||||
out_buf[1] = val>>8;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMAP8: {
|
||||
const color_map * map = system_colors();
|
||||
while (num_bytes > 3) {
|
||||
if (in_buf[3] < 128) {
|
||||
out_buf[0] = B_TRANSPARENT_8_BIT;
|
||||
}
|
||||
else {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
|
||||
out_buf[0] = map->index_map[val];
|
||||
}
|
||||
out_buf += 1;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case B_GRAY8:
|
||||
while (num_bytes > 3) { /* There are better algorithms than Y = .25B+.50G+.25R */
|
||||
/* but hardly faster -- and it's still better than (B+G+R)/3 ! */
|
||||
out_buf[0] = (in_buf[0]+in_buf[1]*2+in_buf[2])>>2;
|
||||
out_buf += 1;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_GRAY1: {
|
||||
uchar ob = 0;
|
||||
int cnt = 0;
|
||||
uchar c = 0;
|
||||
while (num_bytes > 3) {
|
||||
if (cnt == 8) {
|
||||
out_buf[0] = ob;
|
||||
out_buf += 1;
|
||||
cnt = 0;
|
||||
ob = 0;
|
||||
}
|
||||
c = ((in_buf[0]+in_buf[1]*2+in_buf[2])&0x200)>>(2+cnt);
|
||||
ob = ob | c;
|
||||
cnt++;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
if (cnt > 0) {
|
||||
out_buf[0] = ob;
|
||||
out_buf += 1;
|
||||
}
|
||||
} break;
|
||||
/* big endian version, when the encoding is not endianess independant */
|
||||
case B_RGB32_BIG:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[3] = in_buf[0];
|
||||
out_buf[2] = in_buf[1];
|
||||
out_buf[1] = in_buf[2];
|
||||
out_buf += 4;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGBA32_BIG:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[3] = in_buf[0];
|
||||
out_buf[2] = in_buf[1];
|
||||
out_buf[1] = in_buf[2];
|
||||
out_buf[0] = in_buf[3];
|
||||
out_buf += 4;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB24_BIG:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[2] = in_buf[0];
|
||||
out_buf[1] = in_buf[1];
|
||||
out_buf[0] = in_buf[2];
|
||||
out_buf += 3;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<3)&0x7e0)|((in_buf[2]<<8)&0xf800);
|
||||
out_buf[0] = val>>8;
|
||||
out_buf[1] = val;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00)|0x8000;
|
||||
out_buf[0] = val>>8;
|
||||
out_buf[1] = val;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_RGBA15_BIG:
|
||||
while (num_bytes > 3) {
|
||||
uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
|
||||
if (in_buf[3] > 127) {
|
||||
val = val | 0x8000;
|
||||
}
|
||||
out_buf[0] = val>>8;
|
||||
out_buf[1] = val;
|
||||
out_buf += 2;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMY24:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[0] = 255-in_buf[2];
|
||||
out_buf[1] = 255-in_buf[1];
|
||||
out_buf[2] = 255-in_buf[0];
|
||||
out_buf += 3;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMY32:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[0] = 255-in_buf[2];
|
||||
out_buf[1] = 255-in_buf[1];
|
||||
out_buf[2] = 255-in_buf[0];
|
||||
out_buf += 4;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMYA32:
|
||||
while (num_bytes > 3) {
|
||||
out_buf[0] = 255-in_buf[2];
|
||||
out_buf[1] = 255-in_buf[1];
|
||||
out_buf[2] = 255-in_buf[0];
|
||||
out_buf[3] = in_buf[3];
|
||||
out_buf += 4;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
case B_CMYK32:
|
||||
while (num_bytes > 3) { /* We do direct gray removal */
|
||||
int c = 255-in_buf[2];
|
||||
int m = 255-in_buf[1];
|
||||
int y = 255-in_buf[0];
|
||||
int k = (c>m)?((y>c)?y:c):((y>m)?y:m);
|
||||
out_buf[0] = c-k;
|
||||
out_buf[1] = m-k;
|
||||
out_buf[2] = y-k;
|
||||
out_buf[3] = k;
|
||||
out_buf += 4;
|
||||
in_buf += 4;
|
||||
num_bytes -= 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return out_buf-in_out;
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG_DATA
|
||||
static void
|
||||
print_data(
|
||||
unsigned char * ptr,
|
||||
int n)
|
||||
{
|
||||
while (n-- > 0) {
|
||||
printf("%02x ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
status_t
|
||||
convert_space(
|
||||
color_space in_space,
|
||||
color_space out_space,
|
||||
unsigned char * in_data,
|
||||
int rowbytes,
|
||||
unsigned char * out_data)
|
||||
{
|
||||
ASSERT(in_data != out_data);
|
||||
|
||||
/* Instead of coding each transformation separately, which would create */
|
||||
/* a very large number of conversion functions, we write one function to */
|
||||
/* convert to RGBA32, and another function to convert from RGBA32, and */
|
||||
/* put them together to get a manageable program, at a slight expense in */
|
||||
/* conversion speed. */
|
||||
|
||||
int n;
|
||||
#if DEBUG_DATA
|
||||
printf("convert_space(%x, %x, %x)\n", in_space, out_space, rowbytes);
|
||||
printf("raw data: ");
|
||||
print_data(in_data, rowbytes);
|
||||
#endif
|
||||
/* If we convert from a format to itself, well... */
|
||||
if (in_space == out_space) {
|
||||
memcpy(out_data, in_data, rowbytes);
|
||||
return B_OK;
|
||||
}
|
||||
/* When the input format is RGBA32, we don't need the first conversion. */
|
||||
if (in_space == B_RGBA32) {
|
||||
n = collapse_data(in_data, rowbytes, out_space, out_data);
|
||||
#if DEBUG_DATA
|
||||
printf("collapsed data: ");
|
||||
print_data(out_data, n);
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
/* When the output format is RGBA32, we don't need any second conversion. */
|
||||
if (out_space == B_RGB32 || out_space == B_RGBA32) {
|
||||
n = expand_data(in_space, in_data, rowbytes, out_data);
|
||||
#if DEBUG_DATA
|
||||
printf("expanded data: ");
|
||||
print_data(out_data, n);
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
/* Figure out byte expansion rate -- usually isn't more than 4 */
|
||||
int mul = 4;
|
||||
if (in_space == B_GRAY1) {
|
||||
mul = 32;
|
||||
}
|
||||
unsigned char * buf = (unsigned char *)malloc(rowbytes*mul);
|
||||
if (buf == NULL) {
|
||||
/* oops! */
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
n = expand_data(in_space, in_data, rowbytes, buf);
|
||||
#if DEBUG_DATA
|
||||
printf("expanded data: ");
|
||||
print_data(out_data, n);
|
||||
#endif
|
||||
n = collapse_data(buf, n, out_space, out_data);
|
||||
#if DEBUG_DATA
|
||||
printf("collapsed data: ");
|
||||
print_data(out_data, n);
|
||||
#endif
|
||||
free(buf);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Figure out what the rowbytes is for a given width in a given color space. */
|
||||
/* Rowbytes is bytes per pixel times width, rounded up to nearest multiple of 4. */
|
||||
int
|
||||
calc_rowbytes(
|
||||
color_space space,
|
||||
int width)
|
||||
{
|
||||
int v = width*4;
|
||||
switch (space) {
|
||||
default:
|
||||
/* 4 is fine */
|
||||
break;
|
||||
case B_RGB24:
|
||||
case B_CMY24:
|
||||
case B_RGB24_BIG:
|
||||
v = width*3;
|
||||
break;
|
||||
case B_RGB15:
|
||||
case B_RGBA15:
|
||||
case B_RGB16:
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB16_BIG:
|
||||
v = width*2;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
case B_GRAY8:
|
||||
v = width;
|
||||
break;
|
||||
case B_GRAY1:
|
||||
v = (width+7)/8; /* whole bytes only, please */
|
||||
break;
|
||||
}
|
||||
v = (v+3)&~3;
|
||||
return v;
|
||||
}
|
32
src/add-ons/translators/ppmtranslator/colorspace.h
Normal file
32
src/add-ons/translators/ppmtranslator/colorspace.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* colorspace.h */
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#if !defined(COLORSPACE_H)
|
||||
#define COLORSPACE_H
|
||||
|
||||
|
||||
/* This is the main conversion function; it converts data in in_data */
|
||||
/* with rowbytes amount of pixel data into some other color space in */
|
||||
/* out_data, with enough memory assumed to be in out_data for the */
|
||||
/* converted data. */
|
||||
status_t convert_space(color_space in_space, color_space out_space,
|
||||
unsigned char * in_data, int rowbytes, unsigned char * out_data);
|
||||
|
||||
/* This function expands rowbytes amount of data from in_data into */
|
||||
/* RGBA32 data in out_buf, which must be big enough. */
|
||||
int expand_data(color_space from_space, unsigned char * in_data,
|
||||
int rowbytes, unsigned char * out_buf);
|
||||
|
||||
/* This function converts num_bytes bytes of RGBA32 data into some new */
|
||||
/* color space in out_buf, where out_buf must be big enough. */
|
||||
int collapse_data(unsigned char * in_buf, int num_bytes,
|
||||
color_space out_space, unsigned char * out_buf);
|
||||
|
||||
/* Given a specific number of pixels in width in the color space space */
|
||||
/* this function calculates what the row_bytes should be. */
|
||||
int calc_rowbytes(color_space space, int width);
|
||||
|
||||
#endif /* COLORSPACE_H */
|
Loading…
Reference in New Issue
Block a user