|
| 1 | +#!/usr/bin/xcrun swift |
| 2 | + |
| 3 | +import Cocoa |
| 4 | + |
| 5 | +extension NSDirectoryEnumerator : SequenceType, GeneratorType |
| 6 | +{ |
| 7 | + public typealias GeneratorType = NSDirectoryEnumerator |
| 8 | + public func generate() -> GeneratorType { return self } |
| 9 | + |
| 10 | + public typealias Element = NSString |
| 11 | + public func next() -> Element? { return nextObject() as? Element } |
| 12 | +} |
| 13 | + |
| 14 | +extension NSOutputStream : OutputStreamType |
| 15 | +{ |
| 16 | + public func write(string: String) |
| 17 | + { |
| 18 | + string.withCString() |
| 19 | + { [weak self] (s: UnsafePointer<Int8>) -> () in |
| 20 | + let bytes = UnsafePointer<UInt8>(s) |
| 21 | + let len = Int(strlen(s)) |
| 22 | + self!.write(bytes, maxLength: len) |
| 23 | + } |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +struct TileFile |
| 28 | +{ |
| 29 | + let path: String |
| 30 | + let image: NSBitmapImageRep |
| 31 | +} |
| 32 | + |
| 33 | +var err:NSError? |
| 34 | +let dir = String.fromCString(C_ARGV[1])! |
| 35 | +let out_tiff = String.fromCString(C_ARGV[2])! |
| 36 | +let out_json = String.fromCString(C_ARGV[3])! |
| 37 | +let fm = NSFileManager.defaultManager() |
| 38 | +let png_re = NSRegularExpression(pattern: "^(.*)\\.png$", options: nil, error: &err) |
| 39 | +var images:Dictionary<String, TileFile> = [:] |
| 40 | +for filename in fm.enumeratorAtPath(dir) |
| 41 | +{ |
| 42 | + let string_range = NSRange(location: 0, length: filename.length) |
| 43 | + let match:NSTextCheckingResult? = png_re.firstMatchInString(filename, options: nil, range: string_range) |
| 44 | + if let m = match |
| 45 | + { |
| 46 | + let path = dir.stringByAppendingPathComponent(filename) |
| 47 | + images[filename.substringWithRange(m.rangeAtIndex(1))] = TileFile(path: path, image: NSBitmapImageRep(data: NSData(contentsOfFile: path))) |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +var tile_size: (Int, Int)? |
| 52 | +for (k, v) in images |
| 53 | +{ |
| 54 | + if let (w, h) = tile_size |
| 55 | + { |
| 56 | + if w != v.image.pixelsWide || h != v.image.pixelsHigh |
| 57 | + { |
| 58 | + println("Image \(k) is wrong size(\(v.image.pixelsWide) × \(v.image.pixelsHigh)); discarding.") |
| 59 | + images.removeValueForKey(k) |
| 60 | + } |
| 61 | + } |
| 62 | + else |
| 63 | + { |
| 64 | + tile_size = (v.image.pixelsWide, v.image.pixelsHigh) |
| 65 | + } |
| 66 | + // discard DPI |
| 67 | + v.image.size = NSSize(width: v.image.pixelsWide, height: v.image.pixelsHigh) |
| 68 | +} |
| 69 | +assert(tile_size != nil) |
| 70 | + |
| 71 | +let PAD = 2 |
| 72 | + |
| 73 | +let s = sqrt(Double(images.count)) |
| 74 | +let (tile_width, tile_height) = tile_size! |
| 75 | +var tiles_across = Int(ceil(s)) |
| 76 | +var tiles_down = Int(floor(s)) |
| 77 | +var total_tiles = tiles_across * tiles_down |
| 78 | +var pixel_width = tiles_across * (tile_width + PAD) + PAD |
| 79 | +var pixel_height = tiles_down * (tile_height + PAD) + PAD |
| 80 | +while total_tiles < images.count || pixel_width < pixel_height |
| 81 | +{ |
| 82 | + if total_tiles < images.count |
| 83 | + { |
| 84 | + tiles_across += 1 |
| 85 | + } |
| 86 | + else if pixel_width < pixel_height |
| 87 | + { |
| 88 | + tiles_across += 1 |
| 89 | + tiles_down -= 1 |
| 90 | + } |
| 91 | + total_tiles = tiles_across * tiles_down |
| 92 | + pixel_width = tiles_across * (tile_width + PAD) + PAD |
| 93 | + pixel_height = tiles_down * (tile_height + PAD) + PAD |
| 94 | +} |
| 95 | +println("Using \(tiles_across) × \(tiles_down); \(total_tiles) total (\(images.count) filled); \(pixel_width)px × \(pixel_height)px") |
| 96 | + |
| 97 | +let large_image_rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: pixel_width, pixelsHigh: pixel_height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: pixel_width * 4, bitsPerPixel: 32) |
| 98 | +NSGraphicsContext.setCurrentContext(NSGraphicsContext(bitmapImageRep: large_image_rep)) |
| 99 | +var x = 0, y = 0 |
| 100 | +var first = true |
| 101 | +var f = NSOutputStream(toFileAtPath: out_json, append: false) |
| 102 | +f.open() |
| 103 | +println("{", &f) |
| 104 | +for (k, v) in images |
| 105 | +{ |
| 106 | + let x_px = x * (tile_width + PAD) + PAD |
| 107 | + let y_px = y * (tile_height + PAD) + PAD |
| 108 | + v.image.drawAtPoint(NSPoint(x: x_px, y: y_px)) |
| 109 | + if first |
| 110 | + { |
| 111 | + first = false |
| 112 | + } |
| 113 | + else |
| 114 | + { |
| 115 | + println(",", &f) |
| 116 | + } |
| 117 | + x += 1 |
| 118 | + if x >= tiles_across |
| 119 | + { |
| 120 | + x = 0 |
| 121 | + y += 1 |
| 122 | + } |
| 123 | + print(" \"\(k)\": {\n \"x\": \(x_px),\n \"y\": \(y_px),\n \"w\": \(tile_width),\n \"h\": \(tile_height)\n }", &f) |
| 124 | +} |
| 125 | +println("\n}", &f) |
| 126 | +f.close() |
| 127 | +NSGraphicsContext.currentContext().flushGraphics() |
| 128 | +large_image_rep.TIFFRepresentation.writeToFile(out_tiff + ".tiff", atomically: true) |
0 commit comments