blob: e11bbddcc428ae70a75a32d4c7883922ec5dd115 [file]
/**
* @license
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {html, css, LitElement, PropertyValues} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {ImageInfo} from '../gr-opacity-diff-mode/gr-opacity-diff-mode';
import '../gr-opacity-diff-mode/gr-opacity-diff-mode';
import '../gr-resemble-diff-mode/gr-resemble-diff-mode';
const DiffModes = {
OPACITY: 'opacity',
RESEMBLE: 'resemble',
};
@customElement('gr-image-diff-tool')
export class ImageDiffTool extends LitElement {
static override get styles() {
return [
css`
:host {
background-color: var(--table-header-background-color, #fafafa);
display: block;
font-family: var(--font-family);
}
#header {
align-items: center;
border-bottom: 1px solid var(--border-color, #ddd);
border-top: 1px solid var(--border-color, #ddd);
display: inline-flex;
padding: 0.5em;
width: 100%;
}
h3 {
padding: 0 0.5em;
}
#dropdown {
background-color: var(--view-background-color);
border: 1px solid var(--border-color);
border-radius: 2px;
color: var(--primary-text-color);
font-size: var(--font-size-normal);
height: 2em;
margin-left: 1em;
padding: 0 0.15em;
}
.diffmode {
align-items: center;
display: flex;
justify-content: center;
}
`
];
}
@property({type: Object})
baseImage?: ImageInfo;
@property({type: Object})
revisionImage?: ImageInfo;
@property({type: Boolean, reflect: true})
override hidden = false;
@state()
protected showResembleMode = false;
@state()
protected showOpacityMode = false;
@state()
protected observeMode = '';
override render() {
return html`
<div id="header">
<h3>Image diff</h3>
<select
.value=${this.observeMode}
@change=${this.handleSelectChange}
id="dropdown"
>
<option
value="resemble"
title="Scale the images to the same size and compute a diff with highlights"
>Highlight differences</option
>
<option
value="opacity"
title="Overlay the new image over the old and use an opacity control to view the differences"
>Onion skin</option
>
</select>
</div>
<div class="diffmode">
${this.showResembleMode
? html`
<gr-resemble-diff-mode
.baseImage=${this.baseImage}
.revisionImage=${this.revisionImage}
></gr-resemble-diff-mode>
`
: ''}
</div>
<div class="diffmode">
${this.showOpacityMode
? html`
<gr-opacity-diff-mode
.baseImage=${this.baseImage}
.revisionImage=${this.revisionImage}
></gr-opacity-diff-mode>
`
: ''}
</div>
`;
}
override updated(changedProperties: PropertyValues) {
if (changedProperties.has('observeMode')) {
this.handleSelect(this.observeMode);
}
}
override connectedCallback() {
super.connectedCallback();
if (!this.baseImage || !this.revisionImage) {
// No need to show the diff tool if there are no images.
this.hidden = true;
}
const diff_mode = this.getMode();
diff_mode === DiffModes.OPACITY
? this.displayOpacityMode()
: this.displayResembleMode();
}
protected getMode() {
return window.localStorage.getItem('image-diff-mode');
}
protected setMode(mode: string) {
window.localStorage.setItem('image-diff-mode', mode);
}
protected handleSelectChange(e: Event) {
this.observeMode = (e.target as HTMLSelectElement).value;
}
protected handleSelect(mode: string) {
mode === DiffModes.OPACITY
? this.displayOpacityMode()
: this.displayResembleMode();
}
protected displayResembleMode() {
this.observeMode = DiffModes.RESEMBLE;
this.showResembleMode = true;
this.showOpacityMode = false;
this.setMode(DiffModes.RESEMBLE);
}
protected displayOpacityMode() {
this.observeMode = DiffModes.OPACITY;
this.showResembleMode = false;
this.showOpacityMode = true;
this.setMode(DiffModes.OPACITY);
}
}
declare global {
interface HTMLElementTagNameMap {
'gr-image-diff-tool': ImageDiffTool;
}
}