Also i get the importedImage variable through anything that turns an image into raw rgb (im using Photopea), and use this c++ code:
#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <algorithm>
struct Color {
int r, g, b;
};
std::array<Color, 16> PALETTE = { {
{0x00,0x00,0x00},
{0x33,0x00,0x00}, {0x66,0x00,0x00}, {0x99,0x00,0x00}, {0xCC,0x00,0x00}, {0xFF,0x00,0x00},
{0x00,0x33,0x00}, {0x00,0x66,0x00}, {0x00,0x99,0x00}, {0x00,0xCC,0x00}, {0x00,0xFF,0x00},
{0x00,0x00,0x33}, {0x00,0x00,0x66}, {0x00,0x00,0x99}, {0x00,0x00,0xCC}, {0x00,0x00,0xFF}
} };
// ---------------------
// Closest palette color
// ---------------------
int closest(int r, int g, int b) {
int best = 0;
long bestDist = LONG_MAX;
for (int i = 0; i < 16; i++) {
int dr = PALETTE[i].r - r;
int dg = PALETTE[i].g - g;
int db = PALETTE[i].b - b;
long dist = dr * dr + dg * dg + db * db;
if (dist < bestDist) {
bestDist = dist;
best = i;
}
}
return best;
}
// ---------------------
// rgbToNumberArr (C++ version)
// ---------------------
std::array<int, 9> rgbToNumberArr(int r, int g, int b) {
double R = r, G = g, B = b;
std::array<std::string, 9> pattern;
auto toHexByte = [](int n) {
const char* hex = "0123456789ABCDEF";
n = std::max(0, std::min(255, n));
std::string s;
s += hex[(n >> 4) & 0xF];
s += hex[n & 0xF];
return s;
};
auto decode = [](const std::string& code) {
char c = code[0];
int v = std::stoi(code.substr(1), nullptr, 16);
if (c == 'R') return Color{ v,0,0 };
if (c == 'G') return Color{ 0,v,0 };
return Color{ 0,0,v };
};
// Generate 9-pixel channel pattern
for (int i = 0; i < 9; i++) {
char channel = 'R';
double value = R;
if (G >= R && G >= B) { channel = 'G'; value = G; }
else if (B >= R && B >= G) { channel = 'B'; value = B; }
pattern[i] = std::string(1, channel) + toHexByte((int)value);
if (channel == 'R') R -= r / 9.0;
if (channel == 'G') G -= g / 9.0;
if (channel == 'B') B -= b / 9.0;
}
// Convert to palette indices
std::array<int, 9> out;
for (int i = 0; i < 9; i++) {
Color px = decode(pattern[i]);
out[i] = closest(px.r, px.g, px.b);
}
return out;
}
// ---------------------
// MAIN: RAW -> number[x][y][c]
// ---------------------
int main() {
const int WIDTH = 144; // <-- set your width
const int HEIGHT = 81; // <-- set your height
// Load RAW file
std::ifstream file("image.raw", std::ios::binary);
std::vector<unsigned char> bytes(
(std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>()
);
if (bytes.size() != WIDTH * HEIGHT * 3) {
std::cout << "ERROR: RAW file size does not match WIDTH*HEIGHT*3\n";
return 1;
}
// Convert to pixel array
std::vector<std::vector<Color>> pixels(HEIGHT, std::vector<Color>(WIDTH));
int idx = 0;
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
pixels[y][x] = {
bytes[idx++], // R
bytes[idx++], // G
bytes[idx++] // B
};
}
}
// Convert to GPU tiles: number[x][y][c]
std::vector<std::vector<std::array<int, 9>>> number(
HEIGHT, std::vector<std::array<int, 9>>(WIDTH)
);
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
Color c = pixels[y][x];
number[y][x] = rgbToNumberArr(c.r, c.g, c.b);
}
}
std::ofstream outFile("output.txt");
if (!outFile.is_open()) {
std::cout << "Failed to open output.txt\n";
return 1;
}
outFile << "let importedImage: number[][][] = [\n";
for (int x = 0; x < WIDTH; x++) {
outFile << " [\n";
for (int y = 0; y < HEIGHT; y++) {
outFile << " [";
for (int c = 0; c < 9; c++) {
outFile << number[y][x][c];
if (c != 8) outFile << ", ";
}
outFile << "]";
if (y != HEIGHT - 1) outFile << ",";
outFile << "\n";
}
outFile << " ]";
if (x != WIDTH - 1) outFile << ",";
outFile << "\n";
}
outFile << "];\n";
outFile.close();
std::cout << "Wrote output.txt successfully.\n";
return 0;
}
note that you will need to change the PALETTE variable if you have a different palette in your makecode project