Skip to content

Commit 2631662

Browse files
committed
Update gamma curves
1 parent 62ead0a commit 2631662

File tree

4 files changed

+118
-137
lines changed

4 files changed

+118
-137
lines changed

app/src/main/java/com/radzivon/bartoshyk/avif/MainActivity.kt

Lines changed: 58 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -93,73 +93,71 @@ class MainActivity : AppCompatActivity() {
9393
// HDR EXAMPLES - https://us.zonerama.com/williamskeaguidingphotography/Photo/1000120226/1004888131
9494
lifecycleScope.launch(Dispatchers.IO) {
9595
val coder = HeifCoder()
96-
// val buffer = assets.open("choke_ck.jpg").source().buffer().readByteArray()
97-
// val bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.size)
98-
// val encoded = coder.encodeAvif(bitmap, quality = 99, preciseMode = PreciseMode.LOSSLESS)
99-
// val encoded100 = coder.encodeAvif(bitmap, quality = 100)
100-
// val decoded = coder.decode(encoded)
101-
// val decoded100 = coder.decode(encoded100)
102-
// lifecycleScope.launch(Dispatchers.Main) {
103-
// val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
104-
// imageView.root.setImageBitmap(decoded)
105-
// binding.scrollViewContainer.addView(imageView.root)
106-
// }
107-
// lifecycleScope.launch(Dispatchers.Main) {
108-
// val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
109-
// imageView.root.setImageBitmap(bitmap)
110-
// binding.scrollViewContainer.addView(imageView.root)
111-
// }
96+
val buffer = assets.open("pexels_house_wall_p3.jpg").source().buffer().readByteArray()
97+
val bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.size)
98+
val encoded = coder.encodeAvif(bitmap, quality = 99, preciseMode = PreciseMode.LOSSLESS)
99+
val decoded = coder.decode(encoded)
100+
lifecycleScope.launch(Dispatchers.Main) {
101+
val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
102+
imageView.root.setImageBitmap(decoded)
103+
binding.scrollViewContainer.addView(imageView.root)
104+
}
105+
lifecycleScope.launch(Dispatchers.Main) {
106+
val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
107+
imageView.root.setImageBitmap(bitmap)
108+
binding.scrollViewContainer.addView(imageView.root)
109+
}
112110
// lifecycleScope.launch(Dispatchers.Main) {
113111
// val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
114112
// imageView.root.setImageBitmap(decoded100)
115113
// binding.scrollViewContainer.addView(imageView.root)
116114
// }
117-
val allFiles1 = getAllFilesFromAssets().filter { it.contains(".avif") || it.contains(".heic") }
118-
val allFiles2 = getAllFilesFromAssets(path = "hdr").filter { it.contains(".avif") || it.contains(".heic") }
119-
var allFiles = mutableListOf<String>()
120-
allFiles.addAll(allFiles2)
121-
allFiles.addAll(allFiles1)
115+
// val allFiles1 = getAllFilesFromAssets().filter { it.contains(".avif") || it.contains(".heic") }
116+
// val allFiles2 = getAllFilesFromAssets(path = "hdr").filter { it.contains(".avif") || it.contains(".heic") }
117+
// var allFiles = mutableListOf<String>()
118+
// allFiles.addAll(allFiles2)
119+
// allFiles.addAll(allFiles1)
122120
// allFiles = allFiles.filter { it.contains("blue_lights.avif") || it.contains("bbb_alpha_inverted.avif") }.toMutableList()
123-
// allFiles = allFiles.filter { it.contains("bbb_alpha_inverted.avif") }.toMutableList()
124-
for (file in allFiles) {
125-
try {
126-
Log.d("AVIF", "start processing $file")
127-
val buffer = this@MainActivity.assets.open(file).source().buffer()
128-
.readByteArray()
129-
val size = coder.getSize(buffer)
130-
if (size != null) {
131-
// val bitmap = coder.decodeSampled(
132-
// buffer,
133-
// if (size.width > 1800 || size.height > 1800) size.width / 2 else size.width,
134-
// if (size.width > 1800 || size.height > 1800) size.height / 2 else size.height,
135-
// PreferredColorConfig.RGBA_1010102,
136-
// ScaleMode.RESIZE
121+
//// allFiles = allFiles.filter { it.contains("bbb_alpha_inverted.avif") }.toMutableList()
122+
// for (file in allFiles) {
123+
// try {
124+
// Log.d("AVIF", "start processing $file")
125+
// val buffer = this@MainActivity.assets.open(file).source().buffer()
126+
// .readByteArray()
127+
// val size = coder.getSize(buffer)
128+
// if (size != null) {
129+
//// val bitmap = coder.decodeSampled(
130+
//// buffer,
131+
//// if (size.width > 1800 || size.height > 1800) size.width / 2 else size.width,
132+
//// if (size.width > 1800 || size.height > 1800) size.height / 2 else size.height,
133+
//// PreferredColorConfig.RGBA_1010102,
134+
//// ScaleMode.RESIZE
135+
//// )
136+
// val bitmap = coder.decode(
137+
// buffer,
138+
// preferredColorConfig = PreferredColorConfig.RGBA_8888,
137139
// )
138-
val bitmap = coder.decode(
139-
buffer,
140-
preferredColorConfig = PreferredColorConfig.RGBA_8888,
141-
)
142-
val encoded = coder.encodeAvif(bitmap)
143-
val decodedEncoded = coder.decode(encoded)
144-
lifecycleScope.launch(Dispatchers.Main) {
145-
val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
146-
imageView.root.setImageBitmap(bitmap)
147-
binding.scrollViewContainer.addView(imageView.root)
148-
}
149-
lifecycleScope.launch(Dispatchers.Main) {
150-
val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
151-
imageView.root.setImageBitmap(decodedEncoded)
152-
binding.scrollViewContainer.addView(imageView.root)
153-
}
154-
}
155-
} catch (e: Exception) {
156-
if (e is FileNotFoundException || e is java.io.FileNotFoundException) {
157-
158-
} else {
159-
throw e
160-
}
161-
}
162-
}
140+
// lifecycleScope.launch(Dispatchers.Main) {
141+
// val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
142+
// imageView.root.setImageBitmap(bitmap)
143+
// binding.scrollViewContainer.addView(imageView.root)
144+
// }
145+
// val encoded = coder.encodeAvif(bitmap)
146+
// val decodedEncoded = coder.decode(encoded)
147+
// lifecycleScope.launch(Dispatchers.Main) {
148+
// val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
149+
// imageView.root.setImageBitmap(decodedEncoded)
150+
// binding.scrollViewContainer.addView(imageView.root)
151+
// }
152+
// }
153+
// } catch (e: Exception) {
154+
// Log.d("AVIF", e.toString())
155+
// if (e is FileNotFoundException || e is java.io.FileNotFoundException) {
156+
// } else {
157+
// throw e
158+
// }
159+
// }
160+
// }
163161
}
164162

165163
// https://wh.aimuse.online/creatives/IMUSE_03617fe2db82a584166_27/TT_a9d21ff1061d785347935fef/68f06252.avif

avif-coder/src/main/cpp/algo/fast_math-inl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,20 @@ Exp2f(const DF df, V x) {
8989
}
9090

9191
template<class D, HWY_IF_U16_D(D)>
92-
HWY_FAST_MATH_INLINE Vec<D> DivBy255(D d, Vec<D> x) {
92+
HWY_FAST_MATH_INLINE Vec<D> DivBy255Round(D d, Vec<D> x) {
9393
const auto rounding = Set(d, 1 << 7);
9494
x = Add(x, rounding);
9595
const auto multiplier = Set(d, 0x8080);
9696
x = MulHigh(x, multiplier);
9797
return ShiftRight<7>(x);
9898
}
9999

100+
template<class D, HWY_IF_U16_D(D)>
101+
HWY_FAST_MATH_INLINE Vec<D> DivBy255(D d, Vec<D> x) {
102+
const auto append = Set(d, 1);
103+
return ShiftRight<8>(Add(Add(x, append), ShiftRight<8>(x)));
104+
}
105+
100106
template<class DF, class V>
101107
HWY_FAST_MATH_INLINE V
102108
Lognf(const DF df, V x) {

avif-coder/src/main/cpp/colorspace/GamutAdapter.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,7 @@ struct ChromaAdaptation {
201201
}
202202
}
203203

204-
if (gammaCorrection == Rec2020) {
205-
pqR = bt2020GammaCorrection(df32, pqR);
206-
pqG = bt2020GammaCorrection(df32, pqG);
207-
pqB = bt2020GammaCorrection(df32, pqB);
208-
} else if (gammaCorrection == DCIP3) {
204+
if (gammaCorrection == DCIP3) {
209205
pqR = dciP3PQGammaCorrection(df32, pqR);
210206
pqG = dciP3PQGammaCorrection(df32, pqG);
211207
pqB = dciP3PQGammaCorrection(df32, pqB);
@@ -214,10 +210,10 @@ struct ChromaAdaptation {
214210
pqR = gammaOtf(df32, pqR, gammaEval);
215211
pqG = gammaOtf(df32, pqG, gammaEval);
216212
pqB = gammaOtf(df32, pqB, gammaEval);
217-
} else if (gammaCorrection == Rec709) {
218-
pqR = LinearITUR709ToITUR709(df32, pqR);
219-
pqG = LinearITUR709ToITUR709(df32, pqG);
220-
pqB = LinearITUR709ToITUR709(df32, pqB);
213+
} else if (gammaCorrection == Rec709 || gammaCorrection == Rec2020) {
214+
pqR = Rec709Eotf(df32, pqR);
215+
pqG = Rec709Eotf(df32, pqG);
216+
pqB = Rec709Eotf(df32, pqB);
221217
} else if (gammaCorrection == sRGB) {
222218
pqR = SRGBOetf(df32, pqR);
223219
pqG = SRGBOetf(df32, pqG);

avif-coder/src/main/cpp/colorspace/eotf-inl.h

Lines changed: 48 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,6 @@ static const float alphaRec2020 = 1.09929682680944f;
4444
using namespace hwy;
4545
using namespace hwy::HWY_NAMESPACE;
4646

47-
HWY_FAST_MATH_INLINE float bt2020GammaCorrection(float linear) {
48-
if (0 <= betaRec2020 && linear < betaRec2020) {
49-
return 4.5f * linear;
50-
} else if (betaRec2020 <= linear && linear < 1) {
51-
return alphaRec2020 * powf(linear, 0.45f) - (alphaRec2020 - 1.0f);
52-
}
53-
return linear;
54-
}
55-
5647
HWY_FAST_MATH_INLINE float ToLinearPQ(float v, const float sdrReferencePoint) {
5748
float o = v;
5849
v = std::max(0.0f, v);
@@ -111,44 +102,33 @@ HWY_FAST_MATH_INLINE V ToLinearPQ(const D df, V v, const TFromD<D> sdrReferenceP
111102
}
112103

113104
template<class D, typename V = Vec<D>, HWY_IF_FLOAT(TFromD<D>)>
114-
HWY_FAST_MATH_INLINE V bt2020GammaCorrection(const D d, V color) {
115-
const V bt2020 = Set(d, betaRec2020);
116-
const V alpha2020 = Set(d, alphaRec2020);
117-
using T = hwy::HWY_NAMESPACE::TFromD<D>;
118-
const auto cmp = color < bt2020;
119-
const auto fourAndHalf = Set(d, static_cast<T>(4.5f));
120-
const auto branch1 = Mul(color, fourAndHalf);
121-
const V power1 = Set(d, static_cast<T>(0.45f));
122-
const V ones = Set(d, static_cast<T>(1.0f));
123-
const V power2 = Sub(alpha2020, ones);
124-
const auto branch2 =
125-
Sub(Mul(alpha2020, coder::HWY_NAMESPACE::Pow(d, color, power1)), power2);
126-
return IfThenElse(cmp, branch1, branch2);
127-
}
128-
129-
template<class D, typename V = Vec<D>, HWY_IF_FLOAT(TFromD<D>)>
130-
HWY_FAST_MATH_INLINE V LinearITUR709ToITUR709(const D df, V value) {
131-
const auto minCurve = Set(df, static_cast<TFromD<D>>(0.018f));
105+
HWY_FAST_MATH_INLINE V Rec709Oetf(const D df, V value) {
106+
const auto minCutOff = Set(df, static_cast<TFromD<D>>(0.018053968510807f));
132107
const auto minPowValue = Set(df, static_cast<TFromD<D>>(4.5f));
133-
const auto minLane = Mul(value, minPowValue);
134-
const auto subValue = Set(df, static_cast<TFromD<D>>(0.099f));
135-
const auto scalePower = Set(df, static_cast<TFromD<D>>(1.099f));
108+
const auto lo = Mul(value, minPowValue);
109+
const auto zeros = Zero(df);
110+
const auto ones = Set(df, 1.0f);
111+
const auto subValue = Set(df, static_cast<TFromD<D>>(0.09929682680944f));
112+
const auto scalePower = Set(df, static_cast<TFromD<D>>(1.09929682680944f));
136113
const auto pwrValue = Set(df, static_cast<TFromD<D>>(0.45f));
137-
const auto maxLane = MulSub(coder::HWY_NAMESPACE::Pow(df, value, pwrValue), scalePower,
138-
subValue);
139-
return IfThenElse(value < minCurve, minLane, maxLane);
114+
const auto ho = MulSub(coder::HWY_NAMESPACE::Pow(df, value, pwrValue), scalePower, subValue);
115+
auto Lc = IfThenElse(And(value < minCutOff, value >= zeros), lo, zeros);
116+
Lc = IfThenZeroElse(value < zeros, Lc);
117+
Lc = IfThenElse(And(value >= minCutOff, value <= ones), ho, Lc);
118+
Lc = IfThenElse(value > ones, ones, Lc);
119+
return Lc;
140120
}
141121

142122
HWY_FAST_MATH_INLINE float SRGBEotf(float v) {
143-
if (v < 0) {
144-
return 0;
145-
}
146-
if (v <= 0.045f) {
123+
if (v < 0.0f) {
124+
return 0.0f;
125+
} else if (v < 12.92f * 0.0030412825601275209f) {
147126
return v / 12.92f;
148-
} else if (v <= 1.f) {
149-
return std::powf((v + 0.055f) / 1.055f, 2.4f);
127+
} else if (v < 1.0f) {
128+
return std::powf((v + 0.0550107189475866f) / 1.0550107189475866f, 2.4f);
129+
} else {
130+
return 1.0f;
150131
}
151-
return 1.f;
152132
}
153133

154134
HWY_FAST_MATH_INLINE float Rec709Eotf(float v) {
@@ -162,7 +142,7 @@ HWY_FAST_MATH_INLINE float Rec709Eotf(float v) {
162142
return 1.f;
163143
}
164144

165-
HWY_FAST_MATH_INLINE float FromLinear709(float linear) {
145+
HWY_FAST_MATH_INLINE float Rec709Oetf(float linear) {
166146
if (linear < 0.f) {
167147
return 0.f;
168148
} else if (linear < 0.018053968510807f) {
@@ -177,13 +157,13 @@ template<class D, HWY_IF_F32_D(D), typename T = TFromD<D>, typename V = VFromD<D
177157
HWY_FAST_MATH_INLINE V SRGBEotf(D d, V v) {
178158
const auto highCutOff = Set(d, static_cast<T>(1.0f));
179159
const auto zeros = Zero(d);
180-
const auto lowerValueThreshold = Set(d, T(0.045f));
160+
const auto lowerValueThreshold = Set(d, static_cast<T>(12.92f * 0.0030412825601275209f));
181161
const auto lowValueDivider = Set(d, static_cast<T>(1.0f) / static_cast<T>(12.92f));
182162
const auto lowMask = v <= lowerValueThreshold;
183163
const auto lowValue = Mul(v, lowValueDivider);
184164
const auto powerStatic = Set(d, T(2.4f));
185-
const auto addStatic = Set(d, T(0.055f));
186-
const auto scaleStatic = ApproximateReciprocal(Set(d, T(1.055f)));
165+
const auto addStatic = Set(d, T(0.0550107189475866f));
166+
const auto scaleStatic = ApproximateReciprocal(Set(d, T(1.0550107189475866f)));
187167
const auto highValue = Pow(d, Mul(Add(v, addStatic), scaleStatic), powerStatic);
188168
auto result = IfThenElse(And(lowMask, v >= zeros), lowValue, v);
189169
result = IfThenElse(And(v > lowerValueThreshold, v <= highCutOff), highValue, result);
@@ -193,41 +173,35 @@ HWY_FAST_MATH_INLINE V SRGBEotf(D d, V v) {
193173
}
194174

195175
HWY_FAST_MATH_INLINE float SRGBOetf(const float linear) {
196-
if (linear <= 0.0031308f) {
197-
return 12.92f * linear;
176+
if (linear < 0.0f) {
177+
return 0.0f;
178+
} else if (linear < 0.0030412825601275209f) {
179+
return linear * 12.92f;
180+
} else if (linear < 1.0f) {
181+
return 1.0550107189475866f * powf(linear, 1.0f / 2.4f) - 0.0550107189475866f;
198182
} else {
199-
return 1.055f * std::powf(linear, 1.0f / 2.4f) - 0.055f;
183+
return 1.0f;
200184
}
201185
}
202186

203187
template<class D, typename V = Vec<D>, HWY_IF_FLOAT(TFromD<D>)>
204188
HWY_FAST_MATH_INLINE V SRGBOetf(const D df, V v) {
205189
const auto zeros = Zero(df);
206190
const auto highCutOff = Set(df, static_cast<TFromD<D>>(1.0f));
207-
const auto minCutOff = Set(df, static_cast<TFromD<D>>(0.0031308f));
191+
const auto minCutOff = Set(df, static_cast<TFromD<D>>(0.0030412825601275209f));
208192
const auto minPowValue = Set(df, static_cast<TFromD<D>>(12.92f));
209193
const auto lowValue = Mul(v, minPowValue);
210-
const auto subValue = Set(df, static_cast<TFromD<D>>(0.055f));
211-
const auto scalePower = Set(df, static_cast<TFromD<D>>(1.055f));
194+
const auto subValue = Set(df, static_cast<TFromD<D>>(0.0550107189475866f));
195+
const auto scalePower = Set(df, static_cast<TFromD<D>>(1.0550107189475866f));
212196
const auto pwrValue = Set(df, static_cast<TFromD<D>>(1.0f / 2.4f));
213-
const auto highValue = MulSub(coder::HWY_NAMESPACE::Pow(df, v, pwrValue), scalePower,
214-
subValue);
215-
197+
const auto highValue = MulSub(coder::HWY_NAMESPACE::Pow(df, v, pwrValue), scalePower, subValue);
216198
auto result = IfThenElse(And(v <= minCutOff, v >= zeros), lowValue, v);
217199
result = IfThenElse(And(v > minCutOff, v <= highCutOff), highValue, result);
218200
result = IfThenElse(v > highCutOff, highCutOff, result);
219-
result = IfThenElse(v < zeros, zeros, result);
201+
result = IfThenZeroElse(v < zeros, result);
220202
return result;
221203
}
222204

223-
HWY_FAST_MATH_INLINE float LinearITUR709ToITUR709(const float linear) {
224-
if (linear <= 0.018053968510807f) {
225-
return 4.5f * linear;
226-
} else {
227-
return 1.09929682680944f * std::powf(linear, 0.45f) - 0.09929682680944f;
228-
}
229-
}
230-
231205
template<class D, typename V = Vec<D>, HWY_IF_FLOAT(TFromD<D>)>
232206
HWY_FAST_MATH_INLINE V SMPTE428Eotf(const D df, V value) {
233207
const auto scale = Set(df, static_cast<const TFromD<D>>(1.f / 0.91655527974030934f));
@@ -282,17 +256,24 @@ HWY_FAST_MATH_INLINE float Rec601Oetf(float intensity) {
282256

283257
template<class D, typename T = Vec<D>, HWY_IF_FLOAT(TFromD<D>)>
284258
HWY_FAST_MATH_INLINE T Rec601Eotf(const D d, T intensity) {
285-
const auto topValue = Set(d, 4.5f * 0.018053968510807f);
286-
const auto fourAnd5 = Set(d, 4.5f);
287-
const auto lowMask = intensity < topValue;
288-
const auto lowValues = Div(intensity, fourAnd5);
259+
const auto lowCutOff = Set(d, 4.5f * 0.018053968510807f);
260+
const auto fourAnd5 = Set(d, 1.f / 4.5f);
261+
const auto lowCutOffMask = intensity < lowCutOff;
262+
const auto tressPassCutOffMask = intensity >= lowCutOff;
263+
const auto zeros = Zero(d);
264+
const auto ones = Set(d, 1.f);
265+
const auto lowValues = Mul(intensity, fourAnd5);
289266

290267
const auto addComp = Set(d, 0.09929682680944f);
291268
const auto div1099 = Set(d, 1.f / 1.09929682680944f);
292269
const auto pwScale = Set(d, 1.0f / 0.45f);
293270

294271
const auto high = coder::HWY_NAMESPACE::Pow(d, Mul(Add(intensity, addComp), div1099), pwScale);
295-
return IfThenElse(lowMask, lowValues, high);
272+
auto Lc = IfThenElseZero(And(lowCutOffMask, intensity >= zeros), lowValues);
273+
Lc = IfThenZeroElse(intensity < zeros, Lc);
274+
Lc = IfThenElse(And(tressPassCutOffMask, intensity <= ones), high, Lc);
275+
Lc = IfThenElse(intensity > ones, ones, Lc);
276+
return Lc;
296277
}
297278

298279
HWY_FAST_MATH_INLINE float Rec601Eotf(float intensity) {

0 commit comments

Comments
 (0)