mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-23 11:33:58 +00:00
8f61f84585
Much of what the "reformat" code does involves processing data that is 8, 16, or 32 bits. We want to use size-specific types from stdint.h (e.g. uint16_t) rather than "unsigned short". This was a quick pass to replace the various "unsigned" declarations. More can be done here and elsewhere.
184 lines
5.3 KiB
C++
184 lines
5.3 KiB
C++
/*
|
|
* CiderPress
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
* See the file LICENSE for distribution terms.
|
|
*/
|
|
/*
|
|
* Convert MacPaint 'PNTG' images.
|
|
*/
|
|
#include "StdAfx.h"
|
|
#include "MacPaint.h"
|
|
|
|
/*
|
|
* The files are always 576x720 monochrome.
|
|
*
|
|
* This format often starts with a MacBinary header, especially for files
|
|
* posted to BBSs. The FileType should be 'PNTG', and the CreatorType will
|
|
* usually be 'MPNT'.
|
|
*
|
|
* Following the 128-byte header (or at the very start of the data fork for
|
|
* a file on the Mac) is:
|
|
*
|
|
* +000-003: 4-byte big-endian version number (0 or 2)
|
|
* +004-307: pattern data (38 patterns * 8 bytes), not needed to decode image
|
|
* +308-511: 240 bytes of zeroes, used for padding
|
|
* +512-nnn: PackBits-encoded scan lines (72 bytes of output each)
|
|
*
|
|
* The files seem to be stored in 512-byte chunks, but it's probably unwise to
|
|
* expect anything other than some extra bytes at the end.
|
|
*
|
|
* The bits are in the same order as Windows BMP, but white/black are reversed
|
|
* (i.e. a '1' bit indicates a black pixel). This can be accommodated by
|
|
* changing the palette colors or by inverting the bits.
|
|
*
|
|
* Corrupted MacPaint files seem to be popular. Handling corruption
|
|
* gracefully is important.
|
|
*/
|
|
|
|
/*
|
|
* If the file ends in ".mac", we accept it if it has a MacBinary header or
|
|
* if it begins with 00000002 and exceeds the minimum size required.
|
|
*/
|
|
void
|
|
ReformatMacPaint::Examine(ReformatHolder* pHolder)
|
|
{
|
|
ReformatHolder::ReformatApplies applies = ReformatHolder::kApplicNot;
|
|
const uint8_t* ptr = pHolder->GetSourceBuf(ReformatHolder::kPartData);
|
|
long fileLen = pHolder->GetSourceLen(ReformatHolder::kPartData);
|
|
const char* nameExt = pHolder->GetNameExt();
|
|
long version;
|
|
|
|
if (fileLen < kMinSize) {
|
|
LOGI(" MP: not long enough to be MacPaint (%d vs min %d)",
|
|
fileLen, kMinSize);
|
|
goto done;
|
|
}
|
|
|
|
version = Get32BE(ptr);
|
|
if (stricmp(nameExt, ".mac") == 0 && version >= 0 && version <= 3) {
|
|
LOGI(" MP: found w/o MacBinary header");
|
|
applies = ReformatHolder::kApplicProbably;
|
|
goto done;
|
|
}
|
|
|
|
version = Get32BE(ptr + 128);
|
|
if (version >= 0 && version <= 3 &&
|
|
ptr[65] == 'P' && ptr[66] == 'N' && ptr[67] == 'T' && ptr[68] == 'G')
|
|
{
|
|
LOGI(" MP: found inside MacBinary header");
|
|
applies = ReformatHolder::kApplicProbably;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
pHolder->SetApplic(ReformatHolder::kReformatMacPaint, applies,
|
|
ReformatHolder::kApplicNot, ReformatHolder::kApplicNot);
|
|
}
|
|
|
|
/*
|
|
* Convert the image to a monochrome bitmap.
|
|
*/
|
|
int
|
|
ReformatMacPaint::Process(const ReformatHolder* pHolder,
|
|
ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part,
|
|
ReformatOutput* pOutput)
|
|
{
|
|
MyDIBitmap* pDib;
|
|
const uint8_t* srcBuf = pHolder->GetSourceBuf(part);
|
|
long srcLen = pHolder->GetSourceLen(part);
|
|
int retval = -1;
|
|
|
|
if (srcLen < kMinSize || srcLen > kMaxSize) {
|
|
LOGI(" MacPaint file is only %d bytes long", srcLen);
|
|
goto bail;
|
|
}
|
|
|
|
pDib = ConvertMacPaint(srcBuf, srcLen);
|
|
if (pDib == NULL)
|
|
goto bail;
|
|
|
|
SetResultBuffer(pOutput, pDib);
|
|
retval = 0;
|
|
|
|
bail:
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* Handle the actual conversion.
|
|
*
|
|
* 576 pixels per line == 72 bytes per line, which is a multiple of 4 bytes
|
|
* (required for windows BMP).
|
|
*/
|
|
MyDIBitmap*
|
|
ReformatMacPaint::ConvertMacPaint(const uint8_t* srcBuf, long length)
|
|
{
|
|
MyDIBitmap* pDib = NULL;
|
|
uint8_t* outBuf;
|
|
static const RGBQUAD colorConv[2] = {
|
|
/* blue, green, red, reserved */
|
|
{ 0x00, 0x00, 0x00 }, // black
|
|
{ 0xff, 0xff, 0xff }, // white
|
|
};
|
|
long version1, version2;
|
|
int offset;
|
|
|
|
version1 = Get32BE(srcBuf);
|
|
version2 = Get32BE(srcBuf+128);
|
|
if (version1 >= 0 && version1 <= 3) {
|
|
offset = 0;
|
|
} else if (version2 >= 0 && version2 <= 3 &&
|
|
srcBuf[65] == 'P' && srcBuf[66] == 'N' && srcBuf[67] == 'T' && srcBuf[68] == 'G')
|
|
{
|
|
offset = 128;
|
|
} else {
|
|
LOGI(" MP couldn't determine picture offset!");
|
|
goto bail;
|
|
}
|
|
|
|
pDib = new MyDIBitmap;
|
|
if (pDib == NULL)
|
|
goto bail;
|
|
|
|
srcBuf += offset;
|
|
srcBuf += kLeadingJunkCount;
|
|
length -= offset;
|
|
length -= kLeadingJunkCount;
|
|
LOGI("Adjusted len is %d", length);
|
|
|
|
outBuf = (uint8_t*) pDib->Create(kOutputWidth, kOutputHeight,
|
|
1, kNumColors);
|
|
if (outBuf == NULL) {
|
|
delete pDib;
|
|
pDib = NULL;
|
|
goto bail;
|
|
}
|
|
pDib->SetColorTable(colorConv);
|
|
|
|
uint8_t* outPtr;
|
|
int line;
|
|
|
|
/* top row goes at the bottom of the buffer */
|
|
outPtr = outBuf + (kOutputHeight-1) * (kOutputWidth / 8);
|
|
|
|
/*
|
|
* Loop through all lines. When we've output 72 bytes, stop immediately
|
|
* even if we're in a run. Chances are good that the run was corrupted.
|
|
*/
|
|
for (line = 0; line < kOutputHeight; line++) {
|
|
UnPackBits(&srcBuf, &length, &outPtr, 72, 0xff);
|
|
|
|
/* back up to start of next line */
|
|
outPtr -= 2*(kOutputWidth / 8);
|
|
|
|
if (length < 0)
|
|
break;
|
|
}
|
|
if (length != 0) {
|
|
LOGI(" MP found %d unused bytes at end", length);
|
|
}
|
|
|
|
bail:
|
|
return pDib;
|
|
}
|