/***************************************************************************
PBMTOMDA: Convert portable bitmap to Microdesign area
Copyright (C) 1999,2004 John Elliott <jce@seasip.demon.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "pbm.h"
#include "mallocvar.h"
/* I'm being somewhat conservative in the PBM -> MDA translation. I output
* only the MD2 format and don't allow RLE over the ends of lines.
*/
typedef unsigned char mdbyte;
static FILE *infile;
static mdbyte header[128];
static int bInvert = 0;
static int bScale = 0;
/* Encode 8 pixels as a byte */
static mdbyte
encode(bit ** const bits, int const row, int const col)
{
int n;
int mask;
mdbyte b;
mask = 0x80; /* initial value */
b = 0; /* initial value */
for (n = 0; n < 8; n++) {
if (bits[row][col+n] == PBM_BLACK) b |= mask;
mask = mask >> 1;
}
return b;
}
/* Translate a pbm to MD2 format, one row at a time */
static void
do_translation(bit ** const bits,
int const nOutCols,
int const nOutRows,
int const nInRows)
{
int row;
mdbyte *mdrow; /* malloc'ed */
int const step = bScale ? 2 : 1;
MALLOCARRAY(mdrow, nOutCols);
if (mdrow == NULL)
pm_error("Not enough memory for conversion.");
for (row = 0; row < nOutRows; row+=step)
{
int col;
int x1;
/* Encode image into non-compressed bitmap */
for (col = 0; col < nOutCols; ++col) {
mdbyte b;
if (row < nInRows)
b = encode(bits, row, col*8);
else
b = 0xff; /* All black */
mdrow[col] = bInvert ? b : ~b;
}
/* Encoded. Now RLE it */
for (col = 0; col < nOutCols; )
{
mdbyte const b = mdrow[col];
if (b != 0xFF && b != 0) /* Normal byte */
{
putchar(b);
++col;
}
else /* RLE a run of 0s or 0xFFs */
{
for (x1 = col; x1 < nOutCols; x1++)
{
if (mdrow[x1] != b) break;
if (x1 - col > 256) break;
}
x1 -= col; /* x1 = no. of repeats */
if (x1 == 256) x1 = 0;
putchar(b);
putchar(x1);
col += x1;
}
}
}
free(mdrow);
}
static void usage(char *s)
{
printf("pbmtomda v1.01, Copyright (C) 1999,2004 John Elliott <jce@seasip.demon.co.uk>\n"
"This program is redistributable under the terms of the GNU General Public\n"
"License, version 2 or later.\n\n"
"Usage: %s [ -d ] [ -i ] [ -- ] [ infile ]\n\n"
"-d: Halve height (to compensate for the PCW aspect ratio)\n"
"-i: Invert colors\n"
"--: No more options (use if filename begins with a dash)\n",
s);
exit(0);
}
int main(int argc, char **argv)
{
int nOutRowsUnrounded; /* Before rounding up to multiple of 4 */
int nOutCols, nOutRows;
int nInCols, nInRows;
bit **bits;
int rc;
int n, optstop = 0;
char *fname = NULL;
pbm_init(&argc, argv);
/* Output v2-format MDA images. Simulate MDA header...
* 2004-01-11: Hmm. Apparently some (but not all) MDA-reading
* programs insist on the program identifier being exactly
* 'MicroDesignPCW'. The spec does not make this clear. */
strcpy((char*) header, ".MDAMicroDesignPCWv1.00\r\npbm2mda\r\n");
for (n = 1; n < argc; n++)
{
if (argv[n][0] == '-' && !optstop)
{
if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1;
if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1;
if (argv[n][1] == 'h' || argv[n][1] == 'H') usage(argv[0]);
if (argv[n][1] == '-' && argv[n][2] == 0 && !fname) /* "--" */
{
optstop = 1;
}
if (argv[n][1] == '-' && (argv[n][2] == 'h' || argv[n][2] == 'H')) usage(argv[0]);
}
else if (argv[n][0] && !fname) /* Filename */
{
fname = argv[n];
}
}
if (fname) infile = pm_openr(fname);
else infile = stdin;
bits = pbm_readpbm(infile, &nInCols, &nInRows);
nOutRowsUnrounded = bScale ? nInRows/2 : nInRows;
overflow_add(nOutRowsUnrounded, 3);
nOutRows = ((nOutRowsUnrounded + 3) / 4) * 4;
/* MDA wants rows a multiple of 4 */
nOutCols = nInCols / 8;
rc = fwrite(header, 1, 128, stdout);
if (rc < 128)
pm_error("Unable to write header to output file. errno=%d (%s)",
errno, strerror(errno));
pm_writelittleshort(stdout, nOutRows);
pm_writelittleshort(stdout, nOutCols);
do_translation(bits, nOutCols, nOutRows, nInRows);
pm_close(infile);
fflush(stdout);
pbm_freearray(bits, nInRows);
return 0;
}