1 module rip.io.formats.ppm; 2 3 private { 4 import std.algorithm; 5 import std.conv : parse; 6 7 import std.stdio : File; 8 import std..string; 9 10 import rip.concepts; 11 import rip.io.interfaces; 12 } 13 14 public: 15 static const auto P6 = new P6Worker; 16 17 private: 18 19 static final class P6Worker : FormatWorker!(Surface) { 20 21 override Surface save(in Surface surface, in string filename) const { 22 File file; 23 24 with (file) 25 { 26 open(filename, "w"); 27 writeln("P6"); 28 writeln(surface.getWidth!uint, " ", surface.getHeight!uint); 29 writeln(255); 30 31 //раскомментировать, когда ситуация с этим шаблоном разрешится 32 //mixin colorsToFile; 33 34 void toFile(in RGBColor a) { 35 file.write( 36 a.red!char, 37 a.green!char, 38 a.blue!char); 39 } 40 41 surface 42 .getPixels() 43 .each!toFile; 44 45 close(); 46 } 47 48 return cast(Surface)surface; 49 } 50 //вернёт false, если всё прошло успешно 51 52 override Surface decode(File file) const { 53 with (file) { 54 if (readln().strip == "P6") 55 { 56 auto imageSize = readln.split; 57 auto width = parse!size_t(imageSize[0]); 58 auto height = parse!size_t(imageSize[1]); 59 readln(); 60 auto buffer = new ubyte[width * 3]; 61 62 Surface surface = new Surface(width, height); 63 64 for (size_t i = 0; i < height; i++) 65 { 66 file.rawRead!ubyte(buffer); 67 for (size_t j = 0; j < width; j++) 68 { 69 70 surface[j + i * width] = new RGBColor( 71 buffer[j * 3], 72 buffer[j * 3 + 1], 73 buffer[j * 3 + 2] 74 ); 75 } 76 } 77 78 close(); 79 80 return surface; 81 } 82 } 83 84 assert(0, "PPM: Error. Decoding terminated."); 85 } 86 87 override bool checkOnHeader(File file) const { 88 ubyte[2] buff; 89 file.rawRead(buff); 90 file.seek(0); 91 return buff == [0x50, 0x36]; 92 } 93 94 override Surface load(in string filename) const { 95 File file; 96 97 file.open(filename, "r"); 98 99 return this.decode(file); 100 } 101 }