Skip to content

Commit a14e57f

Browse files
authored
Codec-Compare version 0.2.4 (#14)
1 parent 3437550 commit a14e57f

17 files changed

Lines changed: 200 additions & 45 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## v0.2.4
4+
5+
- Add the megapixels field.
6+
- Fix Help text.
7+
- Add axis scale mode in Settings.
8+
39
## v0.2.3
410

511
- No longer limit JPEG XL input quality range to [75:99] by default (introduced

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codec_compare",
3-
"version": "0.2.3",
3+
"version": "0.2.4",
44
"description": "Codec performance comparison tool",
55
"publisher": "Google LLC",
66
"author": "Yannis Guyon",

readme_preview.png

8 Bytes
Loading

src/batch_selection.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import {Batch} from './entry';
1616
import {dispatch, EventType, listen} from './events';
17-
import {enableDefaultFilters, FieldFilter, getFilteredRowIndices} from './filter';
17+
import {FieldFilter, getFilteredRowIndices} from './filter';
1818
import {MatchedDataPoints} from './matcher';
1919
import {FieldMetricStats, SourceCount} from './metric';
2020

@@ -55,8 +55,6 @@ export class BatchSelection {
5555
this.fieldFilters.push(fieldFilter);
5656
}
5757

58-
enableDefaultFilters(this.batch, this.fieldFilters);
59-
6058
listen(EventType.FILTER_CHANGED, (event) => {
6159
if (event.detail.batchIndex !== this.batch.index) return;
6260
this.updateFilteredRows();

src/codec_compare.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,9 @@ import {LoadingUi} from './loading_ui';
4242
import {PlotUi} from './plot_ui';
4343
import {SettingsUi} from './settings_ui';
4444
import {State} from './state';
45+
import {Tab} from './tab';
4546
import {UrlState} from './url_state';
4647

47-
enum Tab {
48-
SUMMARY = 0, // A simple sentence to describe the plot.
49-
STATS = 1, // Advanced interface with tunable comparison parameters.
50-
GALLERY = 2, // Source data set grid.
51-
}
52-
5348
/** Main component of the codec comparison static viewer. */
5449
@customElement('codec-compare')
5550
export class CodecCompare extends LitElement {
@@ -179,8 +174,7 @@ export class CodecCompare extends LitElement {
179174
180175
<settings-ui .state=${this.state}></settings-ui>
181176
182-
<mwc-button-fit id="helpButton"
183-
?disabled=${this.currentTab === Tab.GALLERY} @click=${() => {
177+
<mwc-button-fit id="helpButton" @click=${() => {
184178
this.helpUi.onOpen();
185179
}}>
186180
<mwc-icon>help</mwc-icon> Help
@@ -207,7 +201,7 @@ export class CodecCompare extends LitElement {
207201
</p>
208202
209203
<p id="credits">
210-
Codec Compare beta version 0.2.3<br>
204+
Codec Compare beta version 0.2.4<br>
211205
<a href="https://github.com/webmproject/codec-compare">
212206
Sources on GitHub
213207
</a>
@@ -219,7 +213,7 @@ export class CodecCompare extends LitElement {
219213
<batch-selection-ui .state=${this.state}></batch-selection-ui>
220214
<matches-ui .state=${this.state}></matches-ui>
221215
<match-ui .state=${this.state}></match-ui>
222-
<help-ui .displaySentence=${this.currentTab === Tab.SUMMARY}></help-ui>
216+
<help-ui .displayedTab=${this.currentTab}></help-ui>
223217
${this.isLoaded ? html`` : html`<loading-ui></loading-ui>`}
224218
`;
225219
}

src/entry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export enum FieldId {
5252
P3NORM, // Difference between original and decoded images.
5353
ENCODED_SIZE, // In bytes.
5454
ENCODED_BITS_PER_PIXEL, // Should be ENCODED_SIZE / (WIDTH * HEIGHT).
55+
MEGAPIXELS, // Should be (WIDTH * HEIGHT) / 1,000,000.
5556
ENCODING_DURATION, // In seconds.
5657
DECODING_DURATION, // In seconds.
5758
RAW_DECODING_DURATION, // Should be DECODING_DURATION exclusive of the color
@@ -110,6 +111,7 @@ const NAME_TO_FIELD_ID = new Map<string, FieldId>([
110111
['p3-norm', FieldId.P3NORM],
111112
['encoded size', FieldId.ENCODED_SIZE],
112113
['bpp', FieldId.ENCODED_BITS_PER_PIXEL],
114+
['megapixels', FieldId.MEGAPIXELS],
113115
['encoding time', FieldId.ENCODING_DURATION],
114116
['decoding time', FieldId.DECODING_DURATION],
115117
['raw decoding time', FieldId.RAW_DECODING_DURATION],

src/entry_loader.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,31 @@ function jsonToBatch(
237237
processField(field, fieldIndex);
238238
}
239239
}
240+
241+
// Compute megapixels if possible.
242+
const megapixelsField =
243+
batch.fields.find(field => field.id === FieldId.MEGAPIXELS);
244+
if (megapixelsField === undefined) {
245+
const widthFieldIndex =
246+
batch.fields.findIndex(field => field.id === FieldId.WIDTH);
247+
const heightFieldIndex =
248+
batch.fields.findIndex(field => field.id === FieldId.HEIGHT);
249+
if (widthFieldIndex !== -1 && heightFieldIndex !== -1 &&
250+
batch.fields[widthFieldIndex].isInteger &&
251+
batch.fields[heightFieldIndex].isInteger) {
252+
const fieldIndex = batch.fields.length;
253+
const field = new Field('megapixels', 'millions of pixels');
254+
batch.fields.push(field);
255+
uniqueValuesSets.push(new Set<string>());
256+
for (const row of batch.rows) {
257+
const megapixels = (row[widthFieldIndex] as number) *
258+
(row[heightFieldIndex] as number) / 1000000;
259+
row.push(megapixels);
260+
field.addValue(String(megapixels), uniqueValuesSets[fieldIndex]);
261+
}
262+
processField(field, fieldIndex);
263+
}
264+
}
240265
return batch;
241266
}
242267

src/entry_loader_test.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,19 @@ describe('loadBatchJson', () => {
6868
expect(response.ok).toBeTrue();
6969
if (!response.ok) return;
7070

71+
const batch = await loadBatchJson(response.url);
72+
const widthFieldIndex =
73+
batch.fields.findIndex((field) => field.id === FieldId.WIDTH);
74+
const heightFieldIndex =
75+
batch.fields.findIndex((field) => field.id === FieldId.HEIGHT);
76+
expect(widthFieldIndex).not.toBe(-1);
77+
expect(heightFieldIndex).not.toBe(-1);
78+
7179
// No bits-per-pixel data in the input file.
7280
const text = await response.text();
7381
expect(text).not.toContain('bpp');
7482

75-
// The bits-per-pixel field still exists because it was computed.
76-
const batch = await loadBatchJson(response.url);
83+
// The bits-per-pixel field exists anyway because it was computed.
7784
const bppFieldIndex = batch.fields.findIndex(
7885
(field) => field.id === FieldId.ENCODED_BITS_PER_PIXEL);
7986
expect(bppFieldIndex).not.toBe(-1);
@@ -90,13 +97,7 @@ describe('loadBatchJson', () => {
9097
// Make sure the computation is correct.
9198
const encodedSizeFieldIndex =
9299
batch.fields.findIndex((field) => field.id === FieldId.ENCODED_SIZE);
93-
const widthFieldIndex =
94-
batch.fields.findIndex((field) => field.id === FieldId.WIDTH);
95-
const heightFieldIndex =
96-
batch.fields.findIndex((field) => field.id === FieldId.HEIGHT);
97100
expect(encodedSizeFieldIndex).not.toBe(-1);
98-
expect(widthFieldIndex).not.toBe(-1);
99-
expect(heightFieldIndex).not.toBe(-1);
100101
if (encodedSizeFieldIndex !== -1 && widthFieldIndex !== -1 &&
101102
heightFieldIndex !== -1) {
102103
for (const row of batch.rows) {
@@ -109,6 +110,21 @@ describe('loadBatchJson', () => {
109110
}
110111
}
111112
}
113+
114+
// Same for megapixels.
115+
expect(text).not.toContain('megapixels');
116+
const megapixelsFieldIndex =
117+
batch.fields.findIndex((field) => field.id === FieldId.MEGAPIXELS);
118+
expect(megapixelsFieldIndex).not.toBe(-1);
119+
expect(megapixelsFieldIndex).toBeLessThan(batch.rows[0].length);
120+
if (megapixelsFieldIndex !== -1 &&
121+
megapixelsFieldIndex < batch.rows[0].length) {
122+
// Make sure the computation is correct.
123+
expect(batch.rows[0][megapixelsFieldIndex] as number)
124+
.toBe(
125+
(batch.rows[0][widthFieldIndex] as number) *
126+
(batch.rows[0][heightFieldIndex] as number) / 1000000);
127+
}
112128
});
113129

114130
it('loads a JSON file where bpp cannot be computed', async () => {

src/help_ui.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import '@material/mwc-icon';
1818
import {css, html, LitElement} from 'lit';
1919
import {customElement, property, query} from 'lit/decorators.js';
2020

21+
import {Tab} from './tab';
22+
2123
/** Returns the element at domPath or null. */
2224
function getShadowElement(domPath: string[]): Element|null {
2325
let element: Element|null|undefined = null;
@@ -32,13 +34,12 @@ function getShadowElement(domPath: string[]): Element|null {
3234
/** Overlay element describing the other elements behind it. */
3335
@customElement('help-ui')
3436
export class HelpUi extends LitElement {
35-
@property() displaySentence!: boolean;
37+
@property() displayedTab!: Tab;
3638

3739
// Always returned by render() so cannot be null.
3840
@query('#closeButton') private readonly closeButton!: HTMLElement;
3941

4042
// Containers of descriptive text blocks.
41-
// Always returned by render() so cannot be null.
4243
@query('#numComparisonsDescription')
4344
private readonly numComparisonsDescription!: HTMLElement;
4445
@query('#matchersDescription')
@@ -48,6 +49,8 @@ export class HelpUi extends LitElement {
4849
@query('#batchSelectionsDescription')
4950
private readonly batchSelectionsDescription!: HTMLElement;
5051
@query('#graphDescription') private readonly graphDescription!: HTMLElement;
52+
@query('#galleryDescription')
53+
private readonly galleryDescription!: HTMLElement;
5154

5255
onOpen() {
5356
// Position the closing button on top of the home page's help button
@@ -74,14 +77,14 @@ export class HelpUi extends LitElement {
7477
// The main interactive user interface elements are on the fixed left menu.
7578
// Position the "tooltips" on the right of them to keep them visible.
7679
// The "tooltips" cover parts of the graph but this works visually.
77-
if (this.displaySentence) {
80+
if (this.displayedTab === Tab.SUMMARY) {
7881
positionElementAtTheRightOf(
7982
this.matchersDescription,
8083
['codec-compare', 'sentence-ui', '#matchers']);
8184
positionElementAtTheRightOf(
8285
this.batchSelectionsDescription,
8386
['codec-compare', 'sentence-ui', '#batches']);
84-
} else {
87+
} else if (this.displayedTab === Tab.STATS) {
8588
positionElementAtTheRightOf(
8689
this.numComparisonsDescription, ['codec-compare', '#numComparisons']);
8790
positionElementAtTheRightOf(
@@ -91,6 +94,10 @@ export class HelpUi extends LitElement {
9194
positionElementAtTheRightOf(
9295
this.batchSelectionsDescription,
9396
['codec-compare', 'batch-selections-ui']);
97+
} else if (this.displayedTab === Tab.GALLERY) {
98+
positionElementAtTheRightOf(
99+
this.galleryDescription,
100+
['codec-compare', 'gallery-ui', '#sourceDataSet']);
94101
}
95102

96103
// This is not the description of the #referenceBatch <p> but it is used as
@@ -109,7 +116,7 @@ export class HelpUi extends LitElement {
109116
this.requestUpdate();
110117
}
111118

112-
private renderSentenceHelp() {
119+
private renderSummaryHelp() {
113120
return html`
114121
<div class="descriptionHolder" id="numComparisonsDescription">
115122
</div>
@@ -130,12 +137,13 @@ export class HelpUi extends LitElement {
130137
<div class="bracket"></div>
131138
<p>
132139
Batches are aggregated by codec.<br>
133-
The advanced interface can be enabled in the settings (left bar).
140+
See the ADVANCED tab for more information and to change the comparison
141+
reference, criteria and shown metrics.
134142
</p>
135143
</div>`;
136144
}
137145

138-
private renderTuneableComparisonHelp() {
146+
private renderAdvancedHelp() {
139147
return html`
140148
<div class="descriptionHolder" id="numComparisonsDescription">
141149
<div class="bracket"></div>
@@ -152,10 +160,11 @@ export class HelpUi extends LitElement {
152160
<div class="descriptionHolder" id="matchersDescription">
153161
<div class="bracket"></div>
154162
<p>
155-
Pairs are selected so that these constraints are respected. Objective
156-
visual distortion metrics such as PSNR and SSIM can be used as matchers
157-
to compare formats and codecs on other metrics such as compression rate
158-
and encoding duration.<br>
163+
Pairs are selected so that these constraints are respected. When
164+
comparing lossy compression methods, objective visual distortion metrics
165+
such as PSNR and SSIM can be used as matchers to compare formats and
166+
codecs on other metrics such as compression rate and encoding duration.
167+
<br>
159168
Numerical fields can be matched with a relative tolerance. If so, pairs
160169
are selected to minimize the difference of the values of these fields.
161170
</p>
@@ -175,7 +184,12 @@ export class HelpUi extends LitElement {
175184
different codecs, or the same codec with different settings. Each batch
176185
has an associated color.<br>
177186
Click the info button to see batch metadata and data points. Some data
178-
points may be filtered out.<br>
187+
points may be filtered out. When comparing lossy compression methods, it
188+
is recommended to filter based on
189+
<a href="https://github.com/webmproject/codec-compare/wiki/Bits-per-pixel-of-Internet-images"
190+
target="_blank">
191+
bits-per-pixel usually seen on the web
192+
<mwc-icon>open_in_new</mwc-icon></a>.<br>
179193
Click the focus button to set a batch as the reference to compare the
180194
others against.<br>
181195
The statistics relative to the reference batch for the fields selected
@@ -185,6 +199,20 @@ export class HelpUi extends LitElement {
185199
</div>`;
186200
}
187201

202+
private renderDatasetHelp() {
203+
return html`
204+
<div class="descriptionHolder" id="galleryDescription">
205+
<div class="bracket"></div>
206+
<p>
207+
These media assets were compressed and decompressed with the codecs
208+
presented here to compare their relative performance.<br>
209+
<br>
210+
The count associated with each asset corresponds to the number of
211+
matched pairs based on that asset.
212+
</p>
213+
</div>`;
214+
}
215+
188216
override render() {
189217
const onClose = () => {
190218
this.style.display = 'none';
@@ -196,17 +224,18 @@ export class HelpUi extends LitElement {
196224
</div>
197225
198226
${
199-
this.displaySentence ? this.renderSentenceHelp() :
200-
this.renderTuneableComparisonHelp()}
227+
this.displayedTab === Tab.SUMMARY ? this.renderSummaryHelp() :
228+
this.displayedTab === Tab.STATS ? this.renderAdvancedHelp() :
229+
this.renderDatasetHelp()}
201230
202231
<div class="descriptionHolder" id="graphDescription">
203232
<p>
204233
The codecs are plotted on this graph as large disks, with the metric
205234
fields as axes. If any, batches sharing the same codec are linked with
206235
straight lines, usually to represent multiple encoding efforts.<br>
207-
If enabled in the Settings page, each matched pair is displayed as a
208-
tiny dot. Click on any to display the details of the reference batch and
209-
of the compared batch.<br>
236+
If enabled in the Settings, each matched pair is displayed as a tiny
237+
dot. Click on any to display the details of the reference batch and of
238+
the compared batch.<br>
210239
<br>
211240
For an introduction to image file formats, please see this
212241
<a href="https://en.wikipedia.org/wiki/Image_file_format"

src/matcher.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export function createMatchers(batches: Batch[]): FieldMatcher[] {
101101
// Same source image, so these will always match. Remove them from the UI.
102102
if (field.id === FieldId.WIDTH || field.id === FieldId.HEIGHT) continue;
103103
if (field.id === FieldId.FRAME_COUNT) continue;
104+
if (field.id === FieldId.MEGAPIXELS) continue;
104105
// If bpp values are available, encoded sizes probably are too.
105106
// Skip the former which brings nothing as a matcher over the latter.
106107
if (field.id === FieldId.ENCODED_BITS_PER_PIXEL) continue;
@@ -241,6 +242,7 @@ export function isLossless(firstBatch: Batch, matchers: FieldMatcher[]) {
241242
return false;
242243
}
243244
}
245+
// Assume other batches to be lossless too.
244246
return true;
245247
}
246248

0 commit comments

Comments
 (0)