Skip to content

Commit 5ab1d65

Browse files
Initial support for HSL color space. #135
1 parent 41f36a8 commit 5ab1d65

File tree

8 files changed

+356
-62
lines changed

8 files changed

+356
-62
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ These decodings are not yet solved, which might make them an interesting target.
4040
## Release Changelog
4141

4242
`master` -- GoodASM REPL now has working autocompletion on Windows.
43-
Dropping support for x86_64 macOS. Optional support for Yara-X.
43+
Dropping support for x86_64 macOS. Optional support for Yara-X. HSL
44+
color space for bit thresholds, with bit color histograms that are
45+
easier on the eyes.
4446

4547
2025-06-01 -- CLI and GUI features to work with ambiguous/damaged
4648
bits, useful when part of an implant ROM is poorly exposed. Solver

maskromtool.cpp

Lines changed: 113 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,17 +1177,27 @@ void MaskRomTool::updateThresholdHistogram(bool force){
11771177

11781178
//Zero the score.
11791179
for(int i=0; i<256; i++)
1180-
reds[i]=greens[i]=blues[i]=0;
1180+
reds[i]=greens[i]=blues[i]=hues[i]=sats[i]=lights[i]=0;
11811181

11821182
//Count the bits of each color.
11831183
for(auto i=bits.constBegin(); i!=bits.constEnd(); i++){
1184-
long pixel=(*i)->bitvalue_raw(this, background);
1184+
QRgb pixel=(*i)->bitvalue_raw(this, background);
1185+
1186+
//RGB are easy.
11851187
int r=((pixel>>16)&0xFF);
11861188
int g=((pixel>>8)&0xFF);
11871189
int b=((pixel)&0xFF);
11881190
reds[r]++;
11891191
greens[g]++;
11901192
blues[b]++;
1193+
1194+
//HSL require conversion.
1195+
QColor c(pixel);
1196+
int h=0, s=0, l=0;
1197+
c.getHsl(&h, &s, &l);
1198+
hues[h]++;
1199+
sats[s]++;
1200+
lights[l]++;
11911201
}
11921202

11931203
/* This looks like a memory leak, but it's
@@ -1201,13 +1211,28 @@ void MaskRomTool::updateThresholdHistogram(bool force){
12011211
green->setName("Green");
12021212
QLineSeries *blue = new QLineSeries();
12031213
blue->setName("Blue");
1214+
QLineSeries *H = new QLineSeries();
1215+
H->setName("H");
1216+
QLineSeries *S = new QLineSeries();
1217+
S->setName("S");
1218+
QLineSeries *L = new QLineSeries();
1219+
L->setName("L");
1220+
1221+
12041222
for(int i=0; i<256; i++){
12051223
red->append(i,reds[i]);
12061224
green->append(i,greens[i]);
12071225
blue->append(i,blues[i]);
1226+
H->append(i, hues[i]);
1227+
S->append(i, sats[i]);
1228+
L->append(i, lights[i]);
1229+
12081230
if(reds[i]>skyhigh) skyhigh=reds[i];
12091231
if(greens[i]>skyhigh) skyhigh=greens[i];
12101232
if(blues[i]>skyhigh) skyhigh=blues[i];
1233+
if(hues[i]>skyhigh) skyhigh=hues[i];
1234+
if(sats[i]>skyhigh) skyhigh=sats[i];
1235+
if(lights[i]>skyhigh) skyhigh=lights[i];
12111236
}
12121237

12131238
QLineSeries *redmark = new QLineSeries();
@@ -1219,23 +1244,64 @@ void MaskRomTool::updateThresholdHistogram(bool force){
12191244
QLineSeries *bluemark = new QLineSeries();
12201245
bluemark->append(thresholdB,0);
12211246
bluemark->append(thresholdB,skyhigh);
1222-
1247+
QLineSeries *hmark = new QLineSeries();
1248+
hmark->append(thresholdH,0);
1249+
hmark->append(thresholdH,skyhigh);
1250+
QLineSeries *smark = new QLineSeries();
1251+
smark->append(thresholdS,0);
1252+
smark->append(thresholdS,skyhigh);
1253+
QLineSeries *lmark = new QLineSeries();
1254+
lmark->append(thresholdL,0);
1255+
lmark->append(thresholdL,skyhigh);
1256+
1257+
//Remove the old ones
12231258
histogramchart.legend()->hide();
12241259
histogramchart.removeAllSeries();
1225-
histogramchart.addSeries(red);
1226-
histogramchart.addSeries(redmark);
1227-
histogramchart.addSeries(green);
1228-
histogramchart.addSeries(greenmark);
1229-
histogramchart.addSeries(blue);
1230-
histogramchart.addSeries(bluemark);
1231-
1232-
//Colors must be set *after* adding them to the chart.
1233-
red->setColor(Qt::red);
1234-
redmark->setColor(Qt::red);
1235-
green->setColor(Qt::green);
1236-
greenmark->setColor(Qt::green);
1237-
blue->setColor(Qt::blue);
1238-
bluemark->setColor(Qt::blue);
1260+
1261+
//Show RGB if none of the thresholds have been set.
1262+
bool showrgb=((thresholdR+thresholdG+thresholdB+thresholdH+thresholdS+thresholdL)==0);
1263+
1264+
//Colors must be set *after* adding series to the chart.
1265+
1266+
if(showrgb || thresholdR>0){
1267+
histogramchart.addSeries(red);
1268+
histogramchart.addSeries(redmark);
1269+
red->setColor(Qt::red);
1270+
redmark->setColor(Qt::red);
1271+
}
1272+
1273+
if(showrgb || thresholdG>0){
1274+
histogramchart.addSeries(green);
1275+
histogramchart.addSeries(greenmark);
1276+
green->setColor(Qt::green);
1277+
greenmark->setColor(Qt::green);
1278+
}
1279+
1280+
if(showrgb || thresholdB>0){
1281+
histogramchart.addSeries(blue);
1282+
histogramchart.addSeries(bluemark);
1283+
blue->setColor(Qt::blue);
1284+
bluemark->setColor(Qt::blue);
1285+
}
1286+
1287+
if(thresholdH>0){
1288+
histogramchart.addSeries(H);
1289+
histogramchart.addSeries(hmark);
1290+
H->setColor(Qt::cyan);
1291+
hmark->setColor(Qt::cyan);
1292+
}
1293+
if(thresholdS>0){
1294+
histogramchart.addSeries(S);
1295+
histogramchart.addSeries(smark);
1296+
S->setColor(Qt::magenta);
1297+
smark->setColor(Qt::magenta);
1298+
}
1299+
if(thresholdL>0){
1300+
histogramchart.addSeries(L);
1301+
histogramchart.addSeries(lmark);
1302+
L->setColor(Qt::darkYellow);
1303+
lmark->setColor(Qt::darkYellow);
1304+
}
12391305

12401306
histogramchart.createDefaultAxes();
12411307
histogramchart.setTitle("Bit Histogram");
@@ -1245,21 +1311,32 @@ void MaskRomTool::updateThresholdHistogram(bool force){
12451311

12461312

12471313
//Set the threshold.
1248-
void MaskRomTool::setBitThreshold(qreal r, qreal g, qreal b){
1314+
void MaskRomTool::setBitThreshold(qreal r, qreal g, qreal b,
1315+
qreal h, qreal s, qreal l){
12491316
thresholdR=r;
12501317
thresholdG=g;
12511318
thresholdB=b;
12521319

1320+
thresholdH=h;
1321+
thresholdS=s;
1322+
thresholdL=l;
1323+
12531324
//Redraws only if the histogram is visible.
12541325
updateThresholdHistogram();
12551326
}
12561327

12571328
//Get the threshold.
1258-
void MaskRomTool::getBitThreshold(qreal &r, qreal &g, qreal &b){
1329+
void MaskRomTool::getBitThreshold(qreal &r, qreal &g, qreal &b,
1330+
qreal &h, qreal &s, qreal &l
1331+
){
12591332
r=thresholdR;
12601333
g=thresholdG;
12611334
b=thresholdB;
12621335

1336+
h=thresholdH;
1337+
s=thresholdS;
1338+
l=thresholdL;
1339+
12631340
if(verbose)
12641341
qDebug()<<"Returning RGB threshold"<<r<<g<<b;
12651342
}
@@ -1545,7 +1622,9 @@ void MaskRomTool::markBit(RomLineItem* row, RomLineItem* col){
15451622
bits.append(bit);
15461623

15471624
bit->bitvalue_raw(this, background);
1548-
bit->bitvalue_sample(this, background, thresholdR, thresholdG, thresholdB);
1625+
bit->bitvalue_sample(this, background,
1626+
thresholdR, thresholdG, thresholdB,
1627+
thresholdH, thresholdS, thresholdL);
15491628

15501629
bitcount++;
15511630
}
@@ -1859,7 +1938,9 @@ void MaskRomTool::markFixes(){
18591938
void MaskRomTool::remarkBits(){
18601939
for(auto i=bits.constBegin(); i!=bits.constEnd(); i++){
18611940
(*i)->bitvalue_raw(this, background);
1862-
(*i)->bitvalue_sample(this, background, thresholdR, thresholdG, thresholdB);
1941+
(*i)->bitvalue_sample(this, background,
1942+
thresholdR, thresholdG, thresholdB,
1943+
thresholdH, thresholdS, thresholdL);
18631944
}
18641945
//We remark all fixes here, because it's fast.
18651946
markFixes();
@@ -1918,6 +1999,7 @@ QJsonObject MaskRomTool::exportJSON(bool justselection){
19181999
/* We try not to break compatibility, but as features are added,
19192000
* we should update this date to indicate the new file format
19202001
* version number.
2002+
* 2025.10.30 -- HSL colorspace.
19212003
* 2025.05.07 -- Disassembly settings, such as damage bits.
19222004
* 2025.03.30 -- Export of partial selection.
19232005
* 2024.07.27 -- Lines are sorted, no new types.
@@ -1933,13 +2015,16 @@ QJsonObject MaskRomTool::exportJSON(bool justselection){
19332015
* 2023.05.05 -- Adds the 'alignthreshold' field. Defaults to 5 if missing.
19342016
* 2022.09.28 -- First public release.
19352017
*/
1936-
root["00version"]="2025.03.30";
2018+
root["00version"]="2025.10.30";
19372019

19382020
//These threshold values will change in a later version.
19392021
QJsonObject settings;
19402022
settings["red"]=thresholdR;
19412023
settings["green"]=thresholdG;
19422024
settings["blue"]=thresholdB;
2025+
settings["H"]=thresholdH; //2025.10.30
2026+
settings["S"]=thresholdS; //2025.10.30
2027+
settings["L"]=thresholdL; //2025.10.30
19432028
settings["bitsize"]=bitSize;
19442029
settings["alignthreshold"]=QJsonValue((int) alignSkipThreshold); //2023.05.05
19452030
settings["sampler"]=sampler->name; //2023.05.08
@@ -2092,7 +2177,12 @@ void MaskRomTool::importJSON(QJsonObject o){
20922177
QJsonValue red=settings.value("red");
20932178
QJsonValue green=settings.value("green");
20942179
QJsonValue blue=settings.value("blue");
2095-
setBitThreshold(red.toDouble(0), green.toDouble(0), blue.toDouble(0));
2180+
QJsonValue h=settings.value("H");
2181+
QJsonValue s=settings.value("S");
2182+
QJsonValue l=settings.value("L");
2183+
setBitThreshold(red.toDouble(0), green.toDouble(0), blue.toDouble(0),
2184+
h.toDouble(0), s.toDouble(0), l.toDouble(0)
2185+
);
20962186
setBitSize(settings.value("bitsize").toDouble(10));
20972187
QJsonValue alignskipthreshold=settings.value("alignthreshold");
20982188
setAlignSkipCountThreshold(alignskipthreshold.toInt(5)); //Default of 5.

maskromtool.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,11 @@ class MaskRomTool : public QMainWindow{
162162
void fileOpen(QString filename);
163163

164164
//Sets the threshold. Expect this to change in later revisions.
165-
void setBitThreshold(qreal r, qreal g, qreal b);
165+
void setBitThreshold(qreal r, qreal g, qreal b,
166+
qreal h, qreal s, qreal l);
166167
//Gets the bit threshold.
167-
void getBitThreshold(qreal &r, qreal &g, qreal &b);
168+
void getBitThreshold(qreal &r, qreal &g, qreal &b,
169+
qreal &h, qreal &s, qreal &l);
168170
//Sets the bit display size.
169171
void setBitSize(qreal size);
170172
//Gets the bit display size.
@@ -247,7 +249,8 @@ class MaskRomTool : public QMainWindow{
247249
GatoROM gr;
248250

249251
//Histogram bits.
250-
qreal reds[256], greens[256], blues[256];
252+
qreal reds[256], greens[256], blues[256],
253+
hues[256], sats[256], lights[256];
251254

252255
private slots:
253256
void on_openButton_triggered();
@@ -314,7 +317,8 @@ private slots:
314317

315318
private:
316319
Ui::MaskRomTool *ui;
317-
qreal thresholdR, thresholdG, thresholdB;
320+
qreal thresholdR, thresholdG, thresholdB,
321+
thresholdH, thresholdS, thresholdL;
318322
qreal bitSize=10;
319323
bool alignmentdirty=true; // Table marking is outdated.
320324
bool markingdirty=true; // Bit marking is outdated.

rombititem.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ void RomBitItem::setBrush(){
4646
QGraphicsRectItem::setBrush(value?truebrush:falsebrush);
4747
}
4848

49-
bool RomBitItem::bitvalue_sample(MaskRomTool *mrt, QImage &bg, float red, float green, float blue){
49+
bool RomBitItem::bitvalue_sample(MaskRomTool *mrt, QImage &bg,
50+
float red, float green, float blue,
51+
float H, float S, float L){
5052
if(!fixed){
5153
//First we grab a fresh sample of the pixel.
5254
QRgb pixel=bitvalue_raw(mrt, bg);
@@ -56,9 +58,25 @@ bool RomBitItem::bitvalue_sample(MaskRomTool *mrt, QImage &bg, float red, float
5658
r=(red>((pixel>>16)&0xFF));
5759
g=(green>((pixel>>8)&0xFF));
5860
b=(blue>((pixel)&0xFF));
61+
62+
//HSL values.
63+
int Hp, Sp, Lp;
64+
bool h, s, l;
65+
QColor c=QColor(pixel);
66+
c.toHsl();
67+
c.getHsl(&Hp, &Sp, &Lp);
68+
h=(H>Hp);
69+
s=(S>Sp);
70+
l=(L>Lp);
71+
72+
73+
74+
5975
//Value is true if any sample fits.
60-
value=r|g|b;
76+
value=r|g|b | h|s|l;
77+
6178

79+
//FIXME: This should be better calibrated.
6280
//Is the value just on the threshold?
6381
int ambiguitythreshold=3;
6482
int R, G, B;

rombititem.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ class RomBitItem : public QGraphicsRectItem
3030
//Sample the color of the bit.
3131
QRgb bitvalue_raw(MaskRomTool *mrt, QImage &bg);
3232
//What's the value of the bit? Includes override and average color.
33-
bool bitvalue_sample(MaskRomTool *mrt, QImage &bg, float red, float green, float blue);
33+
bool bitvalue_sample(MaskRomTool *mrt, QImage &bg,
34+
float red, float green, float blue,
35+
float h, float s, float l);
3436
//What's the last value of the bit? Does *not* resample.
3537
bool bitValue();
3638
//Is this bit too close to its threshold, or suspicious for some other reason?

0 commit comments

Comments
 (0)