1 /** 2 * This module provides the public interface for Daffodil. 3 */ 4 module daffodil; 5 6 import std.path; 7 import std.stdio; 8 import std.typecons; 9 import std.algorithm; 10 11 import daffodil.util.data; 12 import daffodil.util.range; 13 14 public { 15 import daffodil.meta; 16 import daffodil.image; 17 import daffodil.pixel; 18 import daffodil.colorspace; 19 import daffodil.util.errors; 20 21 // Submodules 22 static { 23 import filter = daffodil.filter; 24 import transform = daffodil.transform; 25 // Image Formats 26 import bmp = daffodil.bmp; 27 } 28 } 29 30 /** 31 * Detects the :d:struct:`Format` a given input is in. 32 */ 33 Format detectFormat(T)(T data) if (isDataRange!T) { 34 auto range = data.inputRangeObject; 35 foreach (format; formats) { 36 try { 37 if (format.check(range)) { 38 return format; 39 } 40 } catch (ImageException e) { 41 continue; 42 } 43 44 } 45 throw new NotSupported("Unknown Format"); 46 } 47 /// Ditto 48 auto detectFormat(T)(T loadeable) if (isLoadeable!T) { 49 return detectFormat(dataLoad(loadeable)); 50 } 51 /// Ditto 52 Format detectFormat(V = real)(const Image!V image) if (isColorValue!V) { 53 auto typeInfo = typeid(image.meta); 54 foreach (format; formats) { 55 if (format.metaType && format.metaType == typeInfo) { 56 return format; 57 } 58 } 59 throw new NotSupported("Unknown Format"); 60 } 61 62 /** 63 * Loads the metadata from a given input. 64 */ 65 auto loadMeta(T)(T data) if (isDataRange!T) { 66 auto format = detectFormat(data); 67 return format.loadMeta(data.inputRangeObject); 68 } 69 /// Ditto 70 auto loadMeta(T)(T loadeable) if (isLoadeable!T) { 71 return loadMeta(dataLoad(loadeable)); 72 } 73 74 /** 75 * Loads a :d:class:`Image` from a given input. 76 */ 77 auto load(V = real, T)(T data) if (isColorValue!V && isDataRange!T) { 78 auto range = data.inputRangeObject; 79 auto format = detectFormat(data); 80 auto meta = format.loadMeta(range); 81 return new Image!V(format.loadImage(range, meta), meta); 82 } 83 /// Ditto 84 auto load(V = real, T)(T loadeable) if (isColorValue!V && isLoadeable!T) { 85 return load!V(dataLoad(loadeable)); 86 } 87 88 /** 89 * Saves a particular :d:class:`Image` to a given output. 90 */ 91 void save(V = real, T)(const Image!V image, T data) if (isColorValue!V && isOutRange!T) { 92 auto format = detectFormat(image); 93 format.save(data.outputRangeObject!ubyte, image.range.imageRangeObject, image.meta); 94 } 95 /// Ditto 96 void save(V = real)(const Image!V image, string path) if (isColorValue!V) { 97 // Specialcase for paths, to match by extension 98 Nullable!Format format; 99 foreach (f; formats) { 100 if (f.extensions.canFind(path.extension)) { 101 format = f; 102 break; 103 } 104 } 105 106 if (format.isNull) { 107 format = detectFormat(image); 108 } 109 110 auto data = dataSave(path).outputRangeObject!ubyte; 111 format.save(data, image.range.imageRangeObject, image.meta); 112 } 113 /// Ditto 114 void save(V = real, T)(const Image!V image, T saveable) if (isColorValue!V && isSaveable!T && !is(T == string)) { 115 return save(image, dataSave(saveable)); 116 } 117 118 /// 119 alias DataRange = InputRange!ubyte; 120 /// 121 template isDataRange(T) { 122 enum isDataRange = isInputRange!T && is(ElementType!T == ubyte); 123 } 124 /// 125 alias OutRange = OutputRange!ubyte; 126 /// 127 alias isOutRange(T) = isOutputRange!(T, ubyte); 128 129 /** 130 * A struct for metadata about an Image Format. See :d:func:`registerFormat` for 131 * more information. 132 */ 133 struct Format { 134 /// 135 string name; 136 /// 137 bool function(DataRange) check; 138 /// 139 MetaData function(DataRange) loadMeta; 140 /// 141 ImageRange!PixelData function(DataRange, MetaData) loadImage; 142 /// 143 void function(OutRange, RandomAccessImageRange!(real[]), const MetaData) save; 144 /// 145 string[] extensions; 146 /// 147 TypeInfo metaType; 148 } 149 150 private Format[] formats; 151 private Format[string] formatsByExt; 152 153 /** 154 * Register a new format for auto-detection with :d:func:`detectFormat`, 155 * :d:func:`loadMeta` and :d:func:`load` functions. 156 */ 157 void registerFormat(Format format) { 158 formats ~= format; 159 160 foreach (ext; format.extensions) { 161 assert(ext !in formatsByExt); 162 formatsByExt[ext] = format; 163 } 164 }