| 1 | // Aseprite |
| 2 | // Copyright (C) 2018-2022 Igara Studio S.A. |
| 3 | // Copyright (C) 2001-2018 David Capello |
| 4 | // |
| 5 | // This program is distributed under the terms of |
| 6 | // the End-User License Agreement for Aseprite. |
| 7 | |
| 8 | #ifdef HAVE_CONFIG_H |
| 9 | #include "config.h" |
| 10 | #endif |
| 11 | |
| 12 | #include "app/context.h" |
| 13 | #include "app/doc.h" |
| 14 | #include "app/file/file.h" |
| 15 | #include "app/file/file_format.h" |
| 16 | #include "app/file/file_formats_manager.h" |
| 17 | #include "base/fs.h" |
| 18 | #include "base/string.h" |
| 19 | #include "dio/detect_format.h" |
| 20 | #include "doc/cel.h" |
| 21 | #include "doc/file/act_file.h" |
| 22 | #include "doc/file/col_file.h" |
| 23 | #include "doc/file/gpl_file.h" |
| 24 | #include "doc/file/hex_file.h" |
| 25 | #include "doc/file/pal_file.h" |
| 26 | #include "doc/image.h" |
| 27 | #include "doc/layer.h" |
| 28 | #include "doc/palette.h" |
| 29 | #include "doc/sprite.h" |
| 30 | |
| 31 | #include <cstring> |
| 32 | |
| 33 | namespace app { |
| 34 | |
| 35 | using namespace doc; |
| 36 | |
| 37 | static const char* palExts[] = { "act" , "col" , "gpl" , "hex" , "pal" }; |
| 38 | |
| 39 | base::paths get_readable_palette_extensions() |
| 40 | { |
| 41 | base::paths paths = get_readable_extensions(); |
| 42 | for (const char* s : palExts) |
| 43 | paths.push_back(s); |
| 44 | return paths; |
| 45 | } |
| 46 | |
| 47 | base::paths get_writable_palette_extensions() |
| 48 | { |
| 49 | base::paths paths = get_writable_extensions(FILE_SUPPORT_INDEXED); |
| 50 | for (const char* s : palExts) |
| 51 | paths.push_back(s); |
| 52 | return paths; |
| 53 | } |
| 54 | |
| 55 | std::unique_ptr<doc::Palette> load_palette( |
| 56 | const char* filename, |
| 57 | const FileOpConfig* config) |
| 58 | { |
| 59 | dio::FileFormat dioFormat = dio::detect_format(filename); |
| 60 | std::unique_ptr<Palette> pal = nullptr; |
| 61 | |
| 62 | switch (dioFormat) { |
| 63 | |
| 64 | case dio::FileFormat::ACT_PALETTE: |
| 65 | pal = doc::file::load_act_file(filename); |
| 66 | break; |
| 67 | |
| 68 | case dio::FileFormat::COL_PALETTE: |
| 69 | pal = doc::file::load_col_file(filename); |
| 70 | break; |
| 71 | |
| 72 | case dio::FileFormat::GPL_PALETTE: |
| 73 | pal = doc::file::load_gpl_file(filename); |
| 74 | break; |
| 75 | |
| 76 | case dio::FileFormat::HEX_PALETTE: |
| 77 | pal = doc::file::load_hex_file(filename); |
| 78 | break; |
| 79 | |
| 80 | case dio::FileFormat::PAL_PALETTE: |
| 81 | pal = doc::file::load_pal_file(filename); |
| 82 | break; |
| 83 | |
| 84 | default: { |
| 85 | FileFormat* ff = FileFormatsManager::instance()->getFileFormat(dioFormat); |
| 86 | if (!ff || !ff->support(FILE_SUPPORT_LOAD)) |
| 87 | break; |
| 88 | |
| 89 | std::unique_ptr<FileOp> fop( |
| 90 | FileOp::createLoadDocumentOperation( |
| 91 | nullptr, filename, |
| 92 | FILE_LOAD_CREATE_PALETTE | |
| 93 | FILE_LOAD_SEQUENCE_NONE | |
| 94 | FILE_LOAD_ONE_FRAME, |
| 95 | config)); |
| 96 | |
| 97 | if (fop && !fop->hasError()) { |
| 98 | fop->operate(nullptr); |
| 99 | fop->postLoad(); |
| 100 | |
| 101 | if (fop->document() && |
| 102 | fop->document()->sprite() && |
| 103 | fop->document()->sprite()->palette(frame_t(0))) { |
| 104 | pal = std::make_unique<Palette>( |
| 105 | *fop->document()->sprite()->palette(frame_t(0))); |
| 106 | } |
| 107 | |
| 108 | delete fop->releaseDocument(); |
| 109 | fop->done(); |
| 110 | } |
| 111 | break; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | if (pal) |
| 116 | pal->setFilename(filename); |
| 117 | |
| 118 | return pal; |
| 119 | } |
| 120 | |
| 121 | bool save_palette(const char* filename, const Palette* pal, int columns, |
| 122 | const gfx::ColorSpaceRef& cs) |
| 123 | { |
| 124 | dio::FileFormat dioFormat = dio::detect_format_by_file_extension(filename); |
| 125 | bool success = false; |
| 126 | |
| 127 | switch (dioFormat) { |
| 128 | |
| 129 | case dio::FileFormat::ACT_PALETTE: |
| 130 | success = doc::file::save_act_file(pal, filename); |
| 131 | break; |
| 132 | |
| 133 | case dio::FileFormat::COL_PALETTE: |
| 134 | success = doc::file::save_col_file(pal, filename); |
| 135 | break; |
| 136 | |
| 137 | case dio::FileFormat::GPL_PALETTE: |
| 138 | success = doc::file::save_gpl_file(pal, filename); |
| 139 | break; |
| 140 | |
| 141 | case dio::FileFormat::HEX_PALETTE: |
| 142 | success = doc::file::save_hex_file(pal, filename); |
| 143 | break; |
| 144 | |
| 145 | case dio::FileFormat::PAL_PALETTE: |
| 146 | success = doc::file::save_pal_file(pal, filename); |
| 147 | break; |
| 148 | |
| 149 | default: { |
| 150 | FileFormat* ff = FileFormatsManager::instance()->getFileFormat(dioFormat); |
| 151 | if (!ff || !ff->support(FILE_SUPPORT_SAVE)) |
| 152 | break; |
| 153 | |
| 154 | int w = (columns > 0 ? std::clamp(columns, 0, pal->size()): pal->size()); |
| 155 | int h = (pal->size() / w) + (pal->size() % w > 0 ? 1: 0); |
| 156 | |
| 157 | Context tmpContext; |
| 158 | gfx::ColorSpaceRef colorSpace = (cs ? cs: gfx::ColorSpace::MakeNone()); |
| 159 | Doc* doc = tmpContext.documents().add( |
| 160 | new Doc(Sprite::MakeStdSprite( |
| 161 | ImageSpec((pal->size() <= 256 ? doc::ColorMode::INDEXED: |
| 162 | doc::ColorMode::RGB), |
| 163 | w, h, 0, colorSpace), pal->size()))); |
| 164 | |
| 165 | Sprite* sprite = doc->sprite(); |
| 166 | doc->sprite()->setPalette(pal, false); |
| 167 | |
| 168 | LayerImage* layer = static_cast<LayerImage*>(sprite->root()->firstLayer()); |
| 169 | layer->configureAsBackground(); |
| 170 | |
| 171 | Image* image = layer->cel(frame_t(0))->image(); |
| 172 | image->clear(0); |
| 173 | |
| 174 | int x, y, c; |
| 175 | for (y=c=0; y<h; ++y) { |
| 176 | for (x=0; x<w; ++x) { |
| 177 | if (doc->colorMode() == doc::ColorMode::INDEXED) |
| 178 | image->putPixel(x, y, c); |
| 179 | else |
| 180 | image->putPixel(x, y, pal->entry(c)); |
| 181 | |
| 182 | if (++c == pal->size()) |
| 183 | goto done; |
| 184 | } |
| 185 | } |
| 186 | done:; |
| 187 | |
| 188 | doc->setFilename(filename); |
| 189 | success = (save_document(&tmpContext, doc) == 0); |
| 190 | |
| 191 | doc->close(); |
| 192 | delete doc; |
| 193 | break; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | return success; |
| 198 | } |
| 199 | |
| 200 | } |
| 201 | |