/* libpbm1.c - pbm utility library part 1
**
** Copyright (C) 1988 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
/* See pmfileio.c for the complicated explanation of this 32/64 bit file
offset stuff.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGE_FILES
#include <stdio.h>
#include "netpbm/pm_c_util.h"
#include "netpbm/mallocvar.h"
#include "netpbm/shhopt.h"
#include "pbm.h"
bit *
pbm_allocrow(unsigned int const cols) {
bit * bitrow;
MALLOCARRAY(bitrow, cols);
if (bitrow == NULL)
pm_error("Unable to allocate space for a %u-column bit row", cols);
return bitrow;
}
void
pbm_init(int * const argcP,
char ** const argv) {
pm_proginit(argcP, (const char **)argv);
}
void
pbm_nextimage(FILE *file, int * const eofP) {
pm_nextimage(file, eofP);
}
void
pbm_check(FILE * const fileP,
enum pm_check_type const checkType,
int const format,
int const cols,
int const rows,
enum pm_check_code * const retvalP) {
if (rows < 0)
pm_error("Invalid number of rows passed to pbm_check(): %d", rows);
if (cols < 0)
pm_error("Invalid number of columns passed to pbm_check(): %d", cols);
if (checkType != PM_CHECK_BASIC) {
if (retvalP)
*retvalP = PM_CHECK_UNKNOWN_TYPE;
} else if (format != RPBM_FORMAT) {
if (retvalP)
*retvalP = PM_CHECK_UNCHECKABLE;
} else {
pm_filepos const bytesPerRow = (cols+7)/8;
pm_filepos const needRasterSize = rows * bytesPerRow;
pm_check(fileP, checkType, needRasterSize, retvalP);
}
}
static unsigned int
bitpop8(unsigned char const x) {
/*----------------------------------------------------------------------------
Return the number of 1 bits in 'x'
-----------------------------------------------------------------------------*/
static unsigned int const p[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 };
return p[x];
}
static int
bitpop(const unsigned char * const packedRow,
unsigned int const cols,
unsigned int const offset) {
/*----------------------------------------------------------------------------
Return the number of 1 bits in 'packedRow', ignoring 0 to 7 bits
at the row start (= on the left edge), indicated by offset.
-----------------------------------------------------------------------------*/
unsigned int const fullLength = cols + offset;
unsigned int sum;
if (fullLength <= 8) {
/* All bits are in a single byte */
sum = bitpop8((packedRow[0] << offset ) & (0xff << (8 - cols)));
} else {
unsigned int const colByteCnt = pbm_packed_bytes(fullLength);
unsigned int const fullByteCnt = fullLength/8;
unsigned int i;
/* First byte, whether it is full or not */
sum = bitpop8(packedRow[0] << offset );
/* Second byte to last full byte */
for (i = 1; i < fullByteCnt; ++i)
sum += bitpop8(packedRow[i]);
/* Partial byte at the right end */
if (colByteCnt > fullByteCnt)
sum += bitpop8(packedRow[i] >> (8 - fullLength%8));
}
return sum;
}
bit
pbm_backgroundbitrow(unsigned const char * const packedBits,
unsigned int const cols,
unsigned int const offset) {
/*----------------------------------------------------------------------------
PBM version of pnm_backgroundxelrow() with additional offset parameter.
When offset == 0, produces the same return value as does
pnm_backgroundxelrow(promoted_bitrow, cols, ...)
-----------------------------------------------------------------------------*/
const unsigned char * const row = &packedBits[offset/8];
unsigned int const rs = offset % 8;
unsigned int const last = pbm_packed_bytes(cols + rs) - 1;
unsigned int retval;
bool const firstbit = (row[0] >> (7-rs)) & 0x01;
bool const lastbit = (row[last] >> (7- (cols+rs-1)%8)) & 0x01;
if (firstbit == lastbit)
retval = firstbit;
else {
if (bitpop(row, cols, rs) >= cols/2)
retval = PBM_BLACK;
else
retval = PBM_WHITE;
}
return retval;
}