Skip to content

Commit

Permalink
The viewer applications can now open MacPaint images directly.
Browse files Browse the repository at this point in the history
  • Loading branch information
wiesmann committed Mar 1, 2024
1 parent 0d274c6 commit 7afa34a
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 19 deletions.
45 changes: 31 additions & 14 deletions QuickDrawViewer/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,30 @@
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleTypeName</key>
<string>Apple QuicDraw pictures</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.pict</string>
</array>
<key>CFBundleTypeName</key>
<string>Apple QuicDraw pictures</string>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>CFBundleTypeName</key>
<string>PDF</string>
<key>LSItemContentTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleTypeName</key>
<string>Apple MacPaint pictures</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.macpaint-image</string>
</array>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string></string>
<string>public.image</string>
</array>
<key>UTTypeDescription</key>
<string>QuickTime Picture</string>
Expand All @@ -57,7 +57,7 @@
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
<string>public.image</string>
</array>
<key>UTTypeDescription</key>
<string>Quickdraw Picture</string>
Expand All @@ -71,6 +71,23 @@
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.image</string>
</array>
<key>UTTypeDescription</key>
<string>MacPaint Picture</string>
<key>UTTypeIdentifier</key>
<string>com.apple.macpaint-image</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>pntg</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
33 changes: 30 additions & 3 deletions QuickDrawViewer/MacPaint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,45 @@

import Foundation

// MacPaint images are fixed size (720 × 576) PackBit compressed bitmaps.
/// MacPaint images are fixed size (720 × 576) PackBit compressed bitmaps.
class MacPaintImage : PixMapMetadata {

func load(data : Data) throws {
self.bitmap = try DecompressPackBit(data: Array(data), unpackedSize: 720 * 72);
// For some reason, MacPaint pictures have black and white inverted.
for i in 0..<self.bitmap.count {
self.bitmap[i] = self.bitmap[i] ^ 0xff;
}
}

/// Convert the MacPaint images into an opcode.
/// This could be a QuickTime opcode that embeds the MacPaint data, but
/// this is very involved, instead we just build a `BitRectOpcode`.
func makeOpcode() -> some OpCode {
let bitRect = BitRectOpcode(isPacked: true);
bitRect.bitmapInfo.rowBytes = self.rowBytes;
let frame = QDRect(topLeft: .zero, dimension: self.dimensions);
bitRect.bitmapInfo.bounds = frame;
bitRect.bitmapInfo.srcRect = frame;
bitRect.bitmapInfo.dstRect = frame;
bitRect.bitmapInfo.data = bitmap;
return bitRect;
}

/// Convert a MacPaint images into a minimalistic picture.
/// This is enough for this program, but a valid quickdraw file would have some header operations.
func macPicture(filename: String?) -> QDPicture {
let frame = QDRect(topLeft: .zero, dimension: self.dimensions);
let picture = QDPicture(size: -1, frame: frame, filename: filename);
picture.opcodes.append(makeOpcode());
return picture;
}

let rowBytes: Int = 72; // 576 ÷ 8
var cmpSize: Int = 1;
var pixelSize: Int = 1;
let dimensions = QDDelta(dv: FixedPoint(720), dh: FixedPoint(576));
var clut: QDColorTable? = QDColorTable.whiteBlack;
var clut: QDColorTable? = QDColorTable.blackWhite;
var bitmap: [UInt8] = [];

}

2 changes: 2 additions & 0 deletions QuickDrawViewer/QuickTime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ func parseQuickTimeStream(reader: QuickDrawDataReader, quicktimePayload: inout Q

/// Parse a QuickTime image into a QuickDraw picture.
/// This will fail if the QuickTime image does not have an `idsc` (image description) atom.
/// Note that the resulting file is enough for this program, a valid QuickDraw file would require some
/// header operations.
/// - Parameter reader: reader pointing to the data.
/// - Throws: if data is corrupt / unreadable
/// - Returns: a _fake_ QuickDraw image with a single QuickTime opcode.
Expand Down
10 changes: 9 additions & 1 deletion QuickDrawViewer/UI/QuickDrawViewerDocument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ extension UTType {
static var quickTimeImage: UTType {
UTType(importedAs: "com.apple.quicktime-image")
}
static var macPaintImage : UTType {
UTType(importedAs: "com.apple.macpaint-image")
}
}

struct QuickDrawViewerDocument: FileDocument {
Expand Down Expand Up @@ -58,12 +61,17 @@ struct QuickDrawViewerDocument: FileDocument {
logger.log(level: .error, "Failed parsing quicktime: \(error)");
throw error;
}
case .macPaintImage:
let macPaint = MacPaintImage();
try macPaint.load(data: data.subdata(in: 512..<data.count));
picture = macPaint.macPicture(filename: configuration.file.filename);
default:
throw CocoaError(.fileReadUnknown);
}
}

static var readableContentTypes: [UTType] { [.quickDrawImage, .quickTimeImage ] };
static var readableContentTypes: [UTType] {
[.quickDrawImage, .quickTimeImage, .macPaintImage] };
// static var writableContentTypes: [UTType] { [.pdf] };

func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ I wanted to teach myself Swift programming, and needed something a bit more invo

This program is far from finished, but I decided to release it for the 40th anniversary of the original Macintosh computer: QuickDraw was the graphical language of the original Macintosh, and the format used to store and exchange images on the computer. Support for these files has been slowly decaying with newer versions of Mac OS X, and on my M1 PowerBook, Preview can only open a small subset of the files I have.

## Supported File types

This application basically handles QuickDraw image files, but also two related (but distinct) image formats:

* QuickTime images (`QTIF`)
* MacPaint images (`PNTG`)

These two formats are handled by converting them into QuickDraw at load time.
QuickTime images are supported so far as the underlying codec is supported.
MacPaint images are supported by virtue of being one of codecs that can be embedded inside QuickTime.

## Structure

This program has basically three parts:
Expand Down Expand Up @@ -36,7 +47,6 @@ It supports the following features.
* MacPaint
* Apple Video (`RPZA`), Apple Component Video (`YUV2`).
* Planar Video (`8BPS`).
* QuickTime images which use a supported codec (see above).

Some basic comment parsing is used to improve images, in particular:

Expand Down

0 comments on commit 7afa34a

Please sign in to comment.