This is macpaintConverter.m in view mode; [Download] [Up]
/***********************************************************************\ Converter class for Convert MacPaint which converts MacPaint files to PostScript files. Copyright (C) 1993 David John Burrowes 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. The author, David John Burrowes, can be reached at: davidjohn@kira.net.netcom.com David John Burrowes 1926 Ivy #10 San Mateo, CA 94403-1367 \***********************************************************************/ #import "macpaintConverter.h" #import "File.h" #import "PSFile.h" #import <strings.h> #import <stdio.h> #import <stdlib.h> // for malloc and free #import <sys/param.h> // for maxpathlen #include <time.h> @implementation macpaintConverter ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Method: UnpackFrom:To: // Parameters: // A buffer to unpack data from // A buffer to put data into // Returns: // self // Stores: n/a // Description: // This takes a buffer in memory, and assumes it contains a macpaint image // in packbits form. This then takes that packed data, and unpacks it into // the To: buffer. Note that it inverts all the image data as it goes, because // the mac uses 1 for white, and PS 1 for black (or the reverse or something). // Bugs: // none, of course. Actually, there's room for tons. The most obvious thing is that // this does nothing to assure the 'goodness' of the data being passed to it. // it just blindly decompresses until it has unpacked 51840 bytes (the size of // an unpacked mac paint image) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - UnpackFrom: (ByteString) sourceData To: (ByteString) destData { Byte flag; Byte dataByte; Integer index; // counter Integer sourceIndex = 0, destIndex = 0; // counters Integer BytesDone = 0; // Number of bytes put into unpacked buffer Integer nextPeak = 0; while (BytesDone < 51840) { // // Let's not call our manager EVERY byte!. // if (BytesDone > nextPeak) { [myManager SetPercentageDone: (BytesDone / 518.4) * Weighting]; nextPeak += 5184; } // // Read in a byte, which tells us about the following data... // if < 128, we will copy bytes literally, if > 128, will copy the next // byte a numnber of times. // flag = sourceData[sourceIndex]; sourceIndex++; if (flag < 128) { // // copy one more than the number of Bytes literally. // flag++; for (index = 0; index < flag; index++) { // invert the data destData[destIndex] = ~sourceData[sourceIndex]; sourceIndex++; destIndex++; } BytesDone += flag; } else { // // copy next Byte 257-flag times // dataByte = ~sourceData[sourceIndex]; sourceIndex++; for (index = 0; index < 257 -flag; index ++) { destData[destIndex] = dataByte; destIndex++; } BytesDone += 257-flag; } } return self; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -(int) PackDataFrom: (ByteString) source To: (ByteString) dest { Boolean runs = NO; Integer numTraversedBytes; Integer startByte = 0; Integer lineLength = 72; Integer index = 0; Integer destIndex = 0; Integer ctr; Integer accumulated; Integer runCount; accumulated = 0; do { startByte = index; /* first Byte is always assumed to be OK. Safe assumption. Either we are starting (Byte 0 should always be good), or we just dumped some data, at which index points to the first Byte that did not match that pattern, and so is good to use for starting with the next */ index++; accumulated++; // Try to accumulate a run while ((source[index-1] == source[index]) && ((index-startByte) < 128) && (accumulated < lineLength)) { index++; accumulated++; } if ((index-startByte) > 2) runs = YES; else { runCount = 1; // not enough to justify a run, so carry on. as a litteral sequence of Bytes while ((source[index-1] != source[index]) && ((index-startByte) < 128) && (accumulated < lineLength)) { index++; accumulated++; } // // @@ bug: in the above, we should be checking to allow for accumulating // @@ runs with length 2, since they are too short to be treated as runs. // @@ the present code works, but just isn't ideal. // if (accumulated < lineLength) // We ran into a match, not the end { index--; // Thus, back up over 1 of the 2 Bytes. accumulated--; } runs = NO; } numTraversedBytes = index-startByte; if (runs == YES) { dest[destIndex] = 257-numTraversedBytes; destIndex++; dest[destIndex] = source[startByte]; destIndex++; } else { dest[destIndex] = numTraversedBytes - 1; destIndex++; for (ctr = startByte; ctr < startByte+numTraversedBytes; ctr++) { dest[destIndex] = source[ctr]; destIndex++; } } } while (accumulated < lineLength); return destIndex; /* return a number that is the num of bytes in the destination */ } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Routine: SetPacking:AndPath: // Parameters: // a flag indicating if we should pack data that we write out // a string indicating where various needed files are to be found // Returns: // self // Description: // This sets up two instance variables, using values we have been provided: // - whether output data should be packed or not (yes or no) // - Where to find the ps files this object needs to do it's conversion. This should // be a legal path name, or null (indicating the current working directory). // Bugs: // this does NOT check for the validity of the path. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SetPacking: (Boolean) shouldPack AndPath: (CString) thepath { if (pathToIncludes != NullCString) FreeCString(pathToIncludes); pathToIncludes= NewCString(strlen(thepath)); strcpy(pathToIncludes, thepath); packing = shouldPack; return self; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Method: free // Parameters: none // Returns: self // Description: // This frees the current object, which entails merely disposing of the string // in the instance variables ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - free { FreeCString(pathToIncludes); return [super free]; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Method: convert:To: // Parameters: a source object and a destination file object (a PSFile object) // Returns: self // Stores: n/a // Description: // This method takes the contents of the source file (a MacPaint file, we assume) // and changes the contents into an eps file, which is written to the destination file. // This relies upon the parameters passed to the init method to determine whether to // pack the data // This depends on a set of files to provide the PS code for the resulting eps file. // Note: When it comes to reporting the percent done, we ignore all the preliminary // file reading and writing, and only report on the precentages through the unpacking // and packing. The Weight value is used to aid in reporting accurate results. When // we are not re-packing the data, we set weight to 1. Otherwise, we set it to 1. // One might also ask: Why bother to unpack data we're about to re-pack anyway. // the answer is that we need to invert it anyway. True, we could invert it wihtout // going through the effort of unpacking it, but hey, it's easier this way... =) =( // Bugs: // Inadequate error responses are provided! // Some others I don't know of surely exist. This object 'grew' too much. not enough // planning ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Convert: sourceFile To: destFile { PositiveInteger newPackedSize, imagePackedSize; Integer thetime; Instance headerInfo, prologueCode; CString comment = NewCString(270); CString tempPath = NewCString(MAXPATHLEN); ByteString unpackedImage, packedImage, newPackedImage; Integer scanlines; Integer packedLoc; // // Locate 'include' files of PS code we need // open them, and if all goes well, proceed. // sprintf(tempPath, "%s/%s", pathToIncludes, "PSstuff/EPS_header"); headerInfo = [[PSFile alloc] initAndUse: tempPath]; if (packing == YES) { sprintf(tempPath, "%s/%s", pathToIncludes, "PSstuff/PackedCode"); prologueCode = [[PSFile alloc] initAndUse: tempPath]; } else { sprintf(tempPath, "%s/%s", pathToIncludes, "PSstuff/UnpackedCode"); prologueCode = [[PSFile alloc] initAndUse: tempPath]; } [headerInfo OpenFor: FILE_READ]; [prologueCode OpenFor: FILE_READ]; if (([headerInfo GetErrorCode] != 0) || ([prologueCode GetErrorCode] != 0)) [self StoreErrorCode: ERR_BADINCLUDES AndText: "Could not load a necessary included PS file"]; else { // // Write the header and prolog of the destinatin file. // [destFile AppendFrom: headerInfo]; thetime = time(NULL); sprintf(comment, "CreationDate: (%s", (char*) ctime(&thetime)); comment[strlen(comment)-1] = EndOfCString; // ctime puts a \n on which we don't wan strcat(comment, ")"); [destFile WriteDSCComment: comment]; sprintf(comment, "Title: (%s)", [sourceFile GetFilename]); [destFile WriteDSCComment: comment]; [destFile WriteDSCComment: "EndComments"]; [destFile WritePSLine: "\nsave\n"]; [destFile WriteDSCComment: "BeginProlog"]; // [destFile AppendFrom: prologueCode]; [destFile WriteDSCComment: "EndProlog"]; [destFile WritePSLine: "\nshowMPimage"]; // // Write the hex ddata of the image to the output. // imagePackedSize = [sourceFile FileSize] - 512; packedImage = NewByteString(imagePackedSize); unpackedImage = NewByteString(52000); // allocate a listtle extra (over 51840) newPackedImage = NewByteString(52000); // allocate as much as we'll need [sourceFile MoveTo: 512]; [sourceFile Read: imagePackedSize BytesInto: packedImage]; if (packing == YES) Weighting = 0.5; else Weighting = 1; Weighting = Weighting * .75; [self UnpackFrom: packedImage To: unpackedImage]; if (packing == YES) { packedLoc = 0; for (scanlines = 0; scanlines < 720; scanlines++) { // // Let's not call our manager EVERY scanline. // if ((scanlines % 72) == 0) [myManager SetPercentageDone: 40+ (((scanlines / 7.2)*.6))]; newPackedSize = [self PackDataFrom: &(unpackedImage[scanlines*72]) To: newPackedImage]; [destFile Write: newPackedSize BytesOfHexDataFrom: newPackedImage]; } // Add 80> to mark the end of file for an ASCIIHexDecode & Runlength filter [destFile WritePSLine: "80>"]; } else { [myManager SetPercentageDone: 75]; for (scanlines = 0; scanlines < 720; scanlines++) // total 51840 bytes [destFile Write: 72 BytesOfHexDataFrom: &(unpackedImage[scanlines*72])]; [destFile WritePSLine: ">"]; // Add > to mark EOF for ASCIIHexDecode filter } // // Finish off the ps code. // 93.01.31 djb Moved EOF after the restore. Somehow I had it showpage, eof, restore [destFile WritePSLine: "showpage"]; [destFile WritePSLine: "restore"]; [destFile WriteDSCComment: "EOF"]; [self StoreErrorCode: ERR_OK AndText: "Simplisitically assumed all went well"]; FreeByteString(unpackedImage); FreeByteString(newPackedImage); FreeByteString(packedImage); } [prologueCode Close]; [headerInfo Close]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.